Search code examples
c#fileuwpstoragefile

How can you modify a file after move and replacing another in UWP?


In UWP after calling MoveAndReplaceAsync to replace and old file with a new one I cannot modify the new file afterwards.

E.g. Here I open a file and save it in _file

private async void OpenButton_Click(object sender, RoutedEventArgs e)
    {
        var picker =
            new Windows.Storage.Pickers.FileOpenPicker
            {
                ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail,
                SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary
            };
        picker.FileTypeFilter.Add(".txt");

        _file = await picker.PickSingleFileAsync();
    }

This in this handler I write out to a new file, move and replace it over the opened one and then try to append.

    private async void MoveAndReplaceAndAppend_Click(object sender, RoutedEventArgs e)
    {
        // Create a temp file for writing to
        var tempFolder = ApplicationData.Current.TemporaryFolder;
        var filename = Guid.NewGuid().ToString();
        var tmpFile = await tempFolder.CreateFileAsync(filename, CreationCollisionOption.GenerateUniqueName);

        try
        {
            var stream = await tmpFile.OpenAsync(FileAccessMode.ReadWrite);
            var dw = new DataWriter(stream);
            dw.WriteString("New file");
            await tmpFile.MoveAndReplaceAsync(_file);
        }
        catch (Exception ex)
        {
            var dlg = new MessageDialog($"Error while move and replacing {ex.Message}");
            await dlg.ShowAsync();
        }

        var failures = "";
        try
        {
            await FileIO.AppendTextAsync(_file, "testing");
        }
        catch (Exception ex)
        {
            failures += $"Failed appending to _file: {ex.Message}\n";
        }

        try
        {
            await FileIO.AppendTextAsync(tmpFile, "testing");
        }
        catch (Exception ex)
        {
            failures += $"Failed appending to tmpFile: {ex.Message}\n";
        }

        var errorDialog = new MessageDialog($"Error while appending\n{failures}");
        await errorDialog.ShowAsync();
    }

I've tried appending with the old and the new StorageFile but always get the following errors.

Failed appending to _file: The process cannot access the file because it is being used by another process.

Failed appending to tmpFile: The process cannot access the file because it is being used by another process.

Solution

  • The problem is that the previous stream's lifetime did not end before replace operations. You could use Dispose() to manage the output stream's lifetime manually.

    var stream = await tmpFile.OpenAsync(FileAccessMode.ReadWrite);
    var dw = new DataWriter(stream);
    dw.WriteString("New file");
    stream.Dispose();
    

    Why don't they close automatically when they go out of scope?

    It shouldn't be necessary that manage the output stream's lifetime manually. You could also use using statement to manage stream's lifetime .

    using (var stream = await tmpFile.OpenAsync(FileAccessMode.ReadWrite))
    {
        var dw = new DataWriter(stream);
        dw.WriteString("New file");
    }
    

    The stream will be released automatically when execution leaves the using statement. For more, you could refer UWP File access permissions.