2014-10-09 3 views
0

입력으로 System.IO.Stream을 가져 와서 파일에서 데이터를 쓰는 데 사용하는 메서드가 필요합니다. 나는 사이클 (첫번째 읽기) 동안의 데이터를 읽을 때 (범위의 출력) 예외가 발생되어,WinRT에서 스트림에서 파일로 데이터를 저장하는 방법은 무엇입니까?

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를 반환합니다.

답변

1

문제는 orginally 생각으로 스트림을 변환하지 않았습니다. 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을 호출해야합니다 (플러시가 충분하지 않음).

이 도움이되기를 바랍니다.

0

그런 종류의 코드에 대해 조언하고 대신 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); 
    } 
}