2016-04-11 29 views
6

你好老乡程序员损坏图像使用的读取和写入流保存文件

我使用Xamarin(IOS)实现下载功能在应用程序,以获取有关它正在下载文件的进度时。

我使用的代码是来自网络各处的各种示例,显示了相同的主体,编码风格最大的区别。它们都在System.IO.File上使用相同的ReadAsync和WriteAsync函数,并使用字节数组作为缓冲区。

但无论我变成什么例子,它导致的图片让他们不同的文物,像这样:

(原件/下载)

我可以” t似乎找到任何理由为什么会发生这种情况。 我试过不同的事情,看看有什么可以触发这一点。我发现将缓冲区更改为更大的尺寸(比如说10240)会导致更多的工件,而较小的缓冲区(例如1024)会导致更少的工件。当调试不同的事情时,我发现了一种“避免”这种情况发生的方式,但是这包括在WriteAsync刚刚完成后立即添加一个任务延迟,时间为20毫秒(代码中注释掉了) - 不是解决方案我想要一起去,但告诉问题可能在两个流的使用(巫婆我的知识是'基本使用只')。 我也尝试使用非异步方法,但给出了相同的结果。

希望有人能告诉我我在这里做错了什么,为什么。

在此先感谢

public async Task<bool> MakeDownloadRequestAsync(string url, string destination, Action<string, long, long, float> progress = null) { 
    if (_downloadHttpClient == null) { 
     _downloadHttpClient = new HttpClient (new NativeMessageHandler()); 
    } 

    bool finished = false; 

    try { 
     var result = await _downloadHttpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); 

     long receivedBytes = 0; 
     long totalBytes = result.Content.Headers.ContentLength.HasValue ? result.Content.Headers.ContentLength.Value : 0; 

     System.Diagnostics.Debug.WriteLine ("Started download file: {0}", url); 

     using (var stream = await _downloadHttpClient.GetStreamAsync (url)) 
     { 
      byte[] buffer = new byte[4096]; 
      var filename = Path.GetFileName (url); 
      var writeStream = _fileStore.OpenWrite (Path.Combine(destination, filename)); 

      while(true) 
      { 
       int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length); 

       if (bytesRead == 0) 
       { 
        finished = true; 
        System.Diagnostics.Debug.WriteLine ("Finished downloading file: {0}", url); 
        break; 
       } 


       await writeStream.WriteAsync(buffer, 0, buffer.Length); 
       //Task.Delay(20); 
       receivedBytes += bytesRead; 

       if (progress != null) 
       { 
        progress.Invoke(url, receivedBytes, totalBytes, (float)receivedBytes/(float)totalBytes); 
       } 
      } 

      writeStream.Dispose(); 
      stream.Dispose(); 
     } 

    } catch (Exception e) { 
     System.Diagnostics.Debug.WriteLine (e); 
    } 


    return finished; 
} 
+0

您可以在操作前后提供确切的图像文件吗? – enkryptor

回答

6

你的问题可能是这一行:

await writeStream.WriteAsync(buffer, 0, buffer.Length); 

它应该是:

await writeStream.WriteAsync(buffer, 0, bytesRead); 

您的代码编写整个缓冲区......不管实际读取的字节数。相反,您只应写入实际读取的字节数。

+0

当然,这很有道理。我预计缓冲区的长度取决于它的内容,但这将是一个固定的大小(正如我问的那样)。感谢百万道格! –

+0

很高兴帮助Pelle。这是一个常见的错误。如果我可以发表另一条评论,则不需要stream.Dispose()调用。当您使用using语句时,将自动调用Dispose。 –

+0

我知道double stream.Dispose(),是另一个失败的尝试,看看有什么可以解决这个问题。但感谢把它给我的关注:) –

0

我找不出上述源代码有什么问题。但我有一个片段来下载文件,并保存完美的作品。

public async static Task DownloadByteArray(string url) 
{ 
    using (var client = new HttpClient(new NativeMessageHandler())) 
    { 
     try 
     { 
      using (var response = await client.GetAsync(new Uri (url))) 
      { 
       using (var responseContent = response.Content) 
       { 
        var byteArray = await responseContent.ReadAsByteArrayAsync(); 
        var folderPath = System.IO.Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments), "Downloads"); 
        System.IO.Directory.CreateDirectory (folderPath); 

        var extension = url.Split ('.').Last(); 
        string filename = System.IO.Path.Combine (folderPath, DateTime.Now.ToString("yyyyMMddhhmmss")+"."+ extension); 
        File.WriteAllBytes (filename,byteArray); 
       } 
      } 
     } 
     catch (Exception ex) 
     { 

     } 
    } 
} 

我会解释一下在这段代码中是否有任何疑问。

+0

感谢您的建议。这是一个下载到内存中的字节数组。我可能下载的文件可能比可用内存大。也不会给我当前正在下载的文件的进度。 –

相关问题