Tiberius Melanith
Tiberius Melanith

Reputation: 1

Function not working with async statement

First of all sorry for this beginner question.

I am using net Framework 4.5 and can not go higher [this is probably important]

Trying to change my file copy code from

private Void to private async void

Why? - Because as long as the copy loop runs the whole process locks up

I have read a bit into async and await but it still seems a bit mistifying for me.

Can anyone please help me?

This is the code in question:

 private async void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target)
        {
            if (target.GetFiles().Length > 0)
            {
                DeleteFilesRecursively(target);
                CopyFilesRecursively(source, target);
            }
            else
            {
                foreach (DirectoryInfo dir in source.GetDirectories())
                {
                    CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
                }
                foreach (FileInfo file in source.GetFiles())
                {
                    progressPercentage = ++targetLength / (double)sourceLength;
                    Console.WriteLine(Convert.ToInt32(progressPercentage * 100).ToString() + "%");
                    PB_MW_FileTransfer.Value = Convert.ToInt32(progressPercentage * 100);
                    file.CopyTo(Path.Combine(target.FullName, file.Name), true);
                }
            }
        }

I know I need to use await statement but no matter what I try it just gives me errors.

I tried background worker before but that is something I understand even less.

Please help me I am struggling so much with this.

just want to remind that Net Framework 4.5 is the one I use for various reasons [because of licensing]

Upvotes: 0

Views: 219

Answers (3)

Stephen Cleary
Stephen Cleary

Reputation: 456322

Why? - Because as long as the copy loop runs the whole process locks up

Your goal is to free up the UI thread.

I tried background worker before but that is something I understand even less.

BackgroundWorker is quite dated at this point. Your modern options are:

  1. Use async and await, calling asynchronous BCL I/O methods. Ideally, this would be the best solution; however, in this case (asynchronous file I/O), the BCL support is less than ideal.
  2. Use Task.Run, which is a modern replacement for BackgroundWorker. Note that you would not want to use this option on ASP.NET or other server environment.

Since you are on WinForms, Task.Run would be a perfect fit:

private void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target) { ... }

// invoked as:
await Task.Run(() => CopyFilesRecursively(source, target));

Upvotes: 1

Tiberius Melanith
Tiberius Melanith

Reputation: 1

Hey there it is me again, if anyone else has a similar problem in the future.

This is what I changed my code into. Here to share it took me quite a while and a friend helped me on a couple of occasions [like how to create sub folders etc]

 private async Task FolderCopyAsync(string source, string target)
        {
            foreach (string filename in Directory.EnumerateFiles(source, "*", SearchOption.AllDirectories))
            {
                using (FileStream SourceStream = File.Open(filename, FileMode.Open))
                {
                    var targetFilename = target + filename.Substring(source.Length);
                    Directory.CreateDirectory(Path.GetDirectoryName(targetFilename));

                    using (FileStream DestinationStream = File.Create(targetFilename))
                    {
                        await SourceStream.CopyToAsync(DestinationStream);
                    }
                }
            }
         }

Upvotes: 0

Blindy
Blindy

Reputation: 67362

Well for one thing you have to make your function return Task, because you're going to want to await it when you call it recursively. Plus every async function in general should be a Task, because presumably the point is that the caller needs to be able to await it.

As mentioned in the comments, just making a function async doesn't do anything by itself, you need to actually await other async functions for it to do anything. In particular for your case, you want to copy using FileStream.CopyToAsync -- ie, open the source stream in read mode, open the destination stream in write mode and await the copy method.

One point to notice is that async file I/O is .Net Core 3, you won't find it in .Net Framework. If you persist with using it, either don't use async at all, because the framework is not really built for it, or implement your own async file I/O with the provided IAsyncResult functions and TaskCompletionSource to signal the TPL when copying is done.

Upvotes: 1

Related Questions