【问题标题】:Print last 10 lines of file or stdin with read write and lseek [closed]使用读写和 lseek 打印文件或标准输入的最后 10 行 [关闭]
【发布时间】:2016-01-18 18:40:17
【问题描述】:

我正在实现tail函数,我应该只使用read()write()lseek()进行I/O,到目前为止我有这个:

int printFileLines(int fileDesc)
{
    char c; 
    int lineCount = 0, charCount = 0;   
    int pos = 0, rState;
    while(pos != -1 && lineCount < 10)
    {
        if((rState = read(fileDesc, &c, 1)) < 0)
        {
            perror("read:");
        }
        else if(rState == 0) break;
        else
        {
            if(pos == -1)
            {
                pos = lseek(fileDesc, 0, SEEK_END);
            }
            pos--;
            pos=lseek(fileDesc, pos, SEEK_SET); 
            if (c == '\n')
            {
                lineCount++;
            }
            charCount++;
        }
    }

    if (lineCount >= 10)
        lseek(fileDesc, 2, SEEK_CUR);
    else
        lseek(fileDesc, 0, SEEK_SET);

    char *lines = malloc(charCount - 1 * sizeof(char));

    read(fileDesc, lines, charCount);
    lines[charCount - 1] = 10;
    write(STDOUT_FILENO, lines, charCount);

    return 0;
}

到目前为止,它适用于超过 10 行的文件,但是当我传递少于 10 行的文件时它会刹车,它只打印该文件的最后一行,我无法使用它stdin。 如果有人可以告诉我如何解决这个问题,那就太好了:D

【问题讨论】:

    标签: c printing lines lseek


    【解决方案1】:

    第一期:

    如果你在这里读到换行符...

    if(read(fileDesc, &c, 1) < 0)
    {
        perror("read:");
    }
    

    ...然后直接将位置设置为preceding那个换行符...

    pos--;
    pos=lseek(fileDesc, pos, SEEK_SET);
    

    然后linecount&gt;= 10(while 循环终止),那么您读取的第一个字符是最后一个换行符之前的行的最后一个字符。换行符本身也不是最后 10 行的一部分,因此只需从当前流位置跳过两个字符:

    if (linecount >= 10)
        lseek(fileDesc, 2, SEEK_CUR);
    

    第二期:

    让我们假设,流偏移已到达流的开头:

    pos--;
    pos=lseek(fileDesc, pos, SEEK_SET); // pos is now 0
    

    while 条件仍然为 TRUE:

    while(pos != -1 && lineCount < 10)
    

    现在读取一个字符。在此之后,文件偏移量为 1(第二个字符):

    if(read(fileDesc, &c, 1) < 0)
    {
        perror("read:");
    }
    

    这里,pos 下降到 -1 并且 lseek 将失败

    pos--;
    pos=lseek(fileDesc, pos, SEEK_SET); 
    

    由于 lseek 失败,文件中的位置现在是 第二个 字符,因此第一个字符丢失。如果 pos == -1 在 while 循环之后,则通过将文件偏移重置为文件开头来解决此问题:

    if (linecount >= 10)
        lseek(fileDesc, 2, SEEK_CUR);
    else
        lseek(fileDesc, 0, SEEK_SET);
    

    性能:

    这需要很多系统调用。一个简单的增强是使用缓冲的 f* 函数:

    FILE *f = fdopen(fileDesc, "r");
    fseek(...);
    fgetc(...);
    

    等等。此外,这不需要系统特定的功能。

    更好的是逐块向后读取文件并对这些块进行操作,但这需要更多的编码工作。

    对于 Unix,您还可以mmap() 整个文件并在内存中向后搜索换行符。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-23
      • 1970-01-01
      • 1970-01-01
      • 2018-02-21
      • 2023-03-28
      • 2012-06-04
      相关资源
      最近更新 更多