Search code examples
firemonkeyc++builder

only read last line of text file (C++ Builder)


Is there an efficient way to read the last line of a text file? Right now i'm simply reading each line with code like below. Then S holds the last line read. Is there a good way to grab that last line without looping through entire text file?

TStreamReader* Reader;
Reader = new TStreamReader(myfile);
while (!Reader->EndOfStream) 
{
 String S = Reader->ReadLine();
}

Solution

  • Exactly as Remy Lebeau commented:

    1. Use file access functions FileOpen,FileSeek,FileRead

      look here for example of usage:

    2. load your file by chunks from end into memory

      so make a static buffer and load file into it from end by chunks ...

    3. stop on eol (end of line) usually CR,LF

      just scan for 13,10 ASCII codes or their combinations from end of chunk. Beware some files have last line also terminated so you should skip that the first time ...

      known eols are:

      13
      10
      13,10
      10,13
      
    4. construct line

      if no eol found add whole chunk to string, if found add just the part after it ...

    Here small example:

    int hnd,siz,i,n;
    const int bufsz=256;                // buffer size
    char buf[bufsz+1];
    AnsiString lin;                     // last line output
    buf[bufsz]=0;                       // string terminator
    hnd=FileOpen("in.txt",fmOpenRead);  // open file
    siz=FileSeek(hnd,0,2);              // obtain size and point to its end
    for (i=-1,lin="";siz;)
        {
        n=bufsz;                        // n = chunk size to load
        if (n>siz) n=siz; siz-=n;
        FileSeek(hnd,siz,0);            // point to its location (from start)
        FileRead(hnd,buf,n);            // load it to buf[]
        if (i<0)                        // first time pass (skip last eol)
            {
            i=n-1; if (i>0) if ((buf[i]==10)||(buf[i]==13)) n--;
            i--;   if (i>0) if ((buf[i]==10)||(buf[i]==13)) if (buf[i]!=buf[i+1]) n--;
            }
        for (i=n-1;i>=0;i--)            // scan for eol (CR,LF)
         if ((buf[i]==10)||(buf[i]==13))
          { siz=0; break; } i++;        // i points to start of line and siz is zero so no chunks are readed after...
        lin=AnsiString(buf+i)+lin;      // add new chunk to line
        }
    FileClose(hnd);                     // close file
    // here lin is your last line