【问题标题】:Read Line with TFileStream delphi用 TFileStream delphi 读取行
【发布时间】:2012-07-20 19:25:41
【问题描述】:

如何使用 TFileStream 的某些行读取文件。我读了有数百万个文件的行。所以我想在我只会使用的记忆中玩耍

例子:

Line 1: 00 00 00 00 00 00 00 00
Line 2: 00 00 00 00 00 00 00 00
Line 3: 00 00 00 00 00 00 00 00
Line 4: 00 00 00 00 00 00 00 00
Line 5: 00 00 00 00 00 00 00 00

我读了第 2 到 4 行

我使用了一个函数TextFile,但它似乎很慢。刚刚找到了一个读取TFileStream最后一行的函数。

【问题讨论】:

标签: delphi tfilestream


【解决方案1】:

您可以像这样使用 TFileStream 类打开文件进行读取...

FileStream := TFileStream.Create( 'MyBigTextFile.txt', fmOpenRead)

TFileStream 不是一个引用计数的对象,所以一定要在完成后释放它,就像这样......

FileStream.Free

从现在开始,我将假设您文件的字符编码是 UTF-8,并且行尾终止符是 MS 样式。如果不是,请相应调整,或​​更新您的问题。

您可以像这样读取 UTF-8 字符的单个代码单元(与读取单个字符不同):

var ch: ansichar;
FileStream.ReadBuffer( ch, 1);

你可以像这样阅读一行文字...

function ReadLine( var Stream: TStream; var Line: string): boolean;
var
  RawLine: UTF8String;
  ch: AnsiChar;
begin
result := False;
ch := #0;
while (Stream.Read( ch, 1) = 1) and (ch <> #13) do
  begin
  result := True;
  RawLine := RawLine + ch
  end;
Line := RawLine;
if ch = #13 then
  begin
  result := True;
  if (Stream.Read( ch, 1) = 1) and (ch <> #10) then
    Stream.Seek(-1, soCurrent) // unread it if not LF character.
  end
end;

读取第 2、3 和 4 行,假设位置在 0 ...

ReadLine( Stream, Line1);
ReadLine( Stream, Line2);
ReadLine( Stream, Line3);
ReadLine( Stream, Line4);

【讨论】:

  • 对于大文件来说,这将是非常缓慢的。一次调用 ReadFile 1 个字节会很痛。
  • 其实是的。 O/S 缓冲区,但调用 ReadFile 有很大的开销。我在这里的一个答案详细介绍了这一点。
  • 它是否有效很大程度上取决于上下文和您的期望。 OP 可以很容易地调整和读取块。但是上述解决方案是 OP 获得基本思想所需的全部。为了提高效率,有无数种变化。但这些都是上下文相关的,这种优化最好留给 OP。
  • 好吧,如果要读取很多行,就需要优化。我参考的答案在这里:stackoverflow.com/questions/5639531/…
  • 感谢您的回复。在 delphi 7 中,给出错误代码 Stream.Seek (soCurrent, -1) 存在可以使用这些参数调用的“Seek”的重载版本格式为 UTF8
【解决方案2】:

您可以使用传统的文件操作。 要真正快速,您必须确保每行中的字节数相同。

Blockread、BlockWrite、Seek 是您可能会查看的关键字。

Sample page for BlockRead

Sample page for Seek

【讨论】:

  • +1 以抵消反对票。鉴于安德烈对我的评论“你的线条可能是固定大小吗?”的回应。 BlockRead()/Seek() 选项是可行的。
【解决方案3】:

正如 David 解释的那样,由于 TFileStream.Read 的原因,Sean 提出的代码很慢。但是如果你使用 TMemoryStream 而不是 TFileStream,那么慢的 Stream.Read 就不是那么重要了。在这种情况下,字符串操作会占用大部分时间。

如果您稍微更改代码,速度会提高 2 倍:

function ReadLine(Stream: TStream; var Line: string): boolean;
var
  ch: AnsiChar;
  StartPos, LineLen: integer;
begin
  result := False;
  StartPos := Stream.Position;
  ch := #0;
  while (Stream.Read( ch, 1) = 1) and (ch <> #13) do;
  LineLen := Stream.Position - StartPos;
  Stream.Position := StartPos;
  SetString(Line, NIL, LineLen);
  Stream.ReadBuffer(Line[1], LineLen);
  if ch = #13 then
    begin
    result := True;
    if (Stream.Read( ch, 1) = 1) and (ch <> #10) then
      Stream.Seek(-1, soCurrent) // unread it if not LF character.
    end
end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多