Whats the difference between this lseek, fseek, read, fread?

后端 未结 3 1156
无人共我
无人共我 2021-02-10 09:17

I am calling these functions:

unsigned blah[5];
lseek(0, 100, SEEK_CUR);
read(0, blah, sizeof(blah));

and

FILE *fr;
fr = fopen(         


        
相关标签:
3条回答
  • 2021-02-10 10:11

    SEEK_CUR starts from the current position. That is why your first seek works when you are at the beginning of the file. To always seek from the beginning you need to use SEEK_SET instead of SEEK_CUR.

    0   SEEK_SET    The beginning of the file
    1   SEEK_CUR    The current position
    2   SEEK_END    The end of the file
    
    0 讨论(0)
  • 2021-02-10 10:16

    With the addition of an open(filename,O_RDONLY); call to the first example, both worked fine for me. I suspect your problem is because of the call lseek(0, 100, SEEK_CUR);, which is asking for a seek on standard input. You cannot always seek on standard in - if you have:

     cat file | ./my_program 
    

    Then standard input is a fifo, and you can't seek. If I do this on my system, seek fails by returning -1, with an error of "Illegal seek". This may be the problem you're having, and you might not notice since you don't check the return value of the seek call in your example.

    Note that if you have:

     ./my_program < file
    

    Then standard input is a file, and you may seek. On my system, seek returns 100, and the output is correct.


    Here is a program you can use to illustrate the return values:

    int main(void){ 
    
      int fd = 0;
      char blah[5];
      printf("Seek moved to this position: %d\n",lseek(fd, 100, SEEK_CUR));
      perror("Seek said");
      printf("Then read read %d bytes\n",read(fd, blah, sizeof(blah)));
      printf("The bytes read were '%c%c%c%c%c'\n",blah[0],blah[1],blah[2],blah[3],blah[4]); 
    }                       
    

    And here are two executions:

     $ ./a.out < text
     Seek moved to this position: 100
     Seek said: Success
     Then read read 5 bytes
     The bytes read were '+++.-'
    

    (Those are the correct bytes from position 100 in that file)

    $ cat text | ./a.out 
    Seek moved to this position: -1
    Seek said: Illegal seek
    Then read read 5 bytes
    The bytes read were '# def'
    

    (Those bytes are the first 5 bytes of the file)


    I also noticed that the standard input version was the one you said was working correctly. If you're having trouble with the FILE * version, I suspect the fopen() call is failing, so make sure you check the return value from fopen(). Of course, you can always do this:

    FILE *fr = stdin;  
    

    So that you're reading from standard in. However, as you can't always seek on standard in, I'd recommend always opening a file if you plan to seek.

    Note that you can't seek on all devices that you can open files on (though you won't have a problem on most systems), so you should always check that the result of a seek() to make sure it succeeded.

    0 讨论(0)
  • 2021-02-10 10:21

    I'm not a 100% sure about the difference, but it seems to be related to pipe vs stdio/file. To illustrate this, I made these 2 different test programs:

    exam.c

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
            char blah[5] = {0,};
    
            /* we're using stdin instead of pipeline  :( */
            lseek(0, 100, SEEK_CUR);
            read(0, blah, sizeof(blah));
    
            printf("%c%c%c%c%c\n", blah[0], blah[1], blah[2], blah[3], blah[4]);
    
            return 0;
    }
    

    test.c

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    
    void testA(const char *s)
    {
            int f = -1;
            char blah[5] = {0,};
    
            f = open(s, O_RDONLY);
    
            if (-1 < f)
            {
                    lseek(f, 100, SEEK_CUR);
                    read(f, blah, sizeof(blah));
            }
    
            printf("%c%c%c%c%c\n", blah[0], blah[1], blah[2], blah[3], blah[4]);
    }
    
    void testB(const char *s)
    {
            FILE *fp = NULL;
            char blah[5] = {0,};
    
            fp = fopen(s, "r");
    
            if (fp)
            {
                    fseek(fp, 100, SEEK_CUR);
                    fread(blah, 1, sizeof(blah), fp);
            }
    
            printf("%c%c%c%c%c\n", blah[0], blah[1], blah[2], blah[3], blah[4]);
    }
    
    int main(int argc, char **argv)
    {
            testA(argv[1]);
            testB(argv[1]);
    
            return 0;
    }
    

    Then I created some test data.

    data.txt

    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    

    When I executed cat ./data.txt | ./exam, the output is

    01234
    

    When I executed ./test ./data.txt, I got

    bcdef
    bcdef
    

    Just FYI, the results remain unchanged even if we replace SEEK_CUR with SEEK_SET.

    However, ./exam <./data.txt results in

    bcdef
    

    which is legitimate.

    I know this is not an acceptable answer without knowing why '0' brings up the data file's contents, but I hope it helps somehow.

    0 讨论(0)
提交回复
热议问题