使用读取和写入流保存文件时图像损坏
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)
{
}
}
}
如果您对这段代码有任何疑问,我会解释。
各位程序员大家好
我正在使用 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)
{
}
}
}
如果您对这段代码有任何疑问,我会解释。