如何在WinRT中将数据从流保存到文件?

时间:2014-10-09 08:17:16

标签: c# stream windows-runtime windows-8.1 winrt-async

我想有一个方法,它将System.IO.Stream作为输入,并使用它将数据从它写入文件。到目前为止,我有以下内容:

    public async Task SaveStreamToFileX(Stream stream, string filePath, IProgress<long> progress)
    {

        var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetDirectoryName(filePath));

        var fileName = Path.GetFileName(filePath);
        StorageFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);

        var istream = stream.AsInputStream();

        var canRead = stream.CanRead; //this returns true

        using (var reader = new DataReader(istream))
        {
            using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
            {
                using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
                {
                    using (DataWriter writer = new DataWriter(outputStream))
                    {
                        IBuffer buffer;
                        long readBytes = 0;
                        const int bufferSize = 8192;
                        while ((buffer = reader.ReadBuffer(bufferSize)).Length > 0) //exception System.Exception with message: Out of range ...
                        {
                            writer.WriteBuffer(buffer);
                            readBytes += bufferSize;
                            progress.Report(readBytes);
                        }
                    }
                }
            }
        }

    }

问题是,当我尝试在循环(第一次读取)中读取数据时,抛出异常(超出范围)。流应该有数据。我不确定是否有这么长的代码是必要的,如果有人有更好的解决方案它会很棒。 边注:  如果我尝试await reader.LoadAsync(50)它会返回50.我不确定LoadAsync应该做什么。也许我必须在读取之前调用它来为读取准备数据?我会进一步研究这个......  此外,Stream.CanRead返回true。

2 个答案:

答案 0 :(得分:1)

问题不在于转换流,正如我想象的那样。缺少知识如何在WinRT中完成文件的工作(在我看来,微软的文档非常糟糕)。

最后在我的同事的帮助下尝试了几种方法并最终得到以下结论:

    public async Task SaveStreamToFile(Stream stream, string filePath, IProgress<long> progress )
    {
        var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetDirectoryName(filePath));

        var fileName = Path.GetFileName(filePath);
        StorageFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);

        var istream = stream.AsInputStream();

        using (var reader = new DataReader(istream))
        {
            using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
            {
                using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
                {
                    using (DataWriter writer = new DataWriter(outputStream))
                    {
                        long writtenBytes = 0;
                        const int bufferSize = 8192;

                        uint loadedBytes = 0;
                        while ((loadedBytes = (await reader.LoadAsync(bufferSize))) > 0) //!!!
                        {
                            IBuffer buffer = reader.ReadBuffer(loadedBytes);
                            writer.WriteBuffer(buffer);
                            uint tmpWritten = await writer.StoreAsync(); //!!!
                            writtenBytes += tmpWritten;
                            progress.Report(writtenBytes);
                        }
                    }
                }
            }
        }
    }    

我希望看到一些更简单的实现,但这有效。问题是缺少LoadAsync(这似乎是调用所必需的),并且在写操作期间必须调用StoreAsync才能提交数据(刷新是不够的)。

我希望这有助于某人。

答案 1 :(得分:1)

我会反对这种代码,而是利用Windows Runtime Interop extension methods。这将产生更整洁,更易读的代码,例如:

private async Task CopyToTempFile(Stream stream, string temporaryFileName) {

    var file = await ApplicationData.Current.TemporaryFolder.CreateFileAsync(temporaryFileName, CreationCollisionOption.ReplaceExisting);

    using (var outputstream = await file.OpenStreamForWriteAsync()) {
        await stream.CopyToAsync(outputstream);
    }
}