fread 使用二进制文件过早地发出 EOF 信号
fread is signalling EOF prematurely with a binary file
我是 C 的新手。我正在尝试制作我自己的 base64
版本;该程序从 stdin 获取输入并输出其 base64 等效于 stdout。在针对二进制文件测试我的程序时,我注意到来自 stdin 的 fread
-ing 似乎在实际到达 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;
}
如您所见,主循环调用 fread
stdin 上的每次迭代到缓冲区中,然后在最后检查读取的数量是否小于缓冲区的大小。如果是,我们假设有错误(在这种情况下返回 0)或达到 EOF,并退出循环。
我假设检查 read
为 < sizeof(buffer)
是可以的,而不仅仅是 != 0
,基于 fread 联机帮助页中的引述:
On success, fread() and fwrite() return the number of items read or written. This number equals the number of bytes transferred only when size is 1. If an error occurs, or the end of the file is reached, the return value is a short item count (or zero).
这意味着如果未读入满缓冲区,则达到 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 一起使用;谢谢。
你在Windows吗?是的,路径名以 C:
开头,你就是这样。您可能在文件中有一个 Control-Z('\x1A'
或 ''
)字符。它(Windows C 运行 时间,以及您的程序)不会将标准输入视为二进制文件,除非您以某种方式对其进行调整,因此 Control-Z 标记输入的结尾。
一种可能的 'somehow' 调整模式是 _set_fmode()
. However, it is more likely that you need _setmode()
:
_setmode(fileno(stdin), O_BINARY);
我保留判断这是最好的还是唯一的方法。你可以像我一样研究手册。我无法测试 fileno()
— 或者可能是 Microsoft 世界中的 _fileno()
— 是否可用。
我是 C 的新手。我正在尝试制作我自己的 base64
版本;该程序从 stdin 获取输入并输出其 base64 等效于 stdout。在针对二进制文件测试我的程序时,我注意到来自 stdin 的 fread
-ing 似乎在实际到达 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;
}
如您所见,主循环调用 fread
stdin 上的每次迭代到缓冲区中,然后在最后检查读取的数量是否小于缓冲区的大小。如果是,我们假设有错误(在这种情况下返回 0)或达到 EOF,并退出循环。
我假设检查 read
为 < sizeof(buffer)
是可以的,而不仅仅是 != 0
,基于 fread 联机帮助页中的引述:
On success, fread() and fwrite() return the number of items read or written. This number equals the number of bytes transferred only when size is 1. If an error occurs, or the end of the file is reached, the return value is a short item count (or zero).
这意味着如果未读入满缓冲区,则达到 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 一起使用;谢谢。
你在Windows吗?是的,路径名以 C:
开头,你就是这样。您可能在文件中有一个 Control-Z('\x1A'
或 ''
)字符。它(Windows C 运行 时间,以及您的程序)不会将标准输入视为二进制文件,除非您以某种方式对其进行调整,因此 Control-Z 标记输入的结尾。
一种可能的 'somehow' 调整模式是 _set_fmode()
. However, it is more likely that you need _setmode()
:
_setmode(fileno(stdin), O_BINARY);
我保留判断这是最好的还是唯一的方法。你可以像我一样研究手册。我无法测试 fileno()
— 或者可能是 Microsoft 世界中的 _fileno()
— 是否可用。