使用读取和写入流保存文件时图像损坏

Corrupted images when using Read and Write streams to save files

各位程序员大家好

我正在使用 Xamarin (iOS) 在应用程序中实现下载功能,以获取正在下载的文件的进度。

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

但无论我转向哪个示例,都会导致图片上出现不同的伪像,如下所示:

(原创/下载)

我似乎找不到发生这种情况的任何原因。 我已经尝试了不同的东西,看看是什么触发了这个。我发现将缓冲区更改为更大的大小(比如 10240)会导致更多的伪影,而更小的缓冲区(比如 1024)会导致更少的伪影。

在调试不同的东西时,我发现了 "way" 到 "avoid" 这种情况的发生,但这包括在 WriteAsync 刚刚完成后立即添加一个任务延迟,持续 20 毫秒(在代码)- 不是我想要的解决方案,但告诉我问题可能在于两个流的使用(在 中我的知识是 'basic usage only')。 我也尝试使用非异步方法,但给出了相同的结果。

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

提前致谢

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

你的问题可能是这一行:

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

应该是:

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

您的代码正在写入整个缓冲区...无论实际读取了多少字节。相反,您应该只写入实际读取的字节数。

我无法弄清楚上面的源代码有什么问题。但是我有一个片段可以下载文件并保存,这对我来说非常有用。

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)
        {

        }
    }
}

如果您对这段代码有任何疑问,我会解释。