Reputation: 1233
I have a method to copy all files and folders in one directory to another, and it works recursively. My problem is that it blocks the main thread and I would like to make the actual copying of files and folders asynchronous. I currently am using a function to copy files over asynchronously, but it does not seem to work. Here is the code:
private async void copyEverything(string source, string target)
{
// Variable to hold the attributes of a file
FileAttributes attributes;
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(source);
DirectoryInfo[] dirs = dir.GetDirectories();
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: " + source);
}
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(target))
{
Directory.CreateDirectory(target);
}
// Loop through for all files in a directory
foreach (string filename in Directory.EnumerateFiles(source))
{
if (!File.Exists(targetFolder + filename.Substring(filename.LastIndexOf('\\'))))
{
attributes = File.GetAttributes(filename);
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
{
//System.Windows.MessageBox.Show("File {" + filename + "} is READ ONLY");
}
else
{
try
{
using (FileStream SourceStream = File.Open(filename, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(target + filename.Substring(filename.LastIndexOf('\\'))))
{
await SourceStream.CopyToAsync(DestinationStream);
filesRemaining--;
}
}
}
catch (UnauthorizedAccessException)
{
}
}
}
}
// Loop through each subdirectory in the current directory and recursively call the
// copyEverything() method using the subdirectory's full name and the name of the
// target folder plus the subdirectory folder name
foreach (DirectoryInfo subdir in dirs)
{
foldersRemaining--;
string temppath = System.IO.Path.Combine(target, subdir.Name);
copyEverything(subdir.FullName, temppath);
}
}
Is there anything I can do to make it work without blocking the main thread?
Upvotes: 2
Views: 8536
Reputation: 67065
Simply marking a method async
does not make it async
, you need to await
the non-UI/blocking code. The await
is where your asynchronous code should go, often in a Task
.
All code that is not in an await
will run in the context of the calling thread (the main in your case). So, even though you are await
ing the copy, you should probably just await
the entire block, using a Task
as already specified
Upvotes: 0
Reputation: 10507
You're still doing a bunch of IO
on the main thread: Directory.Exist
, File.Exist
, etc... You probably want to avoid doing the entire thing on the main thread.
So, an easy solution would be to add a new method:
private void copyEverythingAsync(string source, string target)
{
Task.Run(()=> copyEverything(source, target));
}
And then remove the async/await
from the copyEverything
method.
This will move the operation onto a new thread from the ThreadPool
and not block your main thread.
Upvotes: 1