【问题标题】:Why FileSavePicker is not replacing file?为什么 FileSavePicker 不替换文件?
【发布时间】:2018-03-12 03:39:09
【问题描述】:

当我使用 FileSavePicker 选择(或创建)存储文件时,如果我选择现有文件,它会提示替换。当我按是时,我希望稍后会替换该文件,但事实并非如此。

// existing file is picked, I pressed yes when replace was requested.
file = await picker.PickSaveFileAsync();

所以使用上面的代码,现有文件由 FileSavePicker 选择,我预计 file 现在已被替换,但它没有。

await file.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.AllowOnlyReaders)

这只会打开文件进行写入,它不会替换它,但我希望它被替换。我的问题与this question 相同,但我不是在写文本文件,而是在写二进制数据。

如何将file 替换为新的?

我试过跟随但它抛出 NRE,因为 GetParentAsync 返回 null。

var file = await (await file.GetParentAsync()).CreateFileAsync(file.Name,
                        CreationCollisionOption.ReplaceExisting);

我不希望用户通过删除旧文件并创建新文件来明确创建新文件。我想要的是,如果用户选择现有文件并接受来自 FileSavePicker 的替换请求,则应替换该文件。


好的,这是您可以在您的机器上测试的代码。

var picker = new FileSavePicker
{
    SuggestedStartLocation = PickerLocationId.Desktop,
    DefaultFileExtension = ".bin",
    SuggestedFileName = "Binary file"
};
picker.FileTypeChoices.Add("Binary File", new List<string> {".bin"});

// in second run, choose existing file.
var file = await picker.PickSaveFileAsync();

using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.AllowOnlyReaders))
{
    using (var output = stream.GetOutputStreamAt(0))
    {
        using (var writer = new DataWriter(output))
        {
            writer.WriteBytes(Enumerable.Repeat<byte>(10, 10000).ToArray());
            await writer.StoreAsync();
            writer.DetachStream();
        }
        await output.FlushAsync();
    }
}

运行两次,第一次运行,创建文件。在第二次运行中选择现有文件,并将Repeat&lt;byte&gt;(10, 10000) 更改为更小和不同的内容,例如Repeat&lt;byte&gt;(80, 50) 并检查文件内容。

【问题讨论】:

  • FileSavePicker 不会替换文件,它只是为您提供一个名称。你用这个名字下一步做什么很重要。 WinRT 中的文件操作是事务性的,您不会意外覆盖文件。只有当文件正确关闭时,它才会替换现有文件。因此,sn-ps 中缺少最重要的代码。
  • 对,如何使用它提供给我的 StorageFile 创建文件? (然后 FileSavePicker 在询问“用现有替换”时撒谎)@HansPassant
  • 我不知道你在说什么。发布 SO 用户实际上可以自己运行以验证您的声明的代码。
  • @HansPassant 已经为您提供了示例,如果可以,请测试此代码并让我知道您观察到的情况。谢谢。
  • WinRT 没有足够的理由截断现有文件。考虑 StorageFolder.CreateFileAsync 以便您可以指定 CreationCollisionOption.ReplaceExisting

标签: c# uwp filesavepicker


【解决方案1】:

您始终可以先将打开的流的SetLength 设置为 0 - 这将清除所有旧内容并将流的位置设置为 0。然后您可以将新内容写入流:

var picker = new FileSavePicker
{
    SuggestedStartLocation = PickerLocationId.Desktop,
    DefaultFileExtension = ".bin",
    SuggestedFileName = "Binary file"
};
picker.FileTypeChoices.Add("Binary File", new List<string> { ".bin" });
var file = await picker.PickSaveFileAsync();

using (var stream = await file.OpenStreamForWriteAsync())
{
    stream.SetLength(0);
    var bytes = Encoding.ASCII.GetBytes("Content");
    await stream.WriteAsync(bytes, 0, bytes.Length);
    await stream.FlushAsync();
}

【讨论】:

  • 太棒了,我想知道为什么这还没有成为任何人的问题?我花了一天的时间才意识到我的应用程序没有错误,但它的旧内容与数据阅读器混淆。
  • 我也可以在写入结束时设置长度,SetLength(bytesWritten) 这样万一写入器遇到问题,旧数据不会丢失。
  • @M.kazemAkhgary 是的,如果需要,SetLength 将截断或扩展流。
猜你喜欢
  • 2021-12-07
  • 2015-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-08
  • 2014-12-21
  • 1970-01-01
  • 2022-11-04
相关资源
最近更新 更多