C语言 计算输入缓冲区中的字节数

7fhtutme  于 2023-06-21  发布在  其他
关注(0)|答案(3)|浏览(102)

我正试图写一个从stdin读取的程序,其中一个文件被重定向到stdin。
例如,我的程序名为scan,因此命令行上的调用将是:

./scan < file.txt

我想为它分配一个大的内存块,由char*指向。我不能只把文件名作为输入,因为这是我必须处理的一个要求。我想知道是否有可能计算出输入缓冲区中的字节数,这样我就可以一次性批量读取stdin。
所以就像

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] = '\0';
    return file;
}
koaltpgm

koaltpgm1#

如果输入是从文件重定向的,那么在Linux中可以通过阅读/proc/self/fd/0/dev/fd/0get the name of that file

char filename[BUFSIZE];
int sz = readlink("/proc/self/fd/0", filename, BUFSIZE - 1);
filename[sz] = 0;
puts(filename);

在AIX上,可以改为读取/proc/<PID>/fd/0
在Windows上,您需要像这样使用GetFinalPathNameByHandle()

GetFinalPathNameByHandle(GetStdHandle(STD_OUTPUT_HANDLE), chPath, MAX_PATH, 0)

在BSD macOS上,您将使用fcntl with F_GETPATH

#include <fcntl.h>

char filename[BUFSIZE];
fcntl(0, F_GETPATH, filename);
puts(filename);

在其他平台可能做不到
如果stdin是一个管道,那么显然您无法知道其大小,因为操作系统在将数据传递给消费进程之前不会等待写入进程将其所有数据泵入管道

mgdq6dx1

mgdq6dx12#

我想知道是否有可能计算出输入缓冲区中的字节数,这样我就可以一次性批量读取stdin。
如果你可以确定输入缓冲区中的字节数,那么它将创建一个不可避免的竞争条件-新的字节/字符可以添加到输入缓冲区后,你已经确定有多少字节,但在你使用该值的任何东西。
不可避免的争用条件的结果是“不,实际上不可能确保您可以一次完成stdin的批量读取”。
一种选择是增加(两倍)。)每当“fread()”说它填满了先前分配的存储器并且重试(例如,使用循环和realloc()),直到fread()无法填充分配的内存。然而,fread()是阻塞的(如果你请求1024字节,而只有10个字节,它将等待其他1014字节到达),所以你必须通过将stdin更改为非阻塞来解决这个问题。这是一个特定的平台(例如:像flags = fcntl(0, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(0, F_SETFL, val);这样的东西可能在Linux上工作,但在Windows上不工作),所以你最终会得到一个很大的复杂的混乱。

qzwqbdag

qzwqbdag3#

size_t amt = num_of_bytes_in_stdin(); //how do this?

你也许可以用setvbuf来搞砸,但是你不能。可能未缓冲标准输入。流可能包含多个已满缓冲区。其他人可能已经改变了它的缓冲方式。在您的检查、分配和阅读之间可能添加了更多内容。
I/O的基本特性是你无法知道你将得到什么或多少。
相反,分配一个大的缓冲区进行读取,可能是BUFSIZ。重用缓冲区从流中读取。然后将其复制到大小更合适的内存中。

相关问题