Recent

Author Topic: Delete line in text file.  (Read 35685 times)

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1946
Re: Delete line in text file.
« Reply #15 on: October 03, 2010, 10:28:19 am »
Bad design or not, such files exist, and aren't even that rare, e.g. database dumps

But what IS your problem?
You really sound paranoid (no offense).
Yes, you probably can't open 2GB database with TStringList. So what?
I can't even open a 50 MB textfile with KWrite.
Is this tool now useless? No, it's just great.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12851
  • FPC developer.
Re: Delete line in text file.
« Reply #16 on: October 16, 2010, 04:34:09 pm »
Bad design or not, such files exist, and aren't even that rare, e.g. database dumps

But what IS your problem?

That using classes to load files that use over twice the amount of memory as the file is large is not the best advice. Specially if you don't clearly mention this limitation. Moreover there are some heapfragmentation issues with tstringlist too.

Quote
You really sound paranoid (no offense).

It is not paranoia. I've seen people run into these problems several times.

Quote
Yes, you probably can't open 2GB database with TStringList. So what?

There are perfectly fine solutions (copy to 2nd file, rename back) that do work.

Quote
I can't even open a 50 MB textfile with KWrite.

Not all textfiles are meant for editors. As said, export files are quite often textfiles too.

Quote
Is this tool now useless? No, it's just great.

As said, the original poster didn't give any size indications. If you name a solution only suitable for little files, at least mention that.

typo

  • Hero Member
  • *****
  • Posts: 3051
Re: Delete line in text file.
« Reply #17 on: October 16, 2010, 04:42:19 pm »
This unit could help:

Code: [Select]
unit UTextFileStream;

{$mode Delphi}{$H+}

interface

uses Classes, SysUtils;

type
  TTextFileStream = class(TFileStream)
  private
    FBuffer: string;
    //FLineLength :integer;
  public
    function Eof: Boolean;
    function WriteLn(Text: string):int64;
    function ReadLn: string;
    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
    function RowCount: Integer;
    function EditLine(Line :integer; NewText :string):string;
  end;

implementation

{ TTextFileStream }

const
  NewLine = #13#10;

function TTextFileStream.Eof: Boolean;
begin
  Eof := Position - Length(FBuffer) = Size;
end;

function TTextFileStream.ReadLn: string;
const
  BufferLength = 10000;
var
  NewBuffer: string;
  Readed: Integer;
begin
  Readed := 1;
  while (Pos(#13, FBuffer) = 0) and (Readed > 0) do begin
    SetLength(NewBuffer, BufferLength + 2);
    Readed := Read(NewBuffer[1], BufferLength);
    SetLength(NewBuffer, Readed);
    FBuffer := FBuffer + NewBuffer;
  end;
  if Pos(#13, FBuffer) > 0 then begin
    Result := Copy(FBuffer, 1, Pos(#13, FBuffer) - 1);
    Delete(FBuffer, 1, Pos(#13, FBuffer) + 1);
  end else begin
    Result := FBuffer;
    FBuffer := '';
  end;
end;

function TTextFileStream.RowCount: Integer;
begin
  Result := 0;
  FBuffer := '';
  Seek(0, soBeginning);
  while not Eof do begin
    ReadLn;
    Inc(Result);
  end;
  Seek(0, soBeginning);
end;

function TTextFileStream.Seek(const Offset: Int64;
  Origin: TSeekOrigin): Int64;
begin
  if Origin = soCurrent then
    Result := inherited Seek(Offset - Length(FBuffer), Origin)
    else Result := inherited Seek(Offset, Origin);
  FBuffer := '';
end;

function TTextFileStream.WriteLn(Text: string):int64;
begin
  Result := 0;
  Seek(0, soEnd);
  // não acrescenta NewLine em arquivo vazio
  if Seek(0, soCurrent) > 0 then
    Write(NewLine, Length(NewLine));
  // escreve o texto
  Write(Text[1], Length(Text));
  Result := RowCount;
end;

function TTextFileStream.EditLine(Line :integer; NewText :string):string;
var
  n :integer;
  s :string;
  Buffer :string;
  BytesRead :integer;
  FileLength :integer;
  FilePos :integer;
begin
  Result := '';
  n := 0;
  s := '';
  BytesRead := 1;
  FilePos := 0;
  while (n <= Line) and not Eof do
  begin
    s := Readln;
    Inc(n);
    FilePos := FilePos + Length(s) + Length(NewLine);
  end;
  if Line >= n then
    raise Exception.Create('Line index out of bounds.');
  //FilePos := Position;
  FileLength := Seek(0, soEnd);
  Seek(FilePos, soBeginning);
  SetLength(Buffer, FileLength + Length(NewLine));
  BytesRead := Read(Buffer[1], FileLength - FilePos);
  SetLength(Buffer, BytesRead);
  NewText := NewText + NewLine;
  Seek(int64(FilePos) - int64(Length(s)) - int64(Length(NewLine)), soBeginning);
  Write(NewText[1], Length(NewText));
  Write(Buffer[1], BytesRead);
  SetSize(FilePos - Length(s) - Length(NewLine) + BytesRead + Length(NewText));
  Result := s;
end;

end.       
« Last Edit: October 16, 2010, 04:54:30 pm by typo »

 

TinyPortal © 2005-2018