Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2018-04

Seek with text file

8 messages · 4 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

James Richters

I am trying to figure out how I can remove the last line of a text file to replace it with a new one. I can do this with typed files with seek... but I am confused on how I could do this with just a text file.

If I use:

Var Myfile: Text;
       Mydata:String;
         Assign(myfile,'test.txt');
         append(myfile);
         Writeln(myfile,'New Line'+mydata);
         Close(myfile);
I can write to the end of the file, but I can't use seek to go to the end of the file minus one line.
If I try
Var Myfile: file of Text;
       Mydata:String;
         Assign(myfile,'test.txt');
         Reset(myfile);
         Seek(myfile,FILESIZE(myfile)-1);
         Writeln(myfile,'New Line'+mydata);
         Close(myfile);
I cannot use writeln with typed files....
so I tried with write...
Var Myfile: file of Text;
       Mydata:String;
         Assign(myfile,'test.txt');
         Reset(myfile);
         Seek(myfile,FILESIZE(myfile)-1);
         Write(myfile,'New Line'+mydata);
         Close(myfile);
I get Error: Incompatible types: got "ShortString" expected "Text"
So then I tried
Var Myfile: file of String;
       Mydata:String;
         Assign(myfile,'test.txt');
         Reset(myfile);
         Seek(myfile,FILESIZE(myfile)-1);
         Write(myfile,'New Line'+mydata);
         Close(myfile);

Well that compiles, but when I run it the new line at the end of my file is what I wanted but followed by whole long line of garbage... some of it looks like the contents of memory that was not part of the string. I'm guessing it attached a string of length 255 even though the string was not that long.

Can someone please help me understand this. I really have no concept of the difference between 'text' and 'string' The file I am trying to work with is just a regular text file like you would create with notepad.. Is there some way to open this file and use Seek to get to the line number I want? It seems to me like the file is very well defined, a CRLF at the end of each line defines how long each line is, it seems like I would be able to seek X number of these records... but I can't figure out how to define it... or write just the part of the string with my actual data in it.

If I can't use seek then what do I do? Open it, reset it, then read the entire file except the last line then somehow then write my new line?

Or do I have to read the whole file into a buffer or something, make my change, then write the whole thing out again?

Reply by email

Rik van Kekem
to James Richters

Op 03-04-2018 12:03 schreef James Richters:

Show quoted text 10 lines
So then I tried Var Myfile: file of String; Mydata:String; Assign(myfile,'test.txt'); Reset(myfile); Seek(myfile,FILESIZE(myfile)-1); Write(myfile,'New Line'+mydata); Close(myfile);

And what do you think FILESIZE(myfile) holds?
You would only strip the last character from the file with - 1.

Besides... file of String isn't a thing because String is a pointer to a area with characters and you can't have a file of string. You could do file of String[80] but in that case you don't have a normal text-file anymore.

How large are the files?
The easiest is to just load it into a TStringList and replace the last line.

If you have very very large files you would need to scan for the last line. You could do that from beginning to end but it would be better to do it from end to begin and stopping at the first CRLF. You could do that by opening it as stream of Text and stepping backwards in the file.

But a TStringList is really the easiest for small to medium text-files.

Rik

Reply by email

Rik van Kekem
to Anthony Walter

Op 03-04-2018 13:04 schreef Anthony Walter:

Show quoted text 17 lines
If the file is not to big you could simply write: procedure ChangeLastLine(const FileName, NewLine: string); var   S: TStrings; begin   S := TStringList.Create;   try     S.LoadFromFile(FileName);     if S.Count > 0 then       S[S.Count - 1] := NewLine     else       S.Add(NewLine);   finally     S.Free;   end; end;

Don't forget the S.SaveToFile(FileName) just above the finally-line otherwise nothing is saved back to the file :D

Rik

Reply by email

James Richters
to Rik van Kekem

Thank you for the advice and for the example. I don't know what is considered a large file.. these files can be maybe about 1000 lines long, most will be less, would this solution be suitable for files of this size?

Is Tstringlist something like an array of strings?

Earlier message 27 lines
-----Original Message----- From: fpc-pascal On Behalf Of Rik van Kekem Sent: Tuesday, April 03, 2018 7:20 AM To: Subject: Re: [fpc-pascal] Seek with text file Op 03-04-2018 13:04 schreef Anthony Walter: > If the file is not to big you could simply write: > > procedure ChangeLastLine(const FileName, NewLine: string); var > S: TStrings; > begin > S := TStringList.Create; > try > S.LoadFromFile(FileName); > if S.Count > 0 then > S[S.Count - 1] := NewLine > else > S.Add(NewLine); > finally > S.Free; > end; > end; Don't forget the S.SaveToFile(FileName) just above the finally-line otherwise nothing is saved back to the file :D Rik

Reply by email

Rik van Kekem
to James Richters

Op 03-04-2018 13:58 schreef James Richters:

Thank you for the advice and for the example. I don't know what is considered a large file.. these files can be maybe about 1000 lines long, most will be less, would this solution be suitable for files of this size? Is Tstringlist something like an array of strings?

Yes, TStringList is a TList with strings.
Internally it's indeed an array of strings.

From the code-snippet from Anthony you can see it's really easy to use.

1000 lines of about average 70 characters per lines would be 72*1000=70MB. For current computers with memory in the GB this is not would also be fast to read individual files.

If you however would need to do this for say 2000 files in a row, it could become slow and you would need to code it differently to make it more efficient. But for just a few individual files this is the easiest method.

Rik

Reply by email

Mark Morgan Lloyd
to Rik van Kekem
Rik van Kekem wrote
From the code-snippet from Anthony you can see it's really easy to use. 1000 lines of about average 70 characters per lines would be72*1000=70MB.

72 kB, not MB. Big enough to give some very old systems problems if they used a Windows component as an editor, but these days trivial.

Historically, things like "text" and "file of string[80]" have been fraught because of OS-specific interpretations of what a line of text was. These days there are still ambiguities because of UTF-8 etc.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

James Richters
to Rik van Kekem: Op 03-04-2018 13:58 schreef James Richters: Yes, TStringList is a TList with strings.…

For my use, it seems to work very well. I am creating a file where it pretty much appends a new entry to the end of a file, but occasionally the process needs to over-write the previous entry. This TStringlist is indeed very easy to work with this Tstringlist, especially since I was given an example, Thanks Anthony! For this process I need to write the file out for every entry, but I can think of some other places I could use this and just build the entire file in the TStringList and just write it all out once I'm done.

Sometimes I need to remember I have GB of ram now, and everything doesn't have to fit in a few K of ram anymore 😊

Earlier message 21 lines
-----Original Message----- From: fpc-pascal On Behalf Of Rik van Kekem Sent: Tuesday, April 03, 2018 8:17 AM To: Subject: Re: [fpc-pascal] Seek with text file Op 03-04-2018 13:58 schreef James Richters: > Thank you for the advice and for the example. I don't know what is considered a large file.. these files can be maybe about 1000 lines long, most will be less, would this solution be suitable for files of this size? > > Is Tstringlist something like an array of strings? Yes, TStringList is a TList with strings. Internally it's indeed an array of strings. From the code-snippet from Anthony you can see it's really easy to use. 1000 lines of about average 70 characters per lines would be 72*1000=70MB. For current computers with memory in the GB this is not would also be fast to read individual files. If you however would need to do this for say 2000 files in a row, it could become slow and you would need to code it differently to make it more efficient. But for just a few individual files this is the easiest method. Rik

Reply by email