简体   繁体   English

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

[英]How to save data from stream to file in WinRT?

I would like to have a method which takes as an input a System.IO.Stream and use it to write data from it to file. 我想有一个方法,将System.IO.Stream作为输入并将其从其中写入数据到文件中。 So far I have the following: 到目前为止,我有以下内容:

    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);
                        }
                    }
                }
            }
        }

    }

Problem is, that an exception (Out of range) is thrown when I try to read data in while cycle (first read). 问题是,当我尝试在while周期(首次读取)中读取数据时,引发了异常(超出范围)。 Stream should have data. 流应该有数据。 I am not sure if so long code is neccesarry, if somebody has better solution it would be great. 我不确定是否需要这么长时间的代码,如果有人有更好的解决方案,那会很棒。 Side note: If I try await reader.LoadAsync(50) it returns 50. I am not sure what LoadAsync should do. 旁注:如果我尝试await reader.LoadAsync(50)它将返回50。我不确定LoadAsync应该做什么。 Maybe I have to call it before read to prepare data for the read? 也许我必须在读取之前调用它以准备读取的数据? I will investigate this further ... Also, the Stream.CanRead returns true. 我将对此进行进一步调查。此外,Stream.CanRead返回true。

The problem was not with converting streams as I orginally thought. 问题不在于我最初认为的转换流。 It was just lack of the knowlidge how the work with files is done in WinRT (the docs from microsoft are really terrible in my opinion). 只是缺少有关如何在WinRT中完成文件处理的知识(我认为Microsoft的文档确实很糟糕)。

In the end with help of my collegue with tried several ways and end up with the following: 最后,在我的同事的帮助下,尝试了几种方法,最终得到以下结果:

    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);
                        }
                    }
                }
            }
        }
    }    

I would like to see some simpler implementation, but this works. 我希望看到一些更简单的实现,但这可行。 The problems were that LoadAsync was missing (which seems to be necessary to call) and during write operation the StoreAsync must be called in order to commit the data (flushing was not sufficient). 问题在于缺少LoadAsync (似乎必须调用它),并且在写操作期间必须调用StoreAsync才能提交数据(刷新不足)。

I hope this help somebody. 希望对您有所帮助。

I would advise against that kind of code and instead take advantage of Windows Runtime Interop extension methods . 我建议不要使用这种代码,而应利用Windows Runtime Interop扩展方法 That would produce a neater and more readable code, ex : 这将产生更整洁,更易读的代码,例如:

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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM