Fastest way to move folder to another place in UWP

c move folder to another folder
uwp broadfilesystemaccess
uwp open file from path
c# move all files from one directory to another
c move folder and subfolders
uwp file access denied
uwp save file to local folder
uwp filestream

I have SSD storage and this code takes 32 seconds to move ~200 files and ~40 folders to the same storage in either debug or release mode. total size of folder is ~30 MB.

How can i make this faster?

// moves content from local folder to target folder.
async Task MoveContent(IStorageFolder source, IStorageFolder destination)
{
    foreach(var item in await source.GetItemsAsync())
    {
        switch (item)
        {
            case IStorageFile sourceFile:
                await sourceFile.MoveAsync(destination, sourceFile.Name, NameCollisionOption.ReplaceExisting);
                break;
            case IStorageFolder sourceSubFolder:
                var destinationSubFolder = await destination.CreateFolderAsync(sourceSubFolder.Name, CreationCollisionOption.ReplaceExisting);
                await MoveContent(sourceSubFolder, destinationSubFolder);
                break;
        }
    }
}

And I call it like this

await MoveContent(extractionFolder, targetFolder);

Note that extractionFolder is in ApplicationData.Current.LocalCacheFolder and targetFolder is any folder chosen by user via FolderPicker

To improve the performance of your code, you could try enumerating all files in the folder and subfolders at once instead of throughout the folder structure (folder by folder):

var results = storageFolder.CreateFileQueryWithOptions(
                  new QueryOptions() { FolderDepth = FolderDepth.Deep } );
var files = (await results.GetFilesAsync()).ToArray();

Where storageFolder is the folder you want to move. The custom file query has FolderDepth setting set to Deep so that it returns all files from the whole folder structure. After running this, files array will contain all the files and you can then move them. This will be at least a tad faster than enumerating all folders one by one. You just have to make sure to always check the appropriate subfolders are created in the target location.

Finally you could try to parallelize the move Tasks - for example moving three files at once. You can create multiple Task instances and await them all using Task.WhenAll.

Copy-paste solution

Another quick and dirty solution would be to use StorageFolder.CopyAsync() method to copy the folder to the new location and delete the original (this is even suggested in Docs):

There is not currently a "MoveAsync" or similar method. One simple implementation of moving a folder might be to get the desired folder, copy it to the desired location, and then delete the original folder.

However, the cost of additional storage space is not very appealing and may not even improve the performance, because copying is more costly than moving.

Directory.Move(String, String) Method (System.IO), Moves a file or a directory and its contents to a new location. You can use a script that uses Robocopy, a command line utility that is included in Windows 10. For the script shared below, you just need to add the frequency in days, path to the folder from

There are several issues with the code you posted:

  1. You fire off File I/O operations one by one, and wait for their completion. Since File I/O in UWP is brokered, that involves calling into another process. Since most of the time is spent communicating between processes, you get bottlenecked by your own waits. Your disk isn't active at all during that time.

  2. WinRT file I/O API is utter garbage performance wise. You want to avoid it as much as you can. Since you have proper access to the source path, you should use C# DirectoryInfo class to enumerate files. Then, instead of using MoveAsync (since you no longer have source as IStorageItem), use C# File I/O.

With these changes, it manages to complete my synthetic test case (40 folders, with 5 files in them each) takes 300 ms, compared to 12 seconds using your code. That is 30 times faster. This could get much faster if we were allowed to use Win32 APIs like MoveFile, but unfortunately there is no way to currently do it for folders and files picked by file/folder pickers.

Here's the code.

        async Task MoveContentFast(IStorageFolder source, IStorageFolder destination)
        {
            await Task.Run(() =>
            {
                MoveContextImpl(new DirectoryInfo(source.Path), destination);
            });
        }

        private void MoveContextImpl(DirectoryInfo sourceFolderInfo, IStorageFolder destination)
        {
            var tasks = new List<Task>();

            var destinationAccess = destination as IStorageFolderHandleAccess;

            foreach (var item in sourceFolderInfo.EnumerateFileSystemInfos())
            {
                if ((item.Attributes & System.IO.FileAttributes.Directory) != 0)
                {
                    tasks.Add(destination.CreateFolderAsync(item.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, item.Name, CreationCollisionOption.ReplaceExisting).ContinueWith((openTask) =>
                        {
                            using (var stream = openTask.Result)
                            {
                                var sourceBytes = File.ReadAllBytes(item.FullName);
                                stream.Write(sourceBytes, 0, sourceBytes.Length);
                            }

                            File.Delete(item.FullName);
                        }));
                    }
                    else
                    {
                        int hr = destinationAccess.Create(item.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))
                            {
                                var sourceBytes = File.ReadAllBytes(item.FullName);
                                stream.Write(sourceBytes, 0, sourceBytes.Length);
                            }
                        }

                        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
        }

Work with files, Learn how to work with files in the Universal Windows Platform. a file because some files you work with in UWP may not have a path, or may have an unwieldy path. We'll use the same location as in the example above. Here is a quick summary of APIs, and other useful documentation, to help get you� Files picked from other apps are like files from the file system: they are returned as StorageFile objects. In general, your app can operate on them in the same ways as other objects. Other apps make files available by participating in file picker contracts.

UWP currently doesn't have anything like MoveAsync as of Aug. 2019. This answer achieves similar behavior to a MoveAsync function, and assumes you're working outside of your UWP App sandbox/Local State, because within the sandbox you can use classic much faster System.IO methods from .NET. Just use the latter inside your sandbox, otherwise you can use this ad-hoc:

public static async Task Move_Directory_Async(
    StorageFolder           sourceDir,
    StorageFolder           destParentDir,
    CreationCollisionOption repDirOpt,
    NameCollisionOption     repFilesOpt)
{
    try
    {
        if (sourceDir == null)
            return;

        List<Task> copies = new List<Task>();
        var files = await sourceDir.GetFilesAsync();
        if (files == null || files.Count == 0)
            await destParentDir.CreateFolderAsync(sourceDir.Name);
        else
        {
            await destParentDir.CreateFolderAsync(sourceDir.Name, repDirOpt);
            foreach (var file in files)
                copies.Add(file.CopyAsync(destParentDir, file.Name, repFilesOpt).AsTask());
        }

        await sourceDir.DeleteAsync(StorageDeleteOption.PermanentDelete);
        await Task.WhenAll(copies);
    }
    catch(Exception ex)
    {
        //Handle any needed cleanup tasks here
        throw new Exception(
          $"A fatal exception triggered within Move_Directory_Async:\r\n{ex.Message}", ex);
    }
}

[Two Methods] Move Microsoft Store Apps and Games to Another , Here are two ways to transfer them to another drive. You cannot access this folder directly, you cannot change the apps' location by copy and paste. data, applications, and account settings from one PC to another quickly. Open File Explorer. Click on This PC from the left pane. Under the "Devices and drivers" section, open the new drive location. Navigate to the location you want to move the folders.

Console UWP Applications and File-system Access, Console apps, on the other hand, use the standard console window for You can press F5 at this point, just to get the app built and deployed, A fully- qualified folder path, in which to search. If the file isn't a text file, this will throw an exception – for simplicity, I'm just reporting the error and moving on. Create the folder where you want the solution to be moved to. Check-in all your project files (if you want to keep you changes), or rollback any checked out files. Close the solution. Open the Source Control Explorer. Right-click the solution, and select "Advanced -> Remove Mapping" Change the "Local Folder" value to the one you created in step #1.

Admissions, UWP's available methods of is a bit different from many of the other .Net/C# environment in how files are accessed. Someone that has been� Where storageFolder is the folder you want to move. The custom file query has FolderDepth setting set to Deep so that it returns all files from the whole folder structure. After running this, files array will contain all the files and you can then move them. This will be at least a tad faster than enumerating all folders one by one.

Data Storage with UWP, Dropbox files & folders Unable to move files in Dropbox UWP app for Mobile for Windows 10 mobile which is named as Dropbox for S mode, I can't move any file a file and click move the app will crash, all other functions are working correctly and Thanks for the additional information and quick follow up @ Lasitha - I� One of the fastest way to copy files is use robocopy as pointed by Pyrolistical in above post. its very flexible and powerful. If command doesn't work from your dos prompt directly then try with powershell option like below example. Must Check the documentation for this command before using it "robocopy /?".

Comments
  • You can't really improve the plain copying process itself but you could copy the directories parallel.
  • In windows I can simply cut/paste folder and that takes 0 time, what a shame, UWP doesn't have facility to move folders? @Shawn
  • AFAIK, File reading writing from UWP is supposed to be slow because of a lot of security check etc, what you ca do is, Using a Full Trust Process to launch a normal win32 exe and use that to handle file reading writing to avoid these security checks.
  • when you run the code, is any of your devices running on 100%?
  • hint hint @Peter Torr - MSFT :)
  • Unfortunately this doesn't play well with broadFileSystemAccess. I'll see if it can be re-worked to use the UWP FileIO APIs in some places you're using the .NET FileIO APIs. I hope so. The performance of the UWP copy/move APIs per-file is terrible....
  • It doesn't look like it. I made a lot of changes but as soon as I hit var sourceBytes = File.ReadAllBytes(item.FullName); I got stuck. I commented out the recursion because I was just trying to see if I could get the happy path working first. Here's my gist if you want to take it and cover that final-ish gap. I don't know much about interfacing with byte streams and I'm getting sleepy x_x lol. Cool stuff either way! :) I'm not even sure this can take advantage of your performance boosts due to all the extra async options, but I was willing to test it out =/
  • It might help if I actually left the url.. LOL gist.github.com/the-nose-knows/bc86f2a4e6baa53f96b716178c1dbc24
  • My code will only work if the destination is in brokered path, while the source isn't. If your source is in a path an app can't usually access, you'll need to use IStorageFolderHandleAccess interface to read it.