【问题标题】:Whats the difference between this lseek, fseek, read, fread?这个 lseek、fseek、read、fread 有什么区别?
【发布时间】:2012-02-11 21:22:25
【问题描述】:

我正在调用这些函数:

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

FILE *fr;
fr = fopen(arg[1], "r");
unsigned blah[5];
fseek(fr, 100, SEEK_CUR);
fread(blah, 1, sizeof(blah), fr);

我运行第一个代码我运行这个命令:

cat TEXTFILE | ./a.out

我运行这个命令的第二个代码:

./a.out TEXTFILE

但是,我得到了不同的结果。虽然第一个搜索正确,所以它读取了正确的文本,而第二个则不是。我想使用第二种格式,那我做错了什么?

【问题讨论】:

  • 如果将 fseek 与 SEEK_SET 一起使用会怎样?
  • 另外,作为检查,'read' 返回多少读,fread 返回多少?
  • 也许你应该解释为什么你试图从一个文本文件中读取 unsigned ints。读取字符效果更好, strtol() 进行转换。不用寻找,使用 fgets()
  • 你的意思是返回多少?
  • 您应该经常检查系统调用是否有错误。如果你这样做了,你就会知道你的 lseek() 失败并将 errno 设置为 ESPIPE(非法搜索)。

标签: c


【解决方案1】:

在第一个示例中添加了open(filename,O_RDONLY); 调用,这对我来说都很好。我怀疑你的问题是因为调用lseek(0, 100, SEEK_CUR);,它要求搜索标准输入。你不能总是寻求标准——如果你有:

 cat file | ./my_program 

那么标准输入是一个先进先出,你不能寻求。如果我在我的系统上执行此操作,则返回 -1 会失败,并返回“非法搜索”错误。这可能是您遇到的问题,您可能没有注意到,因为您没有在示例中检查 seek 调用的返回值。

请注意,如果您有:

 ./my_program < file

那么标准输入是一个文件,你可以寻找。在我的系统上,seek返回100,输出是正确的。


这是一个可以用来说明返回值的程序:

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]); 
}                       

这里有两个处决:

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

(这些是该文件中位置 100 的正确字节)

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

(这些字节是文件的前 5 个字节)


我还注意到标准输入版本是您所说的正常工作的版本。如果您在使用FILE * 版本时遇到问题,我怀疑fopen() 调用失败,因此请确保检查来自fopen() 的返回值。当然,您总是可以这样做:

FILE *fr = stdin;  

以便您从标准输入中读取。但是,由于您不能总是在标准输入中搜索,因此如果您打算搜索,我建议您始终打开文件。

请注意,您不能在所有可以打开文件的设备上搜索(尽管在大多数系统上都不会出现问题),因此您应该始终检查 seek() 的结果以确保它成功了。

【讨论】:

    【解决方案2】:

    我不是 100% 确定差异,但它似乎与管道与标准输出/文件有关。为了说明这一点,我制作了这两个不同的测试程序:

    考试.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;
    }
    

    然后我创建了一些测试数据。

    数据.txt

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

    当我执行cat ./data.txt | ./exam时,输出是

    01234
    

    当我执行./test ./data.txt时,我得到了

    bcdef
    bcdef
    

    仅供参考,即使我们将SEEK_CUR 替换为SEEK_SET,结果也不会改变。

    但是,./exam &lt;./data.txt 会导致

    bcdef
    

    这是合法的。

    我知道这不是一个可以接受的答案,但不知道为什么“0”会显示数据文件的内容,但我希望它能以某种方式有所帮助。

    【讨论】:

    • 我添加了一个解释管道和重定向之间区别的答案:)
    • 你可以 - 可以说应该在这种情况下 - 检查来自 lseek() 的返回状态,这会给你 -1 并将 errno 设置为 ESPIPE。
    • @TimothyJones +1 感谢您的解释! :D ...不知道标准输入是不可搜索的。
    • 不客气。请注意,它并非总是不可搜索 - 只是有时,取决于它的提供方式。一般来说,我认为在标准输入上搜索不是一个好习惯。
    【解决方案3】:

    SEEK_CUR 从当前位置开始。这就是为什么当你在文件的开头时你的第一次搜索起作用的原因。要始终从头开始搜索,您需要使用 SEEK_SET 而不是 SEEK_CUR。

    0   SEEK_SET    The beginning of the file
    1   SEEK_CUR    The current position
    2   SEEK_END    The end of the file
    

    【讨论】:

      猜你喜欢
      • 2012-03-10
      • 2010-10-09
      • 2017-05-13
      • 2011-02-14
      • 1970-01-01
      • 1970-01-01
      • 2016-07-18
      • 1970-01-01
      相关资源
      最近更新 更多