Десериализовать очень большой файл изображения - PullRequest
0 голосов
/ 05 февраля 2020

Я получаю свой набор изображений из WebAPI в виде списка объектов 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>();
     }
 }

}

Однако иногда у меня есть один очень большой файл изображения (более 200 МБ). В этом случае обычный метод десериализации не работает. Я продолжаю получать исключения OutOfMemory.

Я пытался прочитать ответ в буферах и получить байтовый массив, но конечный размер всех прочитанных байтов всегда больше, чем фактический размер изображения. Если исходный размер изображения составляет около 220 МБ, то я получаю около 295 МБ, думаю, из-за кодирования. Таким образом, изображение никогда не может быть правильно написано. Ниже показано, как я делаю буферизованное чтение.

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

Что мне здесь не хватает? Как я могу выполнить sh получение данных изображения из этой огромной полезной нагрузки без исключений памяти или дополнительных байтов?

---- Обновление ---

Я пробовал с ниже, но все еще больше число байтов, чем в оригинале.

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 снова составляет около 290 МБ, а исходного изображения - около 210 МБ:

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

1 Ответ

0 голосов
/ 06 февраля 2020

Итак, очевидно, что не существует простого способа десериализации ответа огромного размера, содержащего один объект напрямую, без получения исключений памяти. Вместо этого я стал чередовать свои ответы API.

Если есть много изображений меньшего размера, я отправляю их как список объектов ImageData как обычно и использую JObject для десериализации.

Если есть одно большое изображение, я отправляю только байт массив из API и чтение байтов по полученному ответу.

...