Thread: OPen a file and read it from the last line

  1. #1
    Registered User
    Join Date
    Dec 2007
    Posts
    34

    OPen a file and read it from the last line

    Hi All
    I am having a problem here. I have a file which saves the data as follows:

    Thu 01/24/2008 8:59:27.42 - entry, aa_1, SYS_ADMIN
    Thu 01/24/2008 9:01:45.02 - exit, aa_1, SYS_ADMIN
    Thu 01/24/2008 9:02:28.69 - entry, aa_1, SYS_ADMIN
    Thu 01/24/2008 9:02:45.21 - exit, aa_1, SYS_ADMIN

    I want to open this file and read last row(the latest logged line), also i dont want to read the whole line all i am interested in is the word "SYS_ADMIN" in the latest logged row. How can i accomplish this in C Programming?...your help will highly be appreciated. I am pretty novice in C programming so your help will highly be regarded. Thanks in advance!

  2. #2
    Chinese pâté foxman's Avatar
    Join Date
    Jul 2007
    Location
    Canada
    Posts
    404
    There's some functions defined in the stdio.h and string.h header who could help you solve your problem. One way to do so is to:

    1. Open the file (of course..) (fopen)
    2. Position it at the "end of the file - X" (fseek)
    3. Read X characters (fgets)
    4. Find the last occurrence of a space in the string you just read (strrchr). What you are interested about will be at that position + 1.
    5. Eventually, close the file... (fclose)

  3. #3
    Fountain of knowledge.
    Join Date
    May 2006
    Posts
    794
    I have a similar problem in that I wrote a program to process a text file containing variable number of records such as.
    Code:
    Record 1 start.
    ...
    ...
    variable number of lines..
    ......
    .......
    Record 1 end
    
    Record 2 start.
    ...
    ...
    variable number of lines..
    ......
    .......
    Record 2 end
    
    Record 3 start.
    ...
    ...
    variable number of lines..
    ......
    .......
    Record 3 end
    However now I need to read the records in reverse order 3, 2,1 etc....

    Probably would be easier just to write a program to reverse the records I think, and keep the existing program as it is.
    I guess the original poster could do that - read everything into an array and them write out a new file starting from the end of the array??
    It is a bit more complicated in my case as I would have to search back for "Record 3 start", in the example above then write out each line untill i got to 'record 3 end' then search back for 'Record 2 start' and repeat the process.
    Would probably be the easiest method for me overall I think.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Problem is that you won't know at what position the last line is, so it's impossible to seek directly.
    Thus, there are two ways if you don't want to re-write the file, which I can see.
    1. Read the file line-by-line until you find the last line.
    2. Seek to end and read backwards until you find a newline. From that point onwards would be the last line (also take into mind that the last character in the file might be a newline or several newlines).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User
    Join Date
    Dec 2007
    Posts
    34
    How can i read characters (with fgetc) backwords? I open a file, seek it to the end of the file (with fseek(fp,0,SEEK_END)) and then start reading backwords untill i encounter ','.?

    Is there a way to do it?

    Thanks in advance

  6. #6
    Registered User
    Join Date
    Nov 2006
    Location
    japan
    Posts
    126

    an alternative answer maybe

    Code:
     fseek(fp, 0L, 2)
    takes you to the end of file (as you already should know.)
    you can use fgetc in a loop and increment the value of 0L to 1L 2L .... etc. and in every iteration you compare if it is "," . or if you already know the length of "SYS_ADMIN" you just do
    fseek (fp, sizeof("SYS_ADMIN"), 2).

    once you do that you can do as always with fgetc ...

    by the way you should look at The GNU library reference manual. I am sure you will find something better.

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    > fseek (fp, sizeof("SYS_ADMIN"), 2).
    Unfortunately the sizeof "SYS_ADMIN" and the length of "SYS_ADMIN" are different things entirely. The size of the string is equivalent to sizeof (char * ).

    If the format is simple enough I don't see a problem with reading the whole file line-by-line and afterward simply searching the last line for the appropriate content. It's certainly no slower than the proposed alternatives. Once you find the word in the area you're interested in you can copy it or do whatever you wanted with it.

    It does have the benefit of solving the problem without resorting to "reading backwards," which may mess up future processing.
    Last edited by whiteflags; 01-25-2008 at 02:29 PM.

  8. #8
    Registered User
    Join Date
    Dec 2007
    Posts
    34
    Quote Originally Posted by nacho4d View Post
    Code:
     fseek(fp, 0L, 2)
    takes you to the end of file (as you already should know.)
    you can use fgetc in a loop and increment the value of 0L to 1L 2L .... etc. and in every iteration you compare if it is "," . or if you already know the length of "SYS_ADMIN" you just do
    fseek (fp, sizeof("SYS_ADMIN"), 2).

    once you do that you can do as always with fgetc ...

    by the way you should look at The GNU library reference manual. I am sure you will find something better.
    Thanks for your answer, few comments on it, i increment it by 0L,1L,2L etc, i am already at the end of the file, by incrementing this, i will be going in forward direction not the backward direction, Is it right? Also fgetc will give me an integer back, will i have to compare it's value to the ascii value of ','(comma) or i can simply use comma in the compare string?

    Thanks

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > The size of the string is equivalent to sizeof (char * ).
    Are you sure?

    Seek to the end of the file, minus say 100 bytes.
    Call fgets() until end of file is reached.
    The last result from fgets() will be the last line of the file.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Chinese pâté foxman's Avatar
    Join Date
    Jul 2007
    Location
    Canada
    Posts
    404
    Here's a bit of code of what i had in head

    Code:
    #include <stdio.h>
    #include <string.h>
    #define LARGE_ENOUGH_VALUE 12l   // But not to large either...
    
    int main(void)
    {
        FILE *file;
        char buffer[LARGE_ENOUGH_VALUE];
        char *ptr;
    
        if ((file = fopen("test.txt", "rt")) != NULL)
        {
            if (fseek(file, -LARGE_ENOUGH_VALUE, SEEK_END) != 0)
                printf("Error: fseek returned nonzero value\n");
            else
            {
                if (fgets(buffer, LARGE_ENOUGH_VALUE, file) == NULL)
                    printf("Error: fgets returned NULL\n");
                else
                {
                    if ((ptr = strrchr(buffer, ' ')) == NULL)
                        printf("Error: no space in the line read\n");
                    else
                    {
                        // Here you could think about removing the '\n' if there is one
                        printf("The last word is: &#37;s\n", ptr + 1);
                    }
                }
            }
        }    
    
        return 0;
    }
    Anyway. There's more systematic solution like the one Salem proposed (ie, checking if the line you just read is really the last line of the file, which is something my code isn't doing) but if your log file have a really "standard structure", the solution i gave could also work. But it still would be good to check if the line you read with fgets is really the last line of the file... and since this is not difficult to implement, well, you know what you have to do now.
    Last edited by foxman; 01-25-2008 at 04:13 PM. Reason: Wrote "line" instead of "file"

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by citizen View Post
    > fseek (fp, sizeof("SYS_ADMIN"), 2).
    Unfortunately the sizeof "SYS_ADMIN" and the length of "SYS_ADMIN" are different things entirely. The size of the string is equivalent to sizeof (char * ).
    Visual Studio returns the length, in bytes, of the actual string and not the size of the char* pointer itself.
    Code:
    size_t n = sizeof("This is a test string");
    Returns 22.
    Code:
    size_t n = sizeof(L"This is a test string");
    Returns 44.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Registered User
    Join Date
    Nov 2006
    Location
    japan
    Posts
    126
    Quote Originally Posted by c_geek View Post
    Thanks for your answer, few comments on it, i increment it by 0L,1L,2L etc, i am already at the end of the file, by incrementing this, i will be going in forward direction not the backward direction, Is it right? Also fgetc will give me an integer back, will i have to compare it's value to the ascii value of ','(comma) or i can simply use comma in the compare string?

    Thanks
    in fseek () the second argument is the offset. Wich means the distance between the current position and (in case the 3rd argument is 2)the end of file. or the distance between the current and the start of file (in case the 3rd argument is 1)
    the second argument must be a long that is why I put and "L" (ie : 0L, 1L, 2L)

    in other words. for going backwards from the end of file you should set the 3rd argument 2.
    and increment the 2nd argument everytime you want to compare the character.

    Regarding the integer comparation. well sorry i mistaked, haha. i dont remember very goog but i am sure there is a function to get the character (as a char type). maybe something like fgets() ??

  13. #13
    Registered User
    Join Date
    Nov 2006
    Location
    japan
    Posts
    126

    another idea

    why dont use this?
    Code:
    [Function] 
    char * strrchr (const char *string, int c ) 
    The function strrchr is like strchr, except that it searches backwards from the end 
    of the string string (instead of forwards from the front). 
    For example, 
    strrchr ("hello, world", ’l’) 
    ⇒ "ld"
    in your file you have a lot of lines but I think you can arrange that right? maybe coping a entire line to a string, then you apply the function above
    As I sayd before is a very good idea to take a look to the GNU C manual reference. If you want to master functions and system calls is a good start good luck.

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by nacho4d View Post
    Code:
     fseek(fp, 0L, 2)
    But now seriously, we are supposed to use SEEK_SET, SEEK_END for a reason, instead of pure numbers. It makes the code more readable, so use them!
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    /me points out that random seeks on a text file are undefined to begin with.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Game Pointer Trouble?
    By Drahcir in forum C Programming
    Replies: 8
    Last Post: 02-04-2006, 02:53 AM
  2. Batch file programming
    By year2038bug in forum Tech Board
    Replies: 10
    Last Post: 09-05-2005, 03:30 PM
  3. Replies: 3
    Last Post: 03-04-2005, 02:46 PM
  4. Unknown Memory Leak in Init() Function
    By CodeHacker in forum Windows Programming
    Replies: 3
    Last Post: 07-09-2004, 09:54 AM
  5. simulate Grep command in Unix using C
    By laxmi in forum C Programming
    Replies: 6
    Last Post: 05-10-2002, 04:10 PM