假设我有下面这段代码,我用它来运行一个简单的命令,比如ls
,我们假设输出是100
行长。
当我们在下面的代码中执行cout << buff
时,输出是逐字节、逐位还是逐行流式传输,或者间隔是多少?
假设我们想在流式传输cout<<buff
时打印每个新行的new_line!
字符串结尾。我们怎样才能做到呢?
我认为在while
循环中,我们应该有一些东西应该检查它刚刚将(或即将流)n
流到我们的stringstream output
中,并且它决定在它流到输出之后(或之前)做一些事情。
最初,我将把它放入数据结构中存储,所以我只需要知道如何检查n
,因为我们正在进行缓冲,以及在哪里放置添加new_line!
的函数或我想做的任何事情。
代码如下:
#include <iostream>
#include <stdio.h>
using namespace std;
// imaginary
// stringstream output;
int main() {
FILE *in;
char buff[512];
if(!(in = popen("ls -sail", "r"))){
return 1;
}
while(fgets(buff, sizeof(buff), in)!=NULL){
// output << buff;
// if there is a new line
// output << "new_line!";
cout << buff;
}
pclose(in);
return 0;
}
如果您使用GNU libc,那么您可以使用getline()
而不是fgets
。
否则,使用系统提供的任何工具从FILE*
中读取一行。如果您确实找不到这样的设施(这将是非常令人惊讶的),那么最坏的情况是您总是可以使用这种方法。fgets
也是一个很好的解决方案,如果你考虑到缓冲区大小限制,并在需要时自己做一些更多的缓冲(检查文档,一切都有解释)。
你要记住的是,popen
只是返回一个FILE*
,所以任何可以在标准文件上工作的东西也可以在你的情况下工作。网络上有很多这样的例子。
现在你的问题的"间隔"部分,恐怕它没有什么意义。首先,它取决于外部命令将新数据打印到标准输出的时间间隔。在任何情况下,只要外部命令写入它,就可以在程序中读取它。
管道将缓冲数据,因为它进来(直到它达到一些实现限制,可能不容易找到-但它是"充足的"-在这一点上,管道将"阻塞"当ls
写它,所以ls
将停止),除非你读它更快,在这种情况下,你的线程将阻塞。如果您要输出到屏幕上,那么您的输出可能会限制速率。
这样的管道不是"块"或"行缓冲"的-它只是一个管道-无论在一端放入什么,都会从另一端输出。当然,如果"文件管理"的内部请求4000字节,那么在读取操作完成之前,可能需要在另一端使用4000字节。但最有可能的是,fgets
的内部是健全的,不会要求一次大量的数据。
就像fget
与stdio一样。它将等待,直到EOF(程序已经关闭)或直到缓冲区被填满。
因此,while循环的每次迭代要么获得512字节的数据,要么在程序终止或关闭studio后获得剩余的数据。
你可以用一个像这样的小程序来测试:
#include <thread>
#include <chrono>
#include <iostream>
int main() {
std::cout << "hello" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << " world" << std::endl;
}
你会注意到,尽管休眠时间很长,它仍然会尝试读取512字节,并在stdout关闭时关闭。
要以符合标准的方式管理实际的分块,您可以使用std::fgetc
并构建自己的缓冲区。
你自己的getline可能看起来像这样:
std::string get_line(FILE* f) {
char c;
std::string out;
while(c=std::fgetc(f)!='n' && c!=EOF) {
out+=c;
}
out+='n';
return out;
}
//...
//usage
while(!std::feof(in)) {
cout << get_line(in);
}