charles_ebs
asked on
Reading UNIX format (LF delimited) text files
In all my Delphi applications dealing with text files so far, I've continued to use the "old" way of accessing files (Open as text, ReadLn, etc.). The explanation in the manual of the "new" method seemed a little confusing to me, and I guess I was just too lazy to figure it out since I didn't see a benefit to using it.
'Nuff rambling, on to the problem / question: If ReadLn is used on a LF-delimited file (rather than the DOS CRLF convention) it slurps the entire file in as one "line".
Can someone provide me a simple & efficient program sample that will open a file, read a LF-delimited line at a time into a string variable, until EOF is reached? Thanks.
'Nuff rambling, on to the problem / question: If ReadLn is used on a LF-delimited file (rather than the DOS CRLF convention) it slurps the entire file in as one "line".
Can someone provide me a simple & efficient program sample that will open a file, read a LF-delimited line at a time into a string variable, until EOF is reached? Thanks.
I'm not sure but I thought TStringList.LoadFromStream (and LoadFromFile) could read UNIX text files correctly with recognizing the line endings.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Alan is correct, the LoadFromFile will read $0A delimited strings correctly. For small files probably the easiest way.
Here some (inefficient) code to do what you want.
procedure TForm1.ReadUnixLn(var fd: TextFile; var s: string);
var
i: integer;
c: char;
begin
i := 0;
while ( not Eof(fd) ) do
begin
Read(fd,c);
if ( c=Chr(10) ) then
exit;
SetLength(s,i+1);
s[i] := c;
Inc(i);
end;
end;
procedure TForm1.Button2Click(Sender : TObject);
var
fd: TextFile;
s: string;
begin
try
AssignFile(fd,'data.txt');
FileMode := 0;
Reset(fd);
while ( not Eof(fd) ) do
begin
ReadUnixLn(fd,s);
ShowMessage(s);
end;
except
on e:EInOutError do
ShowMessage(e.Message);
end;
end;
Here some (inefficient) code to do what you want.
procedure TForm1.ReadUnixLn(var fd: TextFile; var s: string);
var
i: integer;
c: char;
begin
i := 0;
while ( not Eof(fd) ) do
begin
Read(fd,c);
if ( c=Chr(10) ) then
exit;
SetLength(s,i+1);
s[i] := c;
Inc(i);
end;
end;
procedure TForm1.Button2Click(Sender
var
fd: TextFile;
s: string;
begin
try
AssignFile(fd,'data.txt');
FileMode := 0;
Reset(fd);
while ( not Eof(fd) ) do
begin
ReadUnixLn(fd,s);
ShowMessage(s);
end;
except
on e:EInOutError do
ShowMessage(e.Message);
end;
end;
ASKER
Oh yeah, forgot to mention that it does need to be able to process huge files, eliminating the solutions that read the whole thing into memory.
I'll take a closer look tomorrow at Alan's UDDF reference and see if I can use it. Thanks for the input so far.
I'll take a closer look tomorrow at Alan's UDDF reference and see if I can use it. Thanks for the input so far.
ASKER
Nice unit; just add it to your program, and call AssignStreamFile instead of AssignFile, and it will read LF-delimited files.
Only problem is, it doesn't handle CRLF files, and although I didn't make that clear, it needs to be able to handle reading either type. SO..., here's the revised code section :
//F.Buffer [F.BufEnd] := Data.Buffer^ [Data.BufferOffset] ;
//Inc (Data.BufferOffset) ;
//Inc (F.BufEnd) ;
if Data.Buffer [Data.BufferOffset] <> #13 then
begin
F.Buffer [F.BufEnd] := Data.Buffer^ [Data.BufferOffset] ;
Inc (F.BufEnd) ;
end;
Inc (Data.BufferOffset) ;
I also removed the unused "Status" stuff to prevent compiler warnings. Not necessary, just my preference.
Good enough for me!
Only problem is, it doesn't handle CRLF files, and although I didn't make that clear, it needs to be able to handle reading either type. SO..., here's the revised code section :
//F.Buffer [F.BufEnd] := Data.Buffer^ [Data.BufferOffset] ;
//Inc (Data.BufferOffset) ;
//Inc (F.BufEnd) ;
if Data.Buffer [Data.BufferOffset] <> #13 then
begin
F.Buffer [F.BufEnd] := Data.Buffer^ [Data.BufferOffset] ;
Inc (F.BufEnd) ;
end;
Inc (Data.BufferOffset) ;
I also removed the unused "Status" stuff to prevent compiler warnings. Not necessary, just my preference.
Good enough for me!