【问题标题】:how to convert memorystream to filestream in Delphi 7?如何在 Delphi 7 中将内存流转换为文件流?
【发布时间】:2018-07-18 13:36:42
【问题描述】:

我有这段代码,我正在将缓冲区读取到内存流中,并且我想将其保存到文件流中。问题是 memoryStream.GetBuffer() 不适用于我的 Delphi 7,因为它是未声明的标识符。

procedure Dictionary.WriteHeaderObj(filename: String);
var MemStream: TMemoryStream;
    i: Integer;
begin
  self.fileName := filename;

  try
    MemStream := TMemoryStream.Create;
    try
      fsOutput := TFileStream.Create(fileName, fmCreate);
      try
       MemStream.Write(VAR_META, lengths.VR_META);
       for i:=0 to length(buffers)-1 do
          MemStream.Write(self.buffers[i].b^,self.buffers[i].l^);
       fsOutput.Write(MemStream.GetBuffer(), 0, memoryStream.Position);
      finally
        MemStream.Free;
      end;
    finally
      fsOutput.Free;
    end;
    except
      on E:Exception do
        Writeln(E.Classname, ': ', E.Message);
  end;
end;

【问题讨论】:

  • 我不明白。从您的示例中,为什么您甚至需要TMemoryStream 并且不将数据直接写入TFileStream?你还泄露了TMemoryStream
  • 您收到范围错误,因为您访问的数组越界。除非单个缓冲区非常小,否则直接写入文件可能会更有效。在内存中创建数据的另一个副本是浪费并且会损害性能。
  • 如果不测量实际性能就没有意义。在不同的环境中也是如此。在内存不足或使用不同类型的磁盘时会表现不同。我的猜测是你会发现你实际上会减慢磁盘的速度。如果您准备过早优化,请至少阅读我发布的主题并关注其中的一些链接。
  • 综上所述,另一方面,一旦你有了TMemoryStream,你就可以简单地使用它的SaveToFile方法而不使用TFileStream。所以混合这两种流类型似乎毫无意义。
  • @jerry 但是,如果您一次写入几个字节,那么由于用户模式和内核模式之间的所有切换,性能都会受到影响。这就是我们有时喜欢缓冲输出的原因。

标签: delphi filestream memorystream


【解决方案1】:

您的代码显示了一些初学者常见的错误。

  1. 确实不需要TMemoryStream。正如 David 所说,这会损害性能。
  2. 将所有内容都写入单个 TMemoryStream 也不是一个好主意,因为您可能会遇到“内存不足”问题。
  3. 如果缓冲区非常小并且使用内存缓冲区是有益的,您应该在两个循环中执行 - 内循环将一定数量的数据写入内存流,而外循环将内存流复制到文件流并清空内存流。
  4. 不幸的是,TMemoryStream 中的Capacity(受保护)没有用,因为每当Size 更改时,TMemoryStream 都会重新分配内存。使用足够大的TBytes 可以避免内存重新分配,但您需要跟踪长度。
  5. 为什么你只是将标头对象写入文件?您打算稍后将正文附加到文件中吗?附加文件通常是个坏主意。
  6. 一些琐碎的事情:始终将string 常量与const 一起传递。
  7. 一些琐碎的事情:始终以“T”开头的类型名称。

我会这样做:

procedure TDictionary.SaveHeaderToStream(AStream: TStream);
// You want to write to a stream, not a file. This is more reusable.
// You don't want to put the create/free code here,
// this is more flexible as it can also be used by SaveToStream
var
  i: Integer;
begin
  for i := 0 to length(buffers) - 1 do
    AStream.Write(self.buffers[i].b^, self.buffers[i].l^);
end;

procedure TDictionary.SaveHeaderToFile(const Filename: string);
var
  fsOutput: TFileStream;
begin
  fsOutput := TFileStream.Create(Filename, fmCreate);
  try
    SaveHeaderToStream(fsOutput);       // fsOutput IS TStream
  finally
    fsOutput.Free;
  end;
end;

procedure TDictionary.SaveBodyToStream(AStream: TStream);
begin
  // Codes here
end;

procedure TDictionary.SaveToStream(AStream: TStream);
begin
  SaveHeaderToStream(AStream);
  SaveBodyToStream(AStream);
end;

procedure TDictionary.SaveToFile(const Filename: string);
var
  fsOutput: TFileStream;
begin
  fsOutput := TFileStream.Create(Filename, fmCreate);
  try
    SaveToStream(fsOutput);
  finally
    fsOutput.Free;
  end;
end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-31
    相关资源
    最近更新 更多