我想要一个方法,它将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);
}
}
}
}
}
}
问题是,当我尝试在while循环(第一次读取)中读取数据时,会引发异常(超出范围)。流应该有数据。我不确定是否需要这么长的代码,如果有人有更好的解决方案,那就太好了。旁注:如果我尝试await reader.LoadAsync(50)
,它会返回50。我不确定LoadAsync应该做什么。也许我必须在读取之前调用它,为读取准备数据?我会进一步调查。。。此外,Stream.CanRead返回true。
问题不是像我最初认为的那样转换流。只是不知道如何在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
才能提交数据(刷新是不够的)。
我希望这能帮助到别人。
我建议不要使用这种代码,而是利用Windows运行时互操作扩展方法。这将产生一个更整洁、更可读的代码,例如:
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);
}
}