fread使用二进制文件过早发出EOF信号

时间:2016-09-05 22:22:06

标签: c io fread

我是C的新人。我试图制作我自己的base64版本;程序从stdin获取输入并输出其base64等效于stdout。在针对二进制文件测试我的程序时,我注意到来自stdin的fread似乎在实际到达EOF之前的早期返回了一个简短计数。

以下是我主要方法的相关部分:

int main(void)
{
    unsigned char buffer[BUFFER_SIZE];
    unsigned char base64_buffer[BASE64_BUFFER];

    while (1)
    {
        TRACE_PUTS("Reading in data from stdin...");
        size_t read = fread(buffer, 1, sizeof(buffer), stdin); /* Read the data in using fread(3) */

        /* Process the buffer */

        TRACE_PRINTF("Amount read: %zu\n", read);
        TRACE_PUTS("Beginning base64 encode of buffer");
        size_t encoded = base64_encode(buffer, read, base64_buffer, sizeof(base64_buffer));

        /* Write the data to stdout */
        TRACE_PUTS("Writing data to standard output");
        ...

        if (read < sizeof(buffer))
        {
            break; /* We reached EOF or had an error during the read */
        }
    }

    if (ferror(stdin))
    {
        /* Handle errors */
        fprintf(stderr, "%s\n", "There was a problem reading from the file.");
        exit(1);
    }

    puts(""); /* Output a newline before finishing */

    return 0;
}

如您所见,主循环将stdin上的每次迭代调用fread到缓冲区,然后在最后检查读取的数量是否小于缓冲区的大小。如果是,我们假设有一个错误(在这种情况下返回0)或者达到EOF,并退出循环。

我假设根据来自fread的联机帮助页的引用,可以将read检查为< sizeof(buffer),而不仅仅是!= 0

  

成功时,fread()和fwrite()返回读取或写入的项目数。此数字等于仅在大小为1时传输的字节数。如果发生错误或达到文件末尾,则返回值为短项目计数(或零)。

这意味着如果未读入完整缓冲区,则达到EOF。

有了这个,这是我在针对cat /bin/echo运行我的应用时获得的跟踪:

$ cat /bin/echo | bin/base64 >/dev/null # only view the trace output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 600
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 600
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 600
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 569
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output

$

以下是/bin/echo实际有多大:

$ cat /bin/echo | wc -c
28352

正如您所看到的,整个文件长度为28352字节,但我的应用程序在停止之前只读取了约2400个字节。知道为什么吗? fread是否特意处理空终止符?

如果有帮助,我正在使用MinGW-w64和GCC;感谢。

1 个答案:

答案 0 :(得分:3)

你在Windows上吗?是的,路径名从C:开始,所以你是。您可能在文件中有一个Control-Z('\x1A''\32')字符。它(Windows C运行时,因此你的程序)不会将标准输入视为二进制文件,除非你以某种方式调整它,所以Control-Z标记输入的结束。

一种可能的&#39;某种方式&#39;调整模式是_set_fmode()。但是,您更有可能需要_setmode()

_setmode(fileno(stdin), O_BINARY);

我保留判断这是否是最佳或唯一的方法。您可以尽我所能研究手册。我无法测试微软世界中的fileno() - 或者_fileno()是否可用。