5
\$\begingroup\$

Here is my effort to implement extensions for FileInfo object:

public static class FileExtensions
{
    public static async Task MoveFileAsync(this FileInfo file, string destinationPath, string destinationFileName = "")
    {
        await CopyFileAsync(file, destinationPath, destinationFileName).ContinueWith((x) =>
        {
            DeleteFileAsync(file);
        }, TaskContinuationOptions.OnlyOnRanToCompletion);
    }

    public static async Task CopyFileAsync(this FileInfo file, string destinationPath, string destinationFileName = "")
    {
        if (string.IsNullOrWhiteSpace(destinationFileName))
        {
            destinationFileName = file.Name;
        }

        using (FileStream SourceStream = file.Open(FileMode.Open))
        {
            using (FileStream DestinationStream = File.Create(Path.Combine(destinationPath, destinationFileName)))
            {
                await SourceStream.CopyToAsync(DestinationStream);
            }
        }
    }

    public static Task DeleteFileAsync(this FileInfo file)
    {
        return Task.Run(() =>
        {
            if (File.Exists(file.FullName))
            {
                File.Delete(file.FullName);
            }
        });
    }
}

The idea was to make it efficient, and basically, allow deleting in the background.

It feels like I mix things, but not sure what exactly is wrong.

So, I have a couple of questions for the beginning:

  1. The implementation of MoveFileAsync:

    • Is this the right way to implement it? I wanted to call the CopyFileAsync and when it is completed -> call DeleteFileAsync.
    • Do I need to add return before DeleteFileAsync(file);? (So that the method will return a task).
  2. The next step is using this DeleteFileAsync method within a loop. Like this:

public Task EmptyWorkingFolder()
{
    var directory = new DirectoryInfo(/*my-directory-path*/);
    var deleteTasks = new List<Task>();

    foreach (FileInfo file in directory.EnumerateFiles())
    {
        deleteTasks.Add(file.DeleteFileAsync());
    }

    return Task.WhenAll(deleteTasks);
}

Now my question is, how useful is this in comparison to just deleting the files synchronously?

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Few tips: 1) if (File.Exists(file.FullName)) a redundant check, look into File.Delete documentation. 2) there's no sense to make disk operations concurrent because file system anyway does all the jobs sequentially for single drive. Run one Task for all the Delete operations if you need to await it. Measure and compare the performance of the different implementations to be sure. 3) don't mix continuations with async/await approach. 4) names for the local variables must begin with lower-cased letter. \$\endgroup\$
    – aepot
    Dec 28, 2021 at 23:21
  • \$\begingroup\$ Thanks for the tips @aepot. Could you please explain more about number 3? \$\endgroup\$
    – SeReGa
    Dec 29, 2021 at 18:45
  • 2
    \$\begingroup\$ For example this await CopyFileAsync(file, destinationPath, destinationFileName).ContinueWith((x) => { DeleteFileAsync(file); }, TaskContinuationOptions.OnlyOnRanToCompletion); can be this await CopyFileAsync(file, destinationPath, destinationFileName); DeleteFileAsync(file); with exactly the same behavior. Continuations and async/await provides the same features but simply looks differently. Mixed code is harder to read. \$\endgroup\$
    – aepot
    Dec 29, 2021 at 22:13
  • \$\begingroup\$ @aepot, now I see how it mixed, and I understand the example, however, how I will have to use 2 awaits in a row (for copy and for delete). So I think that it's better to use Task.WhenAll() to prevent losing errors. \$\endgroup\$
    – SeReGa
    Dec 30, 2021 at 5:42
  • \$\begingroup\$ @aepot, those comments seem to be reviewing the code, and therefore better presented using an answer. And you'll earn reputation points that way! \$\endgroup\$ Mar 22 at 7:43

1 Answer 1

0
\$\begingroup\$

Thank you, everyone I ended up with this code:

public static async Task MoveFileAsync(this FileInfo file, string destinationPath, string destinationFileName = "")
{
    var destinationFileFullName = Path.Combine(destinationPath, destinationFileName);

    if (file.FullName != destinationFileFullName)
    {
        await CopyFileAsync(file, destinationPath, destinationFileName);
        await DeleteFileAsync(file);
    }
}

public static async Task CopyFileAsync(this FileInfo file, string destinationPath, string destinationFileName = "")
{
    if (string.IsNullOrWhiteSpace(destinationFileName))
    {
        destinationFileName = file.Name;
    }
    var destinationFileFullName = Path.Combine(destinationPath, destinationFileName);

    if (file.FullName != destinationFileFullName)
    {
        using (FileStream sourceStream = file.Open(FileMode.Open))
        {
            using (FileStream destinationStream = File.Create(destinationFileFullName))
            {
                await sourceStream.CopyToAsync(destinationStream);
            }
        }
    }
}

public static Task DeleteFileAsync(this FileInfo file)
{
    return Task.Run(() =>
    {
        File.Delete(file.FullName);
    });
}

Please let me know if you have comments on this.

\$\endgroup\$
5
  • \$\begingroup\$ To make this a proper answer, please explain what you changed and why? \$\endgroup\$ Mar 22 at 5:37
  • \$\begingroup\$ As already stated, please explain your changes and why you made them. Just posting new code does not help the OP at all. \$\endgroup\$
    – Linny
    Mar 22 at 6:02
  • \$\begingroup\$ Thanks for posting this code. It's a good idea to summarise which changes you made, and why - a self-answer ought to review the code, just like any other answer. (That's especially true when the improvements were suggested in comments rather than answers, as comments are somewhat ephemeral). \$\endgroup\$ Mar 22 at 7:41
  • \$\begingroup\$ MoveFileAsync isn't effective if moving the file is performed in single file system. For example, take few GB file and try to copy and move it to different locations. Then copying will consume some time but moving will be performed immediately that's because of file system optimisations that using only modifications in file allocation tables but without any changes to the real file data on the disk. Use File.Move, even in Thread, then compare the performance. \$\endgroup\$
    – aepot
    Mar 22 at 16:28
  • \$\begingroup\$ Thanks @aepot, this documentation says that moving a file is equivalent to copying and deleting it: docs.microsoft.com/en-us/dotnet/api/… I will try checking it myself anyway. \$\endgroup\$
    – SeReGa
    Mar 22 at 21:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.