Last Line in File

 

I wrote a function to read the last line in a file. I wanted to know if anyone knows a better method of doing that. The idea is to go to the end of file, go up to the next line, move back till '\n' is found.

//Returns the last line in a file. Exits with the pointer position at where it was.
string GetLastLine(int Handle){

        int initpos = FileTell(Handle);
        string Read = "";
        int ByteCount=3;  //  3 is for \r\n

        while( True){

                FileSeek(Handle,-1*ByteCount, SEEK_END);  //at first loop it is the last char in the last line
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                ///DEBUGGING
                int err = GetLastError();
                if( err != 0){
                        Print("GetLastLine(): Error ",err, " after FileSeek()-- " ,  ErrorDescription(err));
                        return("");
                }
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                

                Read = FileReadString(Handle);
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                ///DEBUGGING
                err = GetLastError();
                if( err != 0){
                        Print("GetLastLine(): Error ",err, " after FileReadString() -- " ,  ErrorDescription(err));
                        return("");
                }
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                


                if ( Read == "" ){  //we hit the "\r\n".

                        //roll back 
                        ByteCount--;      
                        FileSeek(Handle,-1*ByteCount, SEEK_END);  //at first loop it is the last char in the last line
                        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                        ///DEBUGGING
                        err = GetLastError();
                        if( err != 0){
                                Print("GetLastLine(): Error ",err, " after FileSeek in if ( Read == \"\" )-- " ,  ErrorDescription(err));
                                return("");
                        }
                        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                


                        Read = FileReadString(Handle);
                        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                        ///DEBUGGING
                        err = GetLastError();
                        if( err != 0){
                                Print("GetLastLine(): Error ",err, " after FileReadString() in if ( Read == \"\" ) -- " ,  ErrorDescription(err));
                                return("");
                        }

                        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                
                        FileSeek(Handle,initpos, SEEK_SET); 
                        return(Read);
                }       

                ByteCount++;
        }
    
}


I couldn't find any libraries to do this in the code base.

 

Do you know how long are the lines, or usual (min, max) length of the lines?

With this I would read starting from a position near the end of the file (few lines earlier) and simply keep the last line.

 

I am thinking on something better than moving backwards byte by byte.

For example read the last 100 bytes, check with StringFind if it contains \n.

if not, read 2*100, 3*100, etc. bytes until found. then you split the string from the position of \n.

100 bytes size may be different according to what you think as realistic length of a line.

 
szgy74:

I am thinking on something better than moving backwards byte by byte.

For example read the last 100 bytes, check with StringFind if it contains \n.

if not, read 2*100, 3*100, etc. bytes until found. then you split the string from the position of \n.

100 bytes size may be different according to what you think as realistic length of a line.


Both min and max are known. Your idea seems good. I didn't think about using StringFind() ...

 

You mean better as in elegant, more readable, or more efficient?

I normally read from the start and just discard the values until FileIsEnding. Not the most efficient but I've had no problems. How long are your files?

 
BenLinus:

Both min and max are known. Your idea seems good. I didn't think about using StringFind() ...


I wonder if using delimiter "\n" instead of ";" in FileOpen() would automatically read to the end of the current line. So you don't have to bother with StringFind.

I am not sure this works.

 
alladir:

You mean better as in elegant, more readable, or more efficient?

I think better as less file operation, so probably more efficient.

Under a certain (small) filesize your version is also OK.

 
alladir:

You mean better as in elegant, more readable, or more efficient?

I normally read from the start and just discard the values until FileIsEnding. Not the most efficient but I've had no problems. How long are your files?


Thanks for sharing. Just wanted to know how actual programmers (unlike myself) would go about it. I'm new.


And, my files are a few megs large -- but I have many of them.

 
szgy74:

I wonder if using delimiter "\n" instead of ";" in FileOpen() would automatically read to the end of the current line. So you don't have to bother with StringFind.

I am not sure this works.




FileReadString() reads to the end of line if the second argument is default and there is no delimiter.
 

Just found out there is a bug in my original function and I couldn't track it down. It sometimes returns things that are not even in the file.

I wanted to try simpler code but it didn't work out as well :( .

shouldn't this work:

string GetLastLine(int Handle){
   string Read;
   FileSeek(Handle,0,SEEK_SET);
   
   while( !FileIsEnding(Handle) )
      Read = FileReadString(Handle); 
   
        
   return(Read);
}
 
BenLinus:

Just found out there is a bug in my original function and I couldn't track it down. It sometimes returns things that are not even in the file.

I wanted to try simpler code but it didn't work out as well :( .

shouldn't this work:


how do you open the file? what is the FileOpen() code?