代码之家  ›  专栏  ›  技术社区  ›  Will

函数:如何逐行读取文件?

  •  8
  • Will  · 技术社区  · 15 年前

    我需要做的是使用unistd.h中的read函数来读取文件 一行接一行。我现在有这个:

    n = read(fd, str, size);
    

    但是,这会读取到文件的末尾,或最大字节数。 有没有办法让它一次读一行,停在一个新行? 这些线都是可变长度的。

    我只允许这两个头文件:

    #include <unistd.h>
    #include <fcntl.h>
    

    练习的重点是逐行读取文件,并且 在读取每一行时将其输出。基本上,模拟fgets() 和fputs()函数。

    7 回复  |  直到 15 年前
        1
  •  7
  •   Jonathan Leffler    15 年前

    您可以将每个字符读入缓冲区并检查换行符( \r\n 对于Windows和 \n 对于Unix系统)。

        2
  •  4
  •   swestrup    15 年前

    您需要创建一个缓冲区,其长度是支持的最长行的两倍,并且需要跟踪缓冲区的状态。

    基本上,每次调用新行时,都会从当前缓冲区位置扫描,寻找行尾标记。如果你找到了,很好,这是你的底线。更新缓冲区指针并返回。

    如果达到maxlength,则返回截断的行并将状态更改为discard。下一次调用时,您需要丢弃行尾,然后进入正常读取状态。

    如果读到的内容已结束,则需要读入另一个maxline字符,如果读到底部,则包装到缓冲区的开头(即,可能需要进行两次读取调用),然后继续扫描。

    以上所有这些都假设您可以设置最大行长度。如果不能,那么就必须使用动态内存,并担心缓冲区malloc失败时会发生什么。此外,您还需要始终检查读取结果,以防在读取缓冲区时碰到文件末尾。

        3
  •  1
  •   Mark B    15 年前

    不幸的是,read函数并不真正适合这种类型的输入。假设这是来自面试/家庭作业/练习的某种人工需求,您可以尝试通过将文件分块读取并将其拆分到换行符上,以某种方式在调用之间保持状态,来模拟基于行的输入。如果仔细记录函数的用法,就可以使用静态位置指示器。

        4
  •  1
  •   R.. GitHub STOP HELPING ICE    15 年前

    如果你需要准确阅读一行(而不是超过)使用 read() ,唯一普遍适用的方法是每次读取1个字节并循环,直到得到换行字节。但是,如果您的文件描述符引用了一个终端,并且它处于默认(规范)模式,read将等待换行并在一行可用时返回小于请求的大小。但是,如果数据到达很快,它可能返回多行,或者如果程序的缓冲区或内部终端缓冲区短于行长度,则返回的行可能少于1行。

    除非您真的需要避免越界(这有时很重要,如果您希望另一个进程/程序继承文件描述符并能够从您中断的地方读取),否则我建议您使用 stdio 函数或您自己的缓冲系统。使用 read 对于基于行或逐字节的IO是非常痛苦的,而且很难纠正。

        5
  •  0
  •   Luca    15 年前

    这是一个很好的问题,但是只允许read函数没有帮助!P

    循环读取调用以获取固定数量的字节,并搜索“\n”字符,然后返回字符串的一部分(直至返回“\n”),并存储其余部分(除“\n”)以前置到下一个字符文件块。

    使用动态内存。

    缓冲区的大小越大,使用的读取调用就越少(这是一个系统调用,因此不便宜,但现在有抢占内核)。

    或者简单地确定一个最大的行长度,并使用fgets,如果你需要快速…

        6
  •  0
  •   DigitalRoss    15 年前

    嗯,它会从终端逐行读取。

    有些选择是:

    • 编写一个函数,该函数在数据用完时使用read,但一次只向调用方返回一行
    • 使用库中的函数来执行以下操作: fgets() .
    • 一次只读取一个字节,这样就不会太过分了。
        7
  •  0
  •   Jonathan Leffler    15 年前

    如果以文本模式打开文件,则在读取文件时,Windows“\r\n”将自动转换为“\n”。

    如果您在unix上,可以使用非标准 gcc'getline()'函数。


    这个 getline() 函数是posix 2008中的标准。