Thread: Best way to read lines out of a text file

  1. #1
    Linux is where it's at movl0x1's Avatar
    Join Date
    May 2007
    Posts
    72

    Best way to read lines out of a text file

    Hi. If i've got a text file like:

    --------------
    filename1\n
    filename2\n
    filename3\n
    --------------

    and want to read a line at a time out of that file into say a buffer

    is this the an ok way to do that? or is there a better way?

    Code:
    char buffer[100];
    FILE *fp;
    int c;
    
              do {
                     c = fscanf(fp, "%s", filename);
                     dosomething_withfilename();
              } while (c != EOF);

    Oh, and am I right in assuming that fscanf appends NULL to the ends of the lines it
    reads into the buffer?
    thanks

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    fscanf() definitely won't do what you want. You want to use fgets(), but that is limited to a specifically sized buffer. That might be okay for your purposes. If you want to be able to handle arbitrarily long lines, it gets more complicated.

  3. #3
    Linux is where it's at movl0x1's Avatar
    Join Date
    May 2007
    Posts
    72
    But wouldn't the above code read those three lines into filename[] one
    at a time in the loop?


    I was thinking that each time fscanf was called it would read up to the \n,
    and then append a null creating a string in memory.

    thanks

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by movl0x1 View Post
    But wouldn't the above code read those three lines into filename[] one
    at a time in the loop?

    thanks
    No, because fscanf() doesn't do that. "%s" means "read a string of non-whitespace characters." It does NOT mean "read an entire line." So if the line of input has a space in it (which it probably does), you will only get the data up to that space.

  5. #5
    Linux is where it's at movl0x1's Avatar
    Join Date
    May 2007
    Posts
    72
    But if it was a file that my program created, and was
    guaranteed to have lines without space in them it would work.


    Guess I should've types 'man fscanf'. I haven't used fcanf much, up
    till now.

    But I think fgets(), as you suggested, is better to use.

    Thank you for your help
    Last edited by movl0x1; 05-29-2007 at 11:30 AM.

  6. #6
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Look at your loop again closely. Even if fscanf() doesn't read anything, you're still calling your function. It's not until after your function is called that you break out of the loop. That's a bad thing.

    Something like this would probably be better:
    Code:
    char buf[BUFSIZ];
    char *p;
    
    while(fgets(buf, sizeof(buf), fp))
    {
      if((p = strchr(buf, '\n')))    // If there's a newline
        *p = '\0';                   // Get rid of it
      do_something();
    }
    Last edited by itsme86; 05-29-2007 at 11:37 AM.
    If you understand what you're doing, you're not learning anything.

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by movl0x1 View Post
    But if it was a file that my program created, and was
    guaranteed to have lines without space in them it would work.
    But the first time a user tries to use it under conditions that violate those assumptions, everything breaks. The word people use for this is "brittle." Sure, you can build your house on a foundation of glass but once the tiniest little crack develops the whole things comes crashing down.

  8. #8
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    > But if it was a file that my program created, and was
    > guaranteed to have lines without space in them it would work.

    That's something that will almost never be the case. If this is for your file splitting program I think you are making too many assumptions. If you actually tried to enforce this (just so you can use fscanf()!) then your program's output is useless to human readers. And I think split was developed with a wide scope of applications in mind.

    There's lots of ways to read a line that would "work" depending on how detailed your case is. fgets() is a hero in most places. But if you're just spitting out n lines of a file then maybe this is easiest, considering your progress
    Code:
    int c;
    size_t lncount = 1;
    for( ; lncount < nlines; )
    {
       c = fgetc( in );
       if( c != EOF )
       {
          fputc( c, out );
          if( c == '\n' )  lncount++;
       }
    }

  9. #9
    Linux is where it's at movl0x1's Avatar
    Join Date
    May 2007
    Posts
    72
    But citizen, doesn't that loop assume that I know how many lines
    are in the file? What if I'm reading a file and I don't know how
    many lines are in it? Wouldn't I read line by line until I come to EOF?

    Thanks itsme86. That loop using fgets() looks good
    but I think it's an endless loop.

    Oh wait, the fgets() loop will return 0 when there's no more lines. I get it.
    Thanks.

    So I guess fscanf() or scanf() are never good ideas unless you ABSOLUTELY know
    that the line contains no whitespace.
    Last edited by movl0x1; 05-29-2007 at 12:08 PM.
    Remember that all that code you write turns into this:

    0100100100110010010011100100111001001
    0010100100100001001111100010010010010 ....

  10. #10
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Quote Originally Posted by movl0x1 View Post
    But citizen, doesn't that loop assume that I know how many lines
    are in the file? What if I'm reading a file and I don't know how
    many lines are in it? Wouldn't I read line by line until I come to EOF?
    No. Of course, all variables would have to be given proper values, but its no worse than anything else. And if you read EOF, just stop the loop. Here's a more thorough example
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    void readlines( FILE *in, FILE *out, unsigned long lines )
    {
      unsigned long linecount = 0;
      int c = 0;
    
      while( (c = fgetc( in )) != EOF && lines > linecount )
      {
        fputc( c, out );
        if( c == '\n' )
          linecount++;
      }
    }
    
    int main( int argc, char **argv )
    {
      if( argc != 4 )
      {
        printf( "Read a certain number of lines from a file.\n" );
        printf( "Usage: excutable <infile> <outfile> <nlines>\n" );
        printf( "\t<infile>\tFile to read lines from.\n" );
        printf( "\t<outfile>\tFile to store output in.\n" );
        printf( "\t<nlines>\tNumber of lines to read.\n" );
      }
      else
      {
        FILE *in, *out;
    
        in = fopen( argv[1], "r" );
        if( !in )
        {
          perror( argv[1] );
          return 0;
        }
    
        out = fopen( argv[2], "w" );
        if( !out )
        {
          perror( argv[2] );
          fclose( in );
          return 0;
        }
    
        readlines( in, out, strtoul( argv[3], NULL, 10 ) );
        fclose( in );
        fclose( out );
      }
    
      return 0;
    }
    C:\Documents and Settings\Owner\cbproject\sandbox\windows\Debug_Bui ld>sandbox lipsum.txt out.txt 5
    C:\Documents and Settings\Owner\cbproject\sandbox\windows\Debug_Bui ld>more out.txt
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
    Aenean vel nisl ullamcorper lectus fringilla vestibulum.
    Aenean mattis consequat leo.
    Praesent in nibh ut tortor cursus sagittis.
    Fusce varius lacus et lorem.
    Last edited by whiteflags; 05-29-2007 at 03:56 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Inventory records
    By jsbeckton in forum C Programming
    Replies: 23
    Last Post: 06-28-2007, 04:14 AM
  2. Basic text file encoder
    By Abda92 in forum C Programming
    Replies: 15
    Last Post: 05-22-2007, 01:19 PM
  3. C++ std routines
    By siavoshkc in forum C++ Programming
    Replies: 33
    Last Post: 07-28-2006, 12:13 AM
  4. read multiple lines from a file
    By YankeePride13 in forum C Programming
    Replies: 2
    Last Post: 11-10-2005, 10:30 PM
  5. Replies: 5
    Last Post: 02-01-2003, 10:58 AM