计算输入缓冲区中的字节数
Figure out number of bytes in input buffer
我正在尝试编写一个从 stdin 读取的程序,其中一个文件被重定向到 stdin。
比如我的程序叫scan,那么命令行的调用就是:
./scan < file.txt
我想为其分配一个大内存块,由char*
指向。我不能只将文件名作为输入,因为这是我必须处理的要求。我想知道是否有可能计算出输入缓冲区中的字节数,以便我可以一次批量读取标准输入。
所以像
char* read_all_stdin()
{
size_t amt = num_of_bytes_in_stdin(); //how do this?
char* file = (char*) malloc(amt+1);
fread(file,1,amt,stdin); //idk if this is allowed either
file[amt] = '[=11=]';
return file;
}
size_t amt = num_of_bytes_in_stdin(); //how do this?
你可能会乱用 setvbuf
, but AFAIK you can't. Stdin might not be buffered. The stream might contain more than one buffer full. Someone else might have changed how it's buffered. More might have been added between your checking, allocating, and reading。
I/O 的基本性质是你无法知道你会得到什么或多少。
相反,分配一个大缓冲区来读取,可能 BUFSIZ
。重用该缓冲区从流中读取。然后从那个复制到更合适大小的内存。
I was wondering if it is possible to figure out the number of bytes sitting in the input buffer, so that I can do a bulk read of stdin all in one go.
如果您可以确定输入缓冲区中的字节数,那么它将创建一个不可避免的竞争条件 - 在您确定输入缓冲区中有多少字节后,可以将新 bytes/characters 添加到输入缓冲区是但在您将该值用于任何事情之前。
不可避免的竞争条件的后果是“不,在实践中,不可能确保您可以一次完成对标准输入的批量读取”。
只要“fread()”说它填满了先前分配的内存并重试(例如使用循环和realloc()
),一种替代方法是增加(加倍?)分配内存的大小,直到fread()
无法填充分配的内存。然而,fread()
是阻塞的(如果你要求 1024 字节并且只有 10 字节它将等待其他 1014 字节到达)所以你必须通过将 stdin
更改为非 -阻塞。遗憾的是,这是特定于平台的(例如 flags = fcntl(0, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(0, F_SETFL, val);
可能适用于 Linux 但不适用于 Windows),所以你最终会遇到一个复杂的大混乱。
如果输入是从文件重定向的,那么在 Linux 中你可以 get the name of that file 通过阅读 /proc/self/fd/0
char filename[bufsize];
int sz = readlink("/proc/self/fd/0", filename, bufsize-1);
filename[sz] = 0;
puts(filename);
其他平台可能不可以
如果 stdin 是管道那么显然你无法知道大小,因为 OS 在将数据传递给消费进程之前不会等待写入进程将其所有数据泵入管道
我正在尝试编写一个从 stdin 读取的程序,其中一个文件被重定向到 stdin。
比如我的程序叫scan,那么命令行的调用就是:
./scan < file.txt
我想为其分配一个大内存块,由char*
指向。我不能只将文件名作为输入,因为这是我必须处理的要求。我想知道是否有可能计算出输入缓冲区中的字节数,以便我可以一次批量读取标准输入。
所以像
char* read_all_stdin()
{
size_t amt = num_of_bytes_in_stdin(); //how do this?
char* file = (char*) malloc(amt+1);
fread(file,1,amt,stdin); //idk if this is allowed either
file[amt] = '[=11=]';
return file;
}
size_t amt = num_of_bytes_in_stdin(); //how do this?
你可能会乱用 setvbuf
, but AFAIK you can't. Stdin might not be buffered. The stream might contain more than one buffer full. Someone else might have changed how it's buffered. More might have been added between your checking, allocating, and reading。
I/O 的基本性质是你无法知道你会得到什么或多少。
相反,分配一个大缓冲区来读取,可能 BUFSIZ
。重用该缓冲区从流中读取。然后从那个复制到更合适大小的内存。
I was wondering if it is possible to figure out the number of bytes sitting in the input buffer, so that I can do a bulk read of stdin all in one go.
如果您可以确定输入缓冲区中的字节数,那么它将创建一个不可避免的竞争条件 - 在您确定输入缓冲区中有多少字节后,可以将新 bytes/characters 添加到输入缓冲区是但在您将该值用于任何事情之前。
不可避免的竞争条件的后果是“不,在实践中,不可能确保您可以一次完成对标准输入的批量读取”。
只要“fread()”说它填满了先前分配的内存并重试(例如使用循环和realloc()
),一种替代方法是增加(加倍?)分配内存的大小,直到fread()
无法填充分配的内存。然而,fread()
是阻塞的(如果你要求 1024 字节并且只有 10 字节它将等待其他 1014 字节到达)所以你必须通过将 stdin
更改为非 -阻塞。遗憾的是,这是特定于平台的(例如 flags = fcntl(0, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(0, F_SETFL, val);
可能适用于 Linux 但不适用于 Windows),所以你最终会遇到一个复杂的大混乱。
如果输入是从文件重定向的,那么在 Linux 中你可以 get the name of that file 通过阅读 /proc/self/fd/0
char filename[bufsize];
int sz = readlink("/proc/self/fd/0", filename, bufsize-1);
filename[sz] = 0;
puts(filename);
其他平台可能不可以
如果 stdin 是管道那么显然你无法知道大小,因为 OS 在将数据传递给消费进程之前不会等待写入进程将其所有数据泵入管道