Копирование части массива byte [] в PDFReader - PullRequest
4 голосов
/ 03 февраля 2012

Это продолжение продолжающейся борьбы за сокращение моего упоминания о загрузке памяти в Как пополнить байтовый массив с помощью SqlDataReader?

Итак, у меня есть байтовый массив заданного размера, для этого примера я скажу новый байт [400000]. Внутри этого массива я буду размещать PDF-файлы разных размеров (менее 400000).

код псевдо будет:

public void Run()
{
    byte[] fileRetrievedFromDatabase = new byte[400000];
    foreach (var document in documentArray)
    {
        // Refill the file with data from the database
        var currentDocumentSize = PopulateFileWithPDFDataFromDatabase(fileRetrievedFromDatabase);

        var reader = new iTextSharp.text.pdf.PdfReader(fileRetrievedFromDatabase.Take((int)currentDocumentSize ).ToArray());
        pageCount = reader.NumberOfPages;
        // DO ADDITIONAL WORK
    } 
}

private int PopulateFileWithPDFDataFromDatabase(byte[] fileRetrievedFromDatabase)
{
    // DataAccessCode Goes here
    int documentSize = 0;
    int bufferSize = 100;                   // Size of the BLOB buffer.
    byte[] outbyte = new byte[bufferSize];  // The BLOB byte[] buffer to be filled by GetBytes.

    myReader = logoCMD.ExecuteReader(CommandBehavior.SequentialAccess);

    Array.Clear(fileRetrievedFromDatabase, 0, fileRetrievedFromDatabase.Length);

    if (myReader == null)
    {
        return;
    }

    while (myReader.Read())
    {
        documentSize = myReader.GetBytes(0, 0, null, 0, 0);

        // Reset the starting byte for the new BLOB.
        startIndex = 0;

        // Read the bytes into outbyte[] and retain the number of bytes returned.
        retval = myReader.GetBytes(0, startIndex, outbyte, 0, bufferSize);

        // Continue reading and writing while there are bytes beyond the size of the buffer.
        while (retval == bufferSize)
        {
            Array.Copy(outbyte, 0, fileRetrievedFromDatabase, startIndex, retval);

            // Reposition the start index to the end of the last buffer and fill the buffer.
            startIndex += retval;
            retval = myReader.GetBytes(0, startIndex, outbyte, 0, bufferSize);
        }
    }

    return documentSize;
}

Проблема с приведенным выше кодом заключается в том, что я продолжаю получать сообщение об ошибке «Перестроить трейлер не найден. Исходная ошибка: PDF startxref not found» при попытке доступа к программе чтения PDF. Я считаю, что это потому, что байтовый массив слишком длинный и имеет конечные 0. Но поскольку я использую байтовый массив, чтобы не создавать новые объекты в LOH, мне нужно это сделать.

Итак, как мне получить только тот фрагмент массива, который мне нужен, и отправить его в PDFReader?

Обновлено

Так что я посмотрел на источник и понял, что у меня есть некоторые переменные из моего реального кода, которые сбивают с толку. Я в основном повторно использую объект fileRetrievedFromDatabase в каждой итерации цикла. Поскольку он передается по ссылке, он очищается (устанавливается на все нули), а затем заполняется в PopulateFileWithPDFDataFromDatabase. Этот объект затем используется для создания нового PDF.

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

Ответы [ 2 ]

1 голос
/ 03 февраля 2012

Судя по всему, в то время как цикл while структурирован, он не копировал данные на своей последней итерации. Необходимо добавить это:

if (outbyte != null && outbyte.Length > 0 && retval > 0)
{
    Array.Copy(outbyte, 0, currentDocument.Data, startIndex, retval);
}

Это сейчас работает, хотя мне определенно понадобится рефакторинг.

1 голос
/ 03 февраля 2012

У вас есть как минимум две опции:

  1. Обрабатывать ваш буфер как кольцевой буфер с двумя индексами для начальной и конечной позиции.нужен индекс последнего байта, записанного в outByte, и вы должны прекратить чтение, когда достигнете этого индекса.
  2. Просто прочитайте то же количество байтов, что и в массиве data, чтобы избежать чтения в«неизвестные» части буфера, которые не принадлежат одному и тому же файлу.

Другими словами, вместо bufferSize в качестве последнего параметра, необходимо иметь data.Length.

// Read the bytes into outbyte[] and retain the number of bytes returned.
retval = myReader.GetBytes(0, startIndex, outbyte, 0, data.Length);

Если длина data равна 10, а размер буфера outbyte равен 15, вам следует читать только data.Length, а не bufferSize.

Однако я все еще нене вижу, как вы повторно используете внешний буфер, если вы этим занимаетесь ... я просто не слежу за тем, что вы указали в своем ответе.Может быть, вы можете уточнить, что именно используется повторно.

...