This is the beginning of the command line interface for Karen’s Replicator 2. I hard coded it to copy the contents of one directory to another, including sub directories.
Here’s the Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Threading;
namespace Replicator2_CLI
{
internal class Program
{
static void Main(string[] args)
{
CopyAll(
new DirectoryInfo(@"J:\home\Desktop\Folder Test"),
new DirectoryInfo(@"B:\test\Folder Test")
);
}
/**
* https://learn.microsoft.com/en-us/dotnet/api/system.io.directoryinfo?view=net-7.0
*/
public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
if (source.FullName.ToLower() == target.FullName.ToLower())
{
return;
}
// Check if the target directory exists, if not, create it.
if (Directory.Exists(target.FullName) == false)
{
Directory.CreateDirectory(target.FullName);
}
// Copy each file into it's new directory.
foreach (FileInfo fi in source.GetFiles())
{
Console.WriteLine(@"Copying {0}\{1}", target.FullName, fi.Name);
//(jmw) fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true);
FileRoutines.CopyFile(fi, new FileInfo(Path.Combine(target.FullName, fi.Name)) );
}
// Copy each subdirectory using recursion.
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir =
target.CreateSubdirectory(diSourceSubDir.Name);
CopyAll(diSourceSubDir, nextTargetSubDir);
}
}
static void CopyFile( string source, string destination )
{
Console.WriteLine( source + " --> " + destination );
FileRoutines.CopyFile(new FileInfo(source), new FileInfo(destination));
}
}
/**
* https://learn.microsoft.com/en-us/archive/msdn-magazine/2005/february/net-matters-file-copy-progress-custom-thread-pools
*/
public sealed class FileRoutines
{
public static void CopyFile(FileInfo source, FileInfo destination)
{
CopyFile(source, destination, CopyFileOptions.None);
}
public static void CopyFile(FileInfo source, FileInfo destination, CopyFileOptions options)
{
CopyFile(source, destination, options, null);
}
public static void CopyFile(FileInfo source, FileInfo destination, CopyFileOptions options, CopyFileCallback callback)
{
CopyFile(source, destination, options, callback, null);
}
public static void CopyFile(FileInfo source, FileInfo destination, CopyFileOptions options, CopyFileCallback callback, object state)
{
if (source == null)
throw new ArgumentNullException("source");
if (destination == null)
throw new ArgumentNullException("destination");
if ((options & ~CopyFileOptions.All) != 0)
throw new ArgumentOutOfRangeException("options");
new FileIOPermission(FileIOPermissionAccess.Read, source.FullName).Demand();
new FileIOPermission(FileIOPermissionAccess.Write, destination.FullName).Demand();
CopyProgressRoutine cpr = callback == null ? null : new CopyProgressRoutine(new CopyProgressData(source, destination, callback, state).CallbackHandler);
bool cancel = false;
if (!CopyFileEx(source.FullName, destination.FullName, cpr, IntPtr.Zero, ref cancel, (int)options))
{
throw new IOException(new Win32Exception().Message);
}
}
private class CopyProgressData
{
private FileInfo _source = null; private FileInfo _destination = null; private CopyFileCallback _callback = null; private object _state = null; public CopyProgressData(FileInfo source, FileInfo destination, CopyFileCallback callback, object state)
{
_source = source;
_destination = destination;
_callback = callback;
_state = state;
}
public int CallbackHandler(long totalFileSize, long totalBytesTransferred, long streamSize, long streamBytesTransferred, int streamNumber, int callbackReason, IntPtr sourceFile, IntPtr destinationFile, IntPtr data)
{
return (int)_callback(_source, _destination, _state, totalFileSize, totalBytesTransferred);
}
}
private delegate int CopyProgressRoutine(long totalFileSize, long TotalBytesTransferred, long streamSize, long streamBytesTransferred, int streamNumber, int callbackReason, IntPtr sourceFile, IntPtr destinationFile, IntPtr data); [SuppressUnmanagedCodeSecurity][DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool CopyFileEx(string lpExistingFileName, string lpNewFileName, CopyProgressRoutine lpProgressRoutine, IntPtr lpData, ref bool pbCancel, int dwCopyFlags);
}
public delegate CopyFileCallbackAction CopyFileCallback(FileInfo source, FileInfo destination, object state, long totalFileSize, long totalBytesTransferred); public enum CopyFileCallbackAction
{
Continue = 0, Cancel = 1, Stop = 2, Quiet = 3
}
[Flags]
public enum CopyFileOptions
{
None = 0x0, FailIfDestinationExists = 0x1, Restartable = 0x2, AllowDecryptedDestination = 0x8, All = FailIfDestinationExists | Restartable | AllowDecryptedDestination
}
public sealed class CustomThreadPool : IDisposable
{
private Semaphore _workWaiting;
private Queue<WaitQueueItem> _queue;
private List<Thread> _threads;
public CustomThreadPool(int numThreads)
{
if (numThreads <= 0)
throw new ArgumentOutOfRangeException("numThreads");
_threads = new List<Thread>(numThreads);
_queue = new Queue<WaitQueueItem>();
_workWaiting = new Semaphore(0, int.MaxValue);
for (int i = 0; i < numThreads; i++)
{
Thread t = new Thread(Run);
t.IsBackground = true;
_threads.Add(t);
t.Start();
}
}
public void Dispose()
{
if (_threads != null)
{
_threads.ForEach(delegate (Thread t)
{
t.Interrupt();
});
_threads = null;
}
}
public void QueueUserWorkItem(WaitCallback callback, object state)
{
if (_threads == null)
throw new ObjectDisposedException(GetType().Name);
if (callback == null)
throw new ArgumentNullException("callback");
WaitQueueItem item = new WaitQueueItem();
item.Callback = callback;
item.State = state;
item.Context = ExecutionContext.Capture();
lock (_queue)
_queue.Enqueue(item);
_workWaiting.Release();
}
private void Run()
{
try
{
while (true)
{
_workWaiting.WaitOne();
WaitQueueItem item;
lock (_queue)
item = _queue.Dequeue();
ExecutionContext.Run(item.Context, new ContextCallback(item.Callback), item.State);
}
}
catch (ThreadInterruptedException) { }
}
private class WaitQueueItem
{
public WaitCallback Callback; public object State; public ExecutionContext Context;
}
}
}