反序列化非常大的图像文件
Deserialize very large image file
我正在从 Web API 接收图像集作为 ImageData 对象的列表,每个对象都包含一个字节数组。
public class ImageData
{
public byte[] data;
}
当我有许多小尺寸图像时,我可以接收 API 响应并使用 JObject 反序列化它,没有任何问题。以下完美运行。
using (var sr = new StreamReader(stream))
using (var jr = new JsonTextReader(sr))
{
while (jr.Read())
{
if (jr.TokenType == JsonToken.StartObject)
{
imageData = JObject.Load(jr).ToObject<ImageData>();
}
}
}
但是,有时我有一个非常大的图像文件(超过 200MB)。在这种情况下,常规反序列化方法不起作用。我不断收到 OutOfMemory 异常。
我尝试读取缓冲区中的响应并获取字节数组,但所有读取字节的最终大小总是大于实际图像大小。如果原始图像大小约为 220MB,我最终得到的图像大小约为 295MB,我相信是由于编码的原因。所以图像永远无法正确写入。
以下是我如何进行缓冲阅读。
byte[] buffer = new byte[1024];
List<byte[]> imageBytes = new List<byte[]>();
while (true)
{
int read = stream.Read(buffer, 0, buffer.Length);
if (read <= 0)
break;
imageBytes.Add(buffer);
}
var output = new byte[imageBytes.Sum(arr => arr.Length)];
int writeIdx = 0;
foreach (var byteArr in imageBytes)
{
byteArr.CopyTo(output, writeIdx);
writeIdx += byteArr.Length;
}
imageData = new ImageData() { data = output };
我在这里错过了什么?如何在没有内存异常或额外字节的情况下从这个巨大的有效载荷中获取图像数据?
----更新---
我在下面尝试过,但字节数仍然比原来的多。
while (true)
{
read = await stream.ReadAsync(buffer, 0, 1024);
++count;
if (read <= 0)
bytesRead += read;
ms.Write(buffer, 0, read);
}
imageData = new ImageData() { data = ms.ToArray() };
尝试使用 FileStream,temp.dcm 大小再次约为 290MB,而原始图像约为 210MB:
string file = @"C:\Test\temp.dcm";
using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write,
FileShare.None, 4096, useAsync: true))
{
await response.Content.CopyToAsync(fs);
}
因此,显然没有简单的方法可以直接反序列化包含单个对象的巨大响应而不会出现内存异常。相反,我最终交替 API 回应。
如果有许多较小尺寸的图像,我像往常一样将它们作为 ImageData 对象列表发送,并使用 JObject 进行反序列化。
如果只有一张大图片,我只从 API 发送字节数组,并读取收到的响应中的字节。
我正在从 Web API 接收图像集作为 ImageData 对象的列表,每个对象都包含一个字节数组。
public class ImageData
{
public byte[] data;
}
当我有许多小尺寸图像时,我可以接收 API 响应并使用 JObject 反序列化它,没有任何问题。以下完美运行。
using (var sr = new StreamReader(stream))
using (var jr = new JsonTextReader(sr))
{
while (jr.Read())
{
if (jr.TokenType == JsonToken.StartObject)
{
imageData = JObject.Load(jr).ToObject<ImageData>();
}
}
}
但是,有时我有一个非常大的图像文件(超过 200MB)。在这种情况下,常规反序列化方法不起作用。我不断收到 OutOfMemory 异常。
我尝试读取缓冲区中的响应并获取字节数组,但所有读取字节的最终大小总是大于实际图像大小。如果原始图像大小约为 220MB,我最终得到的图像大小约为 295MB,我相信是由于编码的原因。所以图像永远无法正确写入。 以下是我如何进行缓冲阅读。
byte[] buffer = new byte[1024];
List<byte[]> imageBytes = new List<byte[]>();
while (true)
{
int read = stream.Read(buffer, 0, buffer.Length);
if (read <= 0)
break;
imageBytes.Add(buffer);
}
var output = new byte[imageBytes.Sum(arr => arr.Length)];
int writeIdx = 0;
foreach (var byteArr in imageBytes)
{
byteArr.CopyTo(output, writeIdx);
writeIdx += byteArr.Length;
}
imageData = new ImageData() { data = output };
我在这里错过了什么?如何在没有内存异常或额外字节的情况下从这个巨大的有效载荷中获取图像数据?
----更新---
我在下面尝试过,但字节数仍然比原来的多。
while (true)
{
read = await stream.ReadAsync(buffer, 0, 1024);
++count;
if (read <= 0)
bytesRead += read;
ms.Write(buffer, 0, read);
}
imageData = new ImageData() { data = ms.ToArray() };
尝试使用 FileStream,temp.dcm 大小再次约为 290MB,而原始图像约为 210MB:
string file = @"C:\Test\temp.dcm";
using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write,
FileShare.None, 4096, useAsync: true))
{
await response.Content.CopyToAsync(fs);
}
因此,显然没有简单的方法可以直接反序列化包含单个对象的巨大响应而不会出现内存异常。相反,我最终交替 API 回应。
如果有许多较小尺寸的图像,我像往常一样将它们作为 ImageData 对象列表发送,并使用 JObject 进行反序列化。
如果只有一张大图片,我只从 API 发送字节数组,并读取收到的响应中的字节。