如何在Delphi中使用大文件?

时间:2011-07-01 22:17:29

标签: delphi delphi-7

当我在内存流或文件流中使用大文件时,我看到一个“内存不足”的错误 我该如何解决这个问题?

示例:

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 个答案:

答案 0 :(得分:11)

你的实施非常混乱。我不确切知道CompressStream的作用,但是如果你想把一个大文件作为一个流来处理,你可以通过简单地使用TFileStream来节省内存,而不是试图一次性将所有内容读入TMemoryStream。

此外,当你完成它时,你永远不会释放TMemoryStream,这意味着你将泄漏大量的内存。 (除非CompressStream负责这一点,但是代码中并不清楚,以这种方式编写它并不是一个好主意。)

答案 1 :(得分:7)

您无法将整个文件放入32位地址空间的单个连续块中。因此内存不足错误。

以较小的片段阅读文件并逐一处理。

答案 2 :(得分:5)

回答标题中的问题,如果需要,你需要逐个字节地处理文件:你明确地不要一次性将文件加载到内存中!你如何做到这一点显然取决于你需要对文件做什么;但既然我们知道你正在尝试实现一个霍夫曼编码器,我会给你一些具体的提示。

霍夫曼编码器是一个流编码器:字节进入并且比特输出。输入数据的每个单元都用其相应的位模式替换。编码器不需要一次看到整个文件,因为它实际上每次只能处理一个字节

这是你如何将文件压缩文件而不将其全部加载到内存中;当然,没有显示实际的霍夫曼编码器,因为问题是关于使用大文件,而不是关于构建实际的编码器。这段代码包括缓冲的输入和输出,并显示了如何将实际的编码器程序链接到它。

(注意,用浏览器编写的代码;如果它不编译,你应该修复它!)

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 编码器。

答案 3 :(得分:1)