如何在Delphi中使用大文件?

如何在Delphi中使用大文件?,delphi,delphi-7,Delphi,Delphi 7,当我在memorystream或filestream中使用一个大文件时,我看到一个“内存不足”的错误 我怎样才能解决这个问题 例如: procedure button1.clıck(click); var mem:TMemoryStream; str:string; begin mem:=Tmemorystream.create; mem.loadfromfile('test.txt');----------> there test.txt size 1 gb.. co

当我在memorystream或filestream中使用一个大文件时,我看到一个“内存不足”的错误 我怎样才能解决这个问题

例如:

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;

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


以较小的片段读取文件,并逐段处理。

尝试类似的方法。

您的实现非常混乱。我不知道CompressStream到底是做什么的,但是如果你想把一个大文件当作一个流来处理,你可以通过简单地使用一个TFileStream来节省内存,而不是试图一次将整个文件读入一个TMemoryStream


此外,在使用TMemoryStream之后,您永远无法释放它,这意味着您将泄漏大量内存。(除非CompressStream解决了这个问题,但是代码中没有明确说明这一点,而且这样写确实不是一个好主意。)

回答标题中的问题,您需要逐段、逐字节地处理文件(如果需要的话):您肯定不会一次将文件加载到内存中!你怎么做显然取决于你需要对文件做什么;但是,既然我们知道您正在尝试实现一个哈夫曼编码器,我将给您一些具体的提示

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

下面是如何在不将文件全部加载到内存的情况下对文件进行哈夫曼压缩;当然,没有显示实际的哈夫曼编码器,因为问题是关于处理大文件,而不是构建实际的编码器。这段代码包括缓冲输入和输出,并显示如何将实际的编码器过程链接到它

(注意,在浏览器中编写的代码;如果它无法编译,您需要修复它!)

type THuffmanBuffer=Byte的数组[0..1023];//因为我需要将数组作为参数传递
过程DoActualHuffmanEncoding(常量EncodeByte:Byte;变量BitBuffer:THuffmanBuffer;变量AtBit:Integer);
开始
//这就是实际的哈夫曼编码发生的地方。此程序将
//从AtBit位索引开始,复制位缓冲区中EncodeByte的正确编码
//预计该程序将使AtBit计数器以位数前进
//这实际上是编写的(这就是为什么AtBit是一个var参数)。
结束;
过程HuffmanEncoder(const FileNameIn,FileNameOut:string);
变量infle,OutFile:TFileStream;
InBuffer,exputffer:THuffmanBuffer;
InByteScont:整数;
OutBitPos:整数;
i:整数;
开始
//首先打开内嵌
infle:=TFileStream.Create(FileNameIn、fmOpenRead或fmShareDenyWrite);
尝试
//现在准备输出文件
OutFile:=TFileStream.Create(FileNameOut,fmCreate);
尝试
//启动输出位计数器
OutBitPos:=0;
//从输入文件读取,一次一个缓冲区(为了效率)
InByteScont:=infle.Read(InBuffer,SizeOf(InBuffer));
而InByteScont 0可以
开始
//逐字节处理输入缓冲区
对于i:=0到InByteScont-1 do
开始
doactualhuffman编码(InBuffer[i]、exputffer、OutBitPos);
//该函数将位写入外部缓冲区,而不是完整字节,并且
//稀有字节的编码可能比1字节长很多。
//每当输出缓冲区接近其容量时,我们将刷新它
//出海
如果(OutBitPos>((SizeOf(exputffer)-10)*8),则
开始
//好的,我们在Exputffer中的可用字节少于10个,是时候开始了
//同花顺!
输出文件写入(OutBuffer,OutBitPos第8部分);
//我们现在可能在缓冲区中只剩下一个不完整的字节。
//我们将把该字节复制到缓冲区的开头,然后继续。
exputffer[0]:=exputffer[OutBitPos div 8];
OutBitPos:=OutBitPos mod 8;
结束;
结束;
//读下一块
InByteScont:=infle.Read(InBuffer,SizeOf(InBuffer));
结束;
//刷新剩余的输出缓冲区。这次我们要刷新
//最后一个字节(可能不完整),因为我们没有
//输入越多,输出就越少。
输出文件写入(OutBuffer,(OutBitPos+7)第8部分);
最后输出文件。自由;
结束;
最后填充。自由;
结束;
结束;

哈夫曼编码器不是一个很难实现的编码器,但正确快速地实现它可能是一个挑战。我建议您从正确的编码器开始,一旦编码和解码都完成了,就想办法实现一个快速编码器。

为什么您需要一次将整个文件存储在内存中?分块读取它并处理我的问题吗不喜欢这样吗?从文件和压缩流(mem)中取出加载直接从磁盘上的文件进行压缩!你不需要内存映射文件来解决这个问题。解释一下为什么它们会解决这个问题。这不是唯一的答案,但这是一种可能性,取决于他需要如何处理它。我使用内存映射文件来搜索文件中的字符串/数据,速度比我认为加载时要快得多文件映射(假设为保护页)是将数据馈送到[未知]的最佳方法编码者,然而,链接是非常无用的,因为它有奇怪的方法和没有来源。@Cenk Aybeyaz,你真的应该开始发布相关的代码摘录和你的问题了。我按照你说的做了。如果我分割文件,你认为如何缩短处理时间?我不知道。我不知道你在用这个文件做什么。你认为呢但是处理时间,@Cenk?你认为它会走多快?它实际上会走多快?@Cenk:现在你不用处理了
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;