Like Tree3Likes

Reading textfile

This is a discussion on Reading textfile within the C Programming forums, part of the General Programming Boards category; Ugh, I still blundered: your file was opened correctly. What's inside?...

  1. #16
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    22,159
    Ugh, I still blundered: your file was opened correctly. What's inside?
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  2. #17
    C Beginner
    Join Date
    Dec 2011
    Location
    Portugal
    Posts
    187
    What does (!fp) mean ?
    It means the file wasn't opened with sucess or does it mean it was opened with sucess ?

  3. #18
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    22,159
    fopen returns a null pointer if the file failed to be opened. !fp evaluates to 1 if fp is a null pointer, hence if !fp evaluates to 1, the file failed to be opened.

    Perhaps it would be easier to understand if written in this way:
    Code:
    fp = fopen("/Users/machd/Desktop/SistemasOperativos2013/GuardaLinhas/merdas.txt", "r");
    if (fp) {
        /* read from the file */
    } else {
        /* report the problem in opening the file */
    }
    As such, if you want to write it in your way, it should be:
    Code:
    fp = fopen("/Users/machd/Desktop/SistemasOperativos2013/GuardaLinhas/merdas.txt", "r");
    if (!fp) {
        /* report the problem in opening the file */
        printf("%s\n", "Failed to open the file.");
    }
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #19
    C Beginner
    Join Date
    Dec 2011
    Location
    Portugal
    Posts
    187
    Quote Originally Posted by laserlight View Post
    fopen returns a null pointer if the file failed to be opened. !fp evaluates to 1 if fp is a null pointer, hence if !fp evaluates to 1, the file failed to be opened.

    Perhaps it would be easier to understand if written in this way:
    Code:
    fp = fopen("/Users/machd/Desktop/SistemasOperativos2013/GuardaLinhas/merdas.txt", "r");
    if (fp) {
        /* read from the file */
    } else {
        /* report the problem in opening the file */
    }
    As such, if you want to write it in your way, it should be:
    Code:
    fp = fopen("/Users/machd/Desktop/SistemasOperativos2013/GuardaLinhas/merdas.txt", "r");
    if (!fp) {
        /* report the problem in opening the file */
        printf("%s\n", "Failed to open the file.");
    }
    Hmm, understood.
    Thanks so much.

    Well, what's inside.

    I got this piece of code to read what's inside the text file :

    Code:
    while(!feof(fp)){
            fgets(buffer,200,fp);
            printf("%s",buffer);
        }
    Got no idea why it ain't working.

    This is what is inside the file :

    Code:
    72	.
    16	./.DS_Store
    8	./a
    8	./lerficheiro.c
    8	./o
    24	./so
    8	./so.c

  5. #20
    Registered User
    Join Date
    Oct 2011
    Posts
    872
    Quote Originally Posted by DeanWinchester View Post
    My code is the following :
    With proper error checking, it should be more like
    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    
    int main(void)
    {
        const char *const filename = "merdas.txt";
        char buffer[500];
        FILE *fp;
        char *line;
    
        fp = fopen(filename, "r");
        if (!fp) {
            fprintf(stderr, "Cannot open '%s': %s.\n", filename, strerror(errno));
            return EXIT_FAILURE;
        }
    
        while (1) {
    
            line = fgets(buffer, sizeof buffer, fp);
            if (!line)
                break;
    
            printf("%s", line);
    
        }
    
        if (ferror(fp) || !feof(fp)) {
            fprintf(stderr, "Error reading '%s'.\n", filename);
            return EXIT_FAILURE;
        }
        if (fclose(fp)) {
            fprintf(stderr, "Error closing '%s'.\n", filename);
            return EXIT_FAILURE;
        }
    
        fprintf(stderr, "File '%s' read successfully.\n", filename);
        return EXIT_SUCCESS;
    }
    fopen() sets errno if it fails (returning NULL), so you can use the above to print the exact reason the open failed.

    The second-to-last if clause checks why the fgets() call failed (returned NULL). ferror() is true if there was a read error. !feof() is true if the read call did not fail because there was no more input. In other words, the condition can be read as (if there was an error, or we didn't consume all input).

    The last if clause closes the stream. It is possible for it to fail in theory, although I haven't seen it in practice. (I do have seen it when writing to a file, when the file happened to be on a remote NFS volume, and the remote server had hardware issues.)

    Compile and run it, and show what it outputs.

  6. #21
    C Beginner
    Join Date
    Dec 2011
    Location
    Portugal
    Posts
    187
    Quote Originally Posted by Nominal Animal View Post
    With proper error checking, it should be more like
    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    
    int main(void)
    {
        const char *const filename = "merdas.txt";
        char buffer[500];
        FILE *fp;
        char *line;
    
        fp = fopen(filename, "r");
        if (!fp) {
            fprintf(stderr, "Cannot open '%s': %s.\n", filename, strerror(errno));
            return EXIT_FAILURE;
        }
    
        while (1) {
    
            line = fgets(buffer, sizeof buffer, fp);
            if (!line)
                break;
    
            printf("%s", line);
    
        }
    
        if (ferror(fp) || !feof(fp)) {
            fprintf(stderr, "Error reading '%s'.\n", filename);
            return EXIT_FAILURE;
        }
        if (fclose(fp)) {
            fprintf(stderr, "Error closing '%s'.\n", filename);
            return EXIT_FAILURE;
        }
    
        fprintf(stderr, "File '%s' read successfully.\n", filename);
        return EXIT_SUCCESS;
    }
    fopen() sets errno if it fails (returning NULL), so you can use the above to print the exact reason the open failed.

    The second-to-last if clause checks why the fgets() call failed (returned NULL). ferror() is true if there was a read error. !feof() is true if the read call did not fail because there was no more input. In other words, the condition can be read as (if there was an error, or we didn't consume all input).

    The last if clause closes the stream. It is possible for it to fail in theory, although I haven't seen it in practice. (I do have seen it when writing to a file, when the file happened to be on a remote NFS volume, and the remote server had hardware issues.)

    Compile and run it, and show what it outputs.
    72 .
    16 ./.DS_Store
    8 ./a
    8 ./lerficheiro.c
    8 ./o
    24 ./so
    8 ./so.c
    File '/Users/machd/Desktop/SistemasOperativos2013/GuardaLinhas/merdas.txt' read successfully.

    Thanks sir, worked just fine.
    I must say I believe I'm the dumbest guy ever as I wasn't calling the function inside main >_>

  7. #22
    C Beginner
    Join Date
    Dec 2011
    Location
    Portugal
    Posts
    187
    Now what I want to do is :

    I want to read line by line.
    After reading the first line,
    I should read until the number is over and when this is done I should add the number to the key field in the struct. Then I should ignore all the spaces and when I found a "." I should start reading it to the field info in the struct.

    Any ideas on how I should start ?

    I'm guessing I should do this by chaining aswell.

  8. #23
    Registered User
    Join Date
    Oct 2011
    Posts
    872
    Quote Originally Posted by DeanWinchester View Post
    I want to read line by line.
    The buffer in the example program contains each line read. You can use the line variable to point at the start of the line.

    Quote Originally Posted by DeanWinchester View Post
    I should read until the number is over and when this is done I should add the number to the key field in the struct. Then I should ignore all the spaces and when I found a "." I should start reading it to the field info in the struct.
    You can use sscanf() to "read" (or convert) the line you've already read. That man page is very detailed, but unfortunately it's a bit confusing to read at first.

    For example, try and see what happens if you rewrite the loop in the example program into
    Code:
        while (1) {
            char value[400];
            int key;
    
            line = fgets(buffer, sizeof buffer, fp);
            if (!line)
                break;
    
            /* Convert the line read into a key, and a value. */
            if (sscanf(line, " %d %399s", &key, value) != 2) {
                /* Remove the newline at the end of the line. */
                line[strcspn(line, "\r\n")] = '\0';
    
                /* Output an error and abort. */
                fprintf(stderr, "'%s': Bad data line, '%s'.\n", filename, line);
                return EXIT_FAILURE;
            }
    
            printf("Key = %d, value = '%s'\n", key, value);
        }
    A couple of important points you should understand:
    • The %d conversion converts an int.
      The function takes a pointer to an int as a parameter, here &key, where the result will be stored.
    • The %s conversion copies a string that does not contain whitespace (spaces, tabs, newlines).
      The function takes a pointer to a char as a parameter, here value (because it is a char array, it gets converted to a pointer to the first char in the array automatically, just as if you had written &(value[0])), where the string will be copied to. There must be enough room to store the token, and an extra end-of-string mark (NUL byte, \0).
    • Since we only have room for 400 characters including the end-of-string mark in value, value can contain at most a 399-character string. We must limit the conversion so we won't overrun the buffer.
      Fortunately this is very simple: we just include the maximum length before the conversion specifier. So, we actually need to use %399s.

    Since tokens end at whitespace, values cannot contain spaces or tabs.

    If you want the value to extend to the end of the line, you can use
    Code:
            if (sscanf(line, " %d %399[^\r\n]", &key, &value) != 2) {
    The %[...] conversion is like the %s conversion, except only characters specified in ... are accepted. You can use ranges; for example 0-9A-Za-z accepts all numbers and letters. If the first character is ^, the meaning is inverted: ^\r\n accepts all characters except CR (\r) or LF (\n).

  9. #24
    Registered User whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    7,752
    Well the number part is easily handled by sscanf like so:

    Code:
    int where;
    
    if (sscanf(linefromfile, "%d .%n", &node->key, &where) == 1)
      // Good.
    Then you can take the information starting from the where character and copy it into the node (denoted by line[where]).

    Of course, how well this works depends on how well you can read the lines of the file. fgets() is not a magical solution, but with a big enough size argument it can cover most common line lengths. How well this works also depends on how well I understood what you said.

  10. #25
    Registered User
    Join Date
    Dec 2004
    Posts
    63
    Well, I think that DeanWinchester at least has learned from this thread that if you ask enough then Nominal Animal will probably write the whole program for you, free of charge. It will probably take a few days to finish and he'll probably get it in bits an pieces, but he'll get there eventually.

  11. #26
    C Beginner
    Join Date
    Dec 2011
    Location
    Portugal
    Posts
    187
    Quote Originally Posted by Nominal Animal View Post
    The buffer in the example program contains each line read. You can use the line variable to point at the start of the line.


    You can use sscanf() to "read" (or convert) the line you've already read. That man page is very detailed, but unfortunately it's a bit confusing to read at first.

    For example, try and see what happens if you rewrite the loop in the example program into
    Code:
        while (1) {
            char value[400];
            int key;
    
            line = fgets(buffer, sizeof buffer, fp);
            if (!line)
                break;
    
            /* Convert the line read into a key, and a value. */
            if (sscanf(line, " %d %399s", &key, value) != 2) {
                /* Remove the newline at the end of the line. */
                line[strcspn(line, "\r\n")] = '\0';
    
                /* Output an error and abort. */
                fprintf(stderr, "'%s': Bad data line, '%s'.\n", filename, line);
                return EXIT_FAILURE;
            }
    
            printf("Key = %d, value = '%s'\n", key, value);
        }
    A couple of important points you should understand:
    • The %d conversion converts an int.
      The function takes a pointer to an int as a parameter, here &key, where the result will be stored.
    • The %s conversion copies a string that does not contain whitespace (spaces, tabs, newlines).
      The function takes a pointer to a char as a parameter, here value (because it is a char array, it gets converted to a pointer to the first char in the array automatically, just as if you had written &(value[0])), where the string will be copied to. There must be enough room to store the token, and an extra end-of-string mark (NUL byte, \0).
    • Since we only have room for 400 characters including the end-of-string mark in value, value can contain at most a 399-character string. We must limit the conversion so we won't overrun the buffer.
      Fortunately this is very simple: we just include the maximum length before the conversion specifier. So, we actually need to use %399s.

    Since tokens end at whitespace, values cannot contain spaces or tabs.

    If you want the value to extend to the end of the line, you can use
    Code:
            if (sscanf(line, " %d %399[^\r\n]", &key, &value) != 2) {
    The %[...] conversion is like the %s conversion, except only characters specified in ... are accepted. You can use ranges; for example 0-9A-Za-z accepts all numbers and letters. If the first character is ^, the meaning is inverted: ^\r\n accepts all characters except CR (\r) or LF (\n).
    Thanks so much.
    You're the best guy ever.
    You're best than my teachers, you explain everything so detailed!

  12. #27
    a_capitalist_story
    Join Date
    Dec 2007
    Posts
    2,652
    It's really amazing, but you have a 1.5 year old thread with the same exact title. One has to wonder if all the spoon-feeding you request here is hindering your ability to progress, or you just aren't getting it at all.. At some point the training wheels have to come off, man.

Page 2 of 2 FirstFirst 12
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Reading from a textfile with unknown length?
    By chickenlittle in forum C++ Programming
    Replies: 4
    Last Post: 09-11-2011, 12:59 AM
  2. Reading textfile into array
    By a.mlw.walker in forum C Programming
    Replies: 9
    Last Post: 08-14-2011, 08:39 PM
  3. Replies: 2
    Last Post: 01-29-2011, 12:58 PM
  4. Replies: 9
    Last Post: 08-09-2008, 11:47 AM
  5. Reading a TextFile into a Linked List
    By cisco_leon in forum C Programming
    Replies: 13
    Last Post: 10-30-2006, 07:11 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21