从stdin读取并填充缓冲区直到EOF

时间:2018-04-13 23:36:48

标签: c file-io io

我需要从stdin读取并填充_SC_PAGESIZE的缓冲区(来自sysconf()),直到stdin处于EOF。这个程序应该是一个wc克隆,所以我希望传递一个类似于常规文件内容的东西。如果缓冲区对于stdin来说不够大,那么我必须继续填充它,处理它用于获取信息,然后清除它并继续从stdin中的文件偏移量再次填充缓冲区。我跟踪stdin的EOF时遇到了问题,而且我得到了一个无限循环。这就是我所拥有的:

int pSize = sysconf(_SC_PAGESIZE);
char *buf = calloc(pSize, sizeof(char));
assert(buf);
if (argc < 2) {
        int fd;
        while (!feof(stdin)) {
                fd = read(0, buf, pSize);
                if (fd == -1)
                        err_sys("Error reading from file\n");
                lseek(0, pSize, SEEK_CUR);
                if (fd == -1)
                        err_sys("Error reading from file\n");
                processBuffer(buf);
                buf = calloc(pSize, sizeof(char));
        }
        close(fd);
}

我假设问题与测试条件有关(而(!feof(stdin)),所以我想我需要的是一个正确的测试条件来退出循环。

2 个答案:

答案 0 :(得分:2)

您可以像

一样编写循环
int n;
do {
    n = read(0, buf, pSize);
    // process it
} while(n > 0);

记住EOF只是一个退出条件,可能在任何其他错误情况发生之前不会发生。真正检查运行循环的有效性是来自read的健康返回代码。另请注意,条件while(n > 0)是否足够取决于您所在的位置。在stdin的情况下,它可能就足够了。但是例如对于套接字,条件可以写成while(n > 0 || errno == EAGAIN)

答案 1 :(得分:1)

为什么您使用的是低级read而不是打开FILE *stream并使用fgets(或POSIX getline)?此外,每次打电话时都会泄漏内存:

            buf = calloc(pSize, sizeof(char));

在你的循环中,因为你覆盖了buf中包含的地址,失去了对前一块内存的引用,导致无法free

相反,分配缓冲区一次,然后不断填充缓冲区,将填充的缓冲区传递给processBuffer。您甚至可以使用三元运算符来确定是打开文件还是只读取stdin,例如

int pSize = sysconf(_SC_PAGESIZE);
char *buf = calloc(pSize, sizeof(char));
assert(buf);

FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) {
    perror ("fopen failed");
    return 1;
}

while (fgets (buf, pSize, fp))
    processBuffer(buf);     /* do not call calloc again -- memory leak */

if (fp != stdin) fclose (fp);   /* close file if not stdin */

注意:,因为fgets将一次读取一行,您可以简单地计算迭代次数以获取行数 - 前提是您的行不是超过_SC_PAGESIZE

如果您想使用精确的pSize块,则可以使用fread代替fgets。唯一的影响是将呼叫次数减少到processBuffer,但这完全取决于您。您唯一需要做的就是将while (...)行更改为:

while (fread (buf, (size_t)pSize, 1, fp) == 1)
    processBuffer(buf);     /* do not call calloc again -- memory leak */

if (ferror(fp))     /* you can test ferror to insure loop exited on EOF */
    perror ("fread ended in error");

注意:read类似,fread无法确保buf中的 nul-terminated 字符串,因此请确保processBuffer不会将buf传递给期望字符串的函数,也不会迭代buf期望在末尾找到 nul-terminatedating 字符。)

仔细看看,如果您有其他问题,请告诉我。