简体   繁体   English

从标准输入读取并填充缓冲区,直到EOF

[英]Read from stdin and fill buffer until EOF

I need to read from stdin and fill a buffer of _SC_PAGESIZE (from sysconf()) until stdin is at EOF. 我需要从stdin读取并填充_SC_PAGESIZE的缓冲区(来自sysconf()),直到stdin处于EOF为止。 This program is supposed to be a wc clone, so I would be expecting something like the contents of a regular file to be passed in. If the buffer isn't big enough for stdin, then I have to keep filling it, process it for information, then clear it and continue to fill the buffer again from the file offset in stdin. 该程序应该是wc克隆,因此我希望传递类似常规文件的内容。如果缓冲区不够大,无法容纳stdin,那么我必须继续填充它,对其进行处理信息,然后清除它并继续从stdin中的文件偏移再次填充缓冲区。 I'm just having a problem with tracking the EOF of stdin, and I'm getting an infinite loop. 我只是在跟踪stdin的EOF时遇到问题,并且遇到了无限循环。 Here's what I have: 这是我所拥有的:

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

I'm assuming the problem has to do with the test condition (while (!feof(stdin)), so I guess what I need is a correct test condition to exit the loop. 我假设问题与测试条件有关(while(!feof(stdin)),所以我想我需要的是正确的测试条件才能退出循环。

You can write the loop like 你可以这样写循环

int n;
do {
    n = read(0, buf, pSize);
    // process it
} while(n > 0);

Remember EOF is just one exit condition that may not occur before any other error condition occurs. 请记住,EOF只是一个退出条件,在任何其他错误条件发生之前可能不会发生。 True check for validity to run the loop is a healthy return code from read . 真正检查运行循环的有效性是read的健康返回代码。 Also, note that condition while(n > 0) is enough or not depends on where you are reading from. 另外,请注意, while(n > 0)是否足够取决于您从何处读取。 In case of stdin it may be enough. 如果是stdin ,可能就足够了。 But for example for sockets the condition can be written like while(n > 0 || errno == EAGAIN) 但是例如对于套接字,条件可以这样写: while(n > 0 || errno == EAGAIN)

Why are you using a low-level read instead of opening a FILE *stream and using fgets (or POSIX getline )? 为什么要使用低级read而不是打开FILE *stream和使用fgets (或POSIX getline )? Further, you leak memory every time you call: 此外,每次调用都会泄漏内存:

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

in your loop because you overwrite the address contained in buf losing the reference to the previous block of memory making it impossible to free . 在循环中,因为您覆盖了buf包含的地址,从而丢失了对前一个内存块的引用,从而无法free它。

Instead, allocate your buffer once, then continually fill the buffer passing the filled buffer to processBuffer . 相反,分配一次缓冲区,然后连续填充缓冲区,将已填充的缓冲区传递给processBuffer You can even use a ternary operator to determine whether to open a file or just read from stdin , eg 您甚至可以使用三元运算符来确定是打开文件还是仅从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 */

( note: since fgets will read a line-at-a-time, you can simply count the number of iterations to obtain your line count -- provided your lines are not longer than _SC_PAGESIZE ) 注意:由于fgets读取一行,因此您只需计数迭代次数即可获得行数-只要您的_SC_PAGESIZE不超过_SC_PAGESIZE

If you want to use exact pSize chunks, then you can use fread instead of fgets . 如果要使用精确的pSize块,则可以使用fread而不是fgets The only effect would be to reduce the number of calls to processBuffer marginally, but it is completely up to you. 唯一的效果是稍微减少对processBuffer的调用processBuffer ,但这完全取决于您。 The only thing that you would need to do is change the while (...) line to: 您唯一需要做的就是将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");

( note: like read , fread does not insure a nul-terminated string in buf , so insure that processBuffer does not pass buf to a function expecting a string, or iterate over buf expecting to find a nul-terminating character at the end.) 注意:read一样, fread不能确保bufnul终止的字符串,因此请确保processBuffer不会将buf传递给需要字符串的函数,或者对buf进行迭代以期望在末尾找到以nul终止的字符。)

Look things over and let me know if you have further questions. 仔细检查一下,如果您还有其他问题,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM