Как я могу использовать большой файл в Delphi? - PullRequest
3 голосов
/ 02 июля 2011

Когда я использую большой файл в потоке памяти или в потоке файлов, я вижу ошибку "недостаточно памяти". Как мне решить эту проблему?

Пример:

procedure button1.clıck(click);
var
  mem:TMemoryStream;
  str:string;
begin
  mem:=Tmemorystream.create;
  mem.loadfromfile('test.txt');----------> there test.txt size 1 gb..
  compressstream(mem);
end;

Ответы [ 4 ]

11 голосов
/ 02 июля 2011

Ваша реализация очень грязная. Я не знаю точно, что делает CompressStream, но если вы хотите работать с большим файлом в виде потока, вы можете сэкономить память, просто используя TFileStream, вместо того, чтобы пытаться прочитать все это в TMemoryStream все сразу.

Кроме того, вы никогда не освобождаете TMemoryStream, когда закончите с ним, а это значит, что вы будете терять большую часть памяти. (Если CompressStream не позаботится об этом, но это не ясно из кода, и на самом деле не стоит писать его таким образом.)

7 голосов
/ 02 июля 2011

Вы не можете поместить весь файл в один непрерывный блок 32-битного адресного пространства. Отсюда ошибка нехватки памяти.

Чтение файла небольшими частями и обработка его по частям.

5 голосов
/ 02 июля 2011

Отвечая на вопрос в заголовке, вам нужно обрабатывать файл по частям, побайтно, если это необходимо: вы окончательно не загружаете файл сразу в память!То, как вы это сделаете, очевидно, зависит от того, что вам нужно сделать с файлом;Но поскольку мы знаем, что вы пытаетесь реализовать кодировщик Хаффмана, я дам вам несколько конкретных советов.

Кодировщик Хаффмана - это потоковый кодировщик: байты входят и биты уходят.Каждая единица входящих данных заменяется соответствующей битовой комбинацией.Кодировщику не нужно видеть весь файл сразу, потому что на самом деле он работает только с одним байтом каждый раз.

Вот как вы можете сжимать файл без сжатия.загрузка всего этого в память;Конечно, фактический кодировщик Хаффмана не показан, потому что речь идет о работе с большими файлами, а не о создании фактического кодировщика.Этот фрагмент кода включает в себя буферизованный ввод и вывод и показывает, как вы должны связать с ним фактическую процедуру кодировщика.

(будьте осторожны, код, написанный в браузере; если он не компилируется, вы ожидаетечтобы исправить это!)

type THuffmanBuffer = array[0..1023] of Byte; // Because I need to pass the array as parameter

procedure DoActualHuffmanEncoding(const EncodeByte:Byte; var BitBuffer: THuffmanBuffer; var AtBit: Integer);
begin
  // This is where the actual Huffman encoding would happen. This procedure will
  // copy the correct encoding for EncodeByte in BitBuffer starting at AtBit bit index
  // The procedure is expected to advance the AtBit counter with the number of bits
  // that were actually written (that's why AtBit is a var parameter).   
end;

procedure HuffmanEncoder(const FileNameIn, FileNameOut: string);
var InFile, OutFile: TFileStream;
    InBuffer, OutBuffer: THuffmanBuffer;
    InBytesCount: Integer;
    OutBitPos: Integer;
    i: Integer;
begin
  // First open the InFile
  InFile := TFileStream.Create(FileNameIn, fmOpenRead or fmShareDenyWrite);
  try
    // Now prepare the OutFile
    OutFile := TFileStream.Create(FileNameOut, fmCreate);
    try
      // Start the out bit counter
      OutBitPos := 0;
      // Read from the input file, one buffer at a time (for efficiency)
      InBytesCount := InFile.Read(InBuffer, SizeOf(InBuffer));
      while InBytesCount <> 0 do
      begin
        // Process the input buffer byte-by-byte
        for i:=0 to InBytesCount-1 do
        begin
          DoActualHuffmanEncoding(InBuffer[i], OutBuffer, OutBitPos);
          // The function writes bits to the outer buffer, not full bytes, and the
          // encoding for a rare byte might be significantly longer then 1 byte.
          // Whenever the output buffer approaches it's capacity we'll flush it
          // out to the OutFile
          if (OutBitPos > ((SizeOf(OutBuffer)-10)*8) then
          begin
            // Ok, we've got less then 10 bytes available in the OutBuffer, time to
            // flush!
            OutFile.Write(OutBuffer, OutBitPos div 8);
            // We're now possibly left with one incomplete byte in the buffer.
            // We'll copy that byte to the start of the buffer and continue.
            OutBuffer[0] := OutBuffer[OutBitPos div 8];
            OutBitPos := OutBitPos mod 8;
          end;
        end;
        // Read next chunk
        InBytesCount := InFile.Read(InBuffer, SizeOf(InBuffer));
      end;

      // Flush the remaining of the output buffer. This time we want to flush
      // the final (potentially incomplete) byte as well, because we've got no
      // more input, there'll be no more output.
      OutFile.Write(OutBuffer, (OutBitPos + 7) div 8);

    finally OutFile.Free;
    end;     
  finally InFile.Free;
  end;
end;

Кодировщик Хаффмана не сложный для реализации, но сделать это правильно, и fast , может оказаться сложной задачей.Я предлагаю вам начать с правильного кодера, как только вы освоите кодирование и декодирование, выясните, как сделать быстрый кодер.

1 голос
/ 02 июля 2011

попробуйте что-то вроде http://www.explainth.at/en/delphi/mapstream.shtml

...