Skip to content

Instantly share code, notes, and snippets.

@the-nose-knows
Created August 16, 2019 04:09
Show Gist options
  • Save the-nose-knows/bc86f2a4e6baa53f96b716178c1dbc24 to your computer and use it in GitHub Desktop.
Save the-nose-knows/bc86f2a4e6baa53f96b716178c1dbc24 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Windows.Storage;
using System.IO;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
// StackOverflow user Sunius is author of original code this was derived from: https://stackoverflow.com/a/54966331/3543437
namespace SuniusMoveFaster
{
public class Move_Faster
{
public async Task MoveContentFast(string source, IStorageFolder destination)
{
await Task.Run(async () =>
{
await MoveContextImpl(source, destination);
});
}
private async Task MoveContextImpl(string source, IStorageFolder destination)
{
var tasks = new List<Task>();
var destinationAccess = destination as IStorageFolderHandleAccess;
StorageFolder sourceFolder = await StorageFolder.GetFolderFromPathAsync(source);
var sourceFiles = await sourceFolder.GetFilesAsync();
foreach (var src_file in sourceFiles)
{
var item = await src_file.GetBasicPropertiesAsync();
//if ((item.Attributes & System.IO.FileAttributes.Directory) != 0)
//{
// tasks.Add(destination.CreateFolderAsync(file.Name, CreationCollisionOption.ReplaceExisting).AsTask().ContinueWith((destinationSubFolder) =>
// {
// MoveContextImpl((DirectoryInfo)item, destinationSubFolder.Result);
// }));
//}
//else
//{
if (destinationAccess == null)
{
// Slower, pre 14393 OS build path
tasks.Add(WindowsRuntimeStorageExtensions.OpenStreamForWriteAsync(destination, src_file.Name, CreationCollisionOption.ReplaceExisting).ContinueWith((openTask) =>
{
using (var stream = openTask.Result)
{
var sourceBytes = File.ReadAllBytes(src_file.Path);
stream.Write(sourceBytes, 0, sourceBytes.Length);
}
File.Delete(src_file.Path);
}));
}
else
{
int hr = destinationAccess.Create(src_file.Name, HANDLE_CREATION_OPTIONS.CREATE_ALWAYS, HANDLE_ACCESS_OPTIONS.WRITE, HANDLE_SHARING_OPTIONS.SHARE_NONE, HANDLE_OPTIONS.NONE, IntPtr.Zero, out SafeFileHandle file);
if (hr < 0)
Marshal.ThrowExceptionForHR(hr);
using (file)
{
using (var stream = new FileStream(file, FileAccess.Write))
{
// Not sure how to replace this with a UWP byte-reader
var sourceBytes = src_file File.ReadAllBytes(src_file.Path);
stream.Write(sourceBytes, 0, sourceBytes.Length);
}
}
//Needs to be replaced with async delete, but doesn't/shouldn't need to be awaited one-by-one; can probably batch them.
File.Delete(item.FullName);
}
//}
}
Task.WaitAll(tasks.ToArray());
}
[ComImport]
[Guid("DF19938F-5462-48A0-BE65-D2A3271A08D6")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IStorageFolderHandleAccess
{
[PreserveSig]
int Create(
[MarshalAs(UnmanagedType.LPWStr)] string fileName,
HANDLE_CREATION_OPTIONS creationOptions,
HANDLE_ACCESS_OPTIONS accessOptions,
HANDLE_SHARING_OPTIONS sharingOptions,
HANDLE_OPTIONS options,
IntPtr oplockBreakingHandler,
out SafeFileHandle interopHandle); // using Microsoft.Win32.SafeHandles
}
internal enum HANDLE_CREATION_OPTIONS : uint
{
CREATE_NEW = 0x1,
CREATE_ALWAYS = 0x2,
OPEN_EXISTING = 0x3,
OPEN_ALWAYS = 0x4,
TRUNCATE_EXISTING = 0x5,
}
[Flags]
internal enum HANDLE_ACCESS_OPTIONS : uint
{
NONE = 0,
READ_ATTRIBUTES = 0x80,
// 0x120089
READ = SYNCHRONIZE | READ_CONTROL | READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA,
// 0x120116
WRITE = SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA,
DELETE = 0x10000,
READ_CONTROL = 0x00020000,
SYNCHRONIZE = 0x00100000,
FILE_READ_DATA = 0x00000001,
FILE_WRITE_DATA = 0x00000002,
FILE_APPEND_DATA = 0x00000004,
FILE_READ_EA = 0x00000008,
FILE_WRITE_EA = 0x00000010,
FILE_EXECUTE = 0x00000020,
FILE_WRITE_ATTRIBUTES = 0x00000100,
}
[Flags]
internal enum HANDLE_SHARING_OPTIONS : uint
{
SHARE_NONE = 0,
SHARE_READ = 0x1,
SHARE_WRITE = 0x2,
SHARE_DELETE = 0x4
}
[Flags]
internal enum HANDLE_OPTIONS : uint
{
NONE = 0,
OPEN_REQUIRING_OPLOCK = 0x40000,
DELETE_ON_CLOSE = 0x4000000,
SEQUENTIAL_SCAN = 0x8000000,
RANDOM_ACCESS = 0x10000000,
NO_BUFFERING = 0x20000000,
OVERLAPPED = 0x40000000,
WRITE_THROUGH = 0x80000000
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment