- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我知道可以通过发出单个 read
来实现完全缓冲的输入。系统调用可能大于应用程序所需的数据块。但我不明白如何在没有内核支持的情况下将行缓冲应用于输入。我想人们必须读取一个数据块然后寻找换行符,但如果是这样,那么完全缓冲有什么区别?
更具体:
假设我有一个输入流 FILE* in
.以下有什么区别,关于stdio
库将从操作系统中检索字节以填充其缓冲区?
setvbuf(in, NULL, _IOLBF, BUFSIZ)
setvbuf(in, NULL, _IOFBF, BUFSIZ)
最佳答案
一个 FILE
struct 有一个默认的内部缓冲区。后 fopen
,并在 fread
上, fgets
等,缓冲区由来自 read(2)
的 stdio 层填充。称呼。
当您这样做时fgets
,它将数据复制到您的缓冲区,从内部缓冲区中提取数据 [直到找到换行符]。如果没有找到换行符,流内部缓冲区会被另一个 read(2)
补充。称呼。然后,继续扫描换行符并填充缓冲区。
这可以重复多次[尤其是如果你正在做 fread
]。剩下的任何内容都可用于下一个流读取操作(例如 fread
、 fgets
、 fgetc
)。
您可以使用 setlinebuf
设置流缓冲区的大小.为了效率,典型的默认大小是机器页面大小 [IIRC]。
因此,流缓冲区“比你领先一步”,可以这么说。它的操作很像一个环形队列[实际上,如果不是现实的话]。
不知道,但行缓冲 [或任何缓冲模式] 通常用于输出文件(例如,默认设置为 stdout)。它说,如果你看到一个换行符,做一个隐含的 fflush
.全缓冲意味着做 fflush
当缓冲区已满时。无缓冲意味着做 fflush
在每个字符上。
如果你打开一个输出日志文件,你会得到完整的缓冲[最有效],所以如果你的程序崩溃,你可能不会得到最后 N 行的输出(即它们仍然在缓冲区中待处理)。您可以设置行缓冲,以便在程序崩溃后获得最后一行。
在输入时,行缓冲对文件 [AFAICT] 没有任何意义。它只是尝试使用最有效的大小(例如流缓冲区大小)。
我认为重要的一点是,在输入时,您事先不知道换行符在哪里,所以 _IOLBF
像任何其他模式一样运作——因为它必须如此。 (即)您将 read(2) 读到流 buf 大小(或完成未完成的 fread
所需的数量)。换句话说,唯一重要的是内部缓冲区大小和 fread
的大小/计数参数。而不是缓冲模式。
对于 TTY 设备(例如 stdin),流将等待换行符 [除非您在底层 fildes(例如 0)上使用 TIOC* ioctl 来设置一次字符又名原始模式],无论流模式如何。那是因为 TTY 设备规范处理层 [在内核中] 将阻止读取(例如,这就是为什么您可以键入退格等而无需应用程序处理它)。
然而,做fgets
在 TTY 设备/流上将在内部得到特殊处理(例如)它将执行选择/轮询并获取待处理字符的数量并仅读取该数量,因此它不会阻止读取。然后它将寻找换行符,如果没有找到换行符,则重新发出选择/轮询。但是,如果找到换行符,它将从 fgets
返回.换句话说,它会做任何必要的事情来允许标准输入上的预期行为。如果用户输入 10 个字符 + 换行符,它不会阻止读取 4096 字节。
更新:
回答您的第二轮跟进问题
I see the tty subsystem and the stdio code running in the process as completely independent. The only way they interface is by the process issuing read syscalls; these may block or not, and this is what depends on the tty settings.
But the process is completely unaware of those settings and can't change them.
If we're on the same page, what you're saying implies that a setvbuf call will change the buffering policy of the tty device, and I find that hard to reconcile with my understanding of Unix I/O.
setvbuf
只设置流缓冲区大小和策略。它与内核完全无关。内核只看到
read(2)
并且不知道应用程序是原始的还是流通过
fread
来的[或
fgets
]。它不会以任何方式影响 TTY 层。
fgetc
上循环的普通应用程序中用户输入
abcdef\n
,
fgetc
将阻塞 [in the driver] 直到输入换行符。这是执行此操作的 TTY 规范处理层。然后,当输入换行符时,
read(2)
由
fgetc
完成将返回值
7
.第一
fgetc
将返回,其余六个将快速发生,从流的内部缓冲区中完成。
However ...
ioctl(fileno(stdin),TIOC*,...)
更改 TTY 层策略.流不会意识到这一点。因此,在这样做时,必须小心。因此,如果一个进程想要,它可以完全控制文件单元后面的 TTY 层,但必须通过
ioctl
手动完成。
ioctl
修改 [甚至禁用] TTY 规范处理 [又名“TTY 原始模式”] 可以由需要真正的一次字符输入的应用程序使用。例如,
vim
,
emacs
,
getkey
, 等等。
stdio
流 [并有效地这样做],正常用法是在正常模式/用法中使用流
或 完全绕过stdio层,做
ioctl(0,TIOC*,...)
然后做
read(2)
直接地。
getkey
程序:
// getkey -- wait for user input
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#define sysfault(_fmt...) \
do { \
printf(_fmt); \
exit(1); \
} while (0)
int
main(int argc,char **argv)
{
int fd;
int remain;
int err;
int oflag;
int stdflg;
char *cp;
struct termios tiold;
struct termios tinew;
int len;
int flag;
char buf[1];
int code;
--argc;
++argv;
stdflg = 0;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 's':
stdflg = 1;
break;
}
}
printf("using %s\n",stdflg ? "fgetc" : "read");
fd = fileno(stdin);
oflag = fcntl(fd,F_GETFL);
fcntl(fd,F_SETFL,oflag | O_NONBLOCK);
err = tcgetattr(fd,&tiold);
if (err < 0)
sysfault("getkey: tcgetattr failure -- %s\n",strerror(errno));
tinew = tiold;
#if 1
tinew.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP |
INLCR | IGNCR | ICRNL | IXON);
tinew.c_oflag &= ~OPOST;
tinew.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tinew.c_cflag &= ~(CSIZE | PARENB);
tinew.c_cflag |= CS8;
#else
cfmakeraw(&tinew);
#endif
#if 0
tinew.c_cc[VMIN] = 0;
tinew.c_cc[VTIME] = 0;
#endif
err = tcsetattr(fd,TCSAFLUSH,&tinew);
if (err < 0)
sysfault("getkey: tcsetattr failure -- %s\n",strerror(errno));
for (remain = 9; remain > 0; --remain) {
printf("\rHit any key within %d seconds to abort ...",remain);
fflush(stdout);
sleep(1);
if (stdflg) {
len = fgetc(stdin);
if (len != EOF)
break;
}
else {
len = read(fd,buf,sizeof(buf));
if (len > 0)
break;
}
}
tcsetattr(fd,TCSAFLUSH,&tiold);
fcntl(fd,F_SETFL,oflag);
code = (remain > 0);
printf("\n");
printf("%s (%d remaining) ...\n",code ? "abort" : "normal",remain);
return code;
}
关于unix - C stdio 输入流如何实现行缓冲?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34806490/
我正在使用 MediaPlayer 在我的应用程序中播放在线 mp3 文件中的一些声音。 但是,即使在播放完成后,我也会在控制台中收到一行又一行的回调和缓冲。 10-24 08:08:48.467
我有一个简单的多边形。 dfr p = st_polygon(list(as.matrix(dfr))) > pbuf = st_buffer(p, .4) > plot(pbuf) > plot(
这可能又是一些愚蠢的问题,也许这确实是我所缺少的东西,但我很难让 glMultiDrawArrays 在 OpenGL4 中工作。 我发现了很多这样的解释: for (int i = 0; i #i
这仅仅是根据网络速度调整预缓冲内容量的问题吗?你是否在一开始就为此调整一次,每秒......? 或者它更复杂 - 对您的网络速度记录历史进行采样并取平均值/中值并对其进行调整? 最佳答案 您的第二段总
嗨,我正在使用 FFmpeg Autogen C#。当我使用 mkv 输出作为文件并使用 h264 rtsp 流作为输入时,一切正常。编解码器是 libx264 ffmpeg.avio_open(
我需要多次遍历几个文本文件的行。目前这是通过多个 with open("file.txt") as f: for line in f: # do something 虽然性能还
昨天给同学们写了一个xinetd小练习:做一个反向回显程序。 为了学习新东西,我尝试实现一个 Haskell 解决方案。琐碎的main = forever $ interact reverse不起作用
我正在阅读《实时渲染第三版》中的遮挡剔除部分,但我无法理解它是如何工作的。一些问题: “Z 金字塔”有何贡献?为什么我们需要多种分辨率的 Z 缓冲区?在书中,它的显示如下(左侧): 八叉树结构与用于一
我通过串行端口与设备通信。 我已成功获取 InputStream 并读取设备发送的内容。 但问题是,我根本不知道何时停止阅读并继续执行另一项任务。 这是简化的代码: inputStream = ser
我有以下代码: func (q *Queue) GetStreams(qi *QueueInfo) { channel := make(chan error, len(qi.AudioChun
在我调用 -play 之前,有没有办法让 MPMusicPlayerController 缓冲内容?还是在您设置队列时默认执行此操作? AVAudioPlayer 有 -prepareToPlay 方
我正在编写一个数据库 备份函数,从System.Diagnostics.Process 对象 读取StandardOutput (StreamReader) 属性。我已成功写入普通文件。 //This
我有一个 wpf 应用程序,其中所有 viewModel 都继承自实现 INotifyPropertyChanged 的类 NotifyPropertyChangeClass(见下文)。 我想限制
我需要类似于 withLatestFrom 的东西,对应于下图: ---------A-----------------B-- -1-2-3------4------5-6-7-8---- -----
有没有办法缓冲 OutputStream,在返回之前修改它?这是我的代码片段: public ServletOutputStream getOutputStream() throws IOExcept
目前我们有实现服务器通信协议(protocol)缓冲的需求。如果有人对此有任何意见,他们可以向我提供任何意见吗。 最佳答案 请查看以下 Protocol Buffer 链接。 http://code.
所以我目前正在开发一个 Java 应用程序,该应用程序应该将特定事件记录到数据库中。我希望每分钟最多有 15 到 20 次插入,基本上我想知道我是否应该为每个插入语句建立一个新连接,或者只要应用程序正
请考虑以下代码,包括两个线程 buffering_thread(用一条消息填充缓冲区指针)和 sending_thread(清空缓冲区): #include "msg.cpp" msg * buffe
是否可以在线播放由两个或多个视频文件组成的视频? 由于我原来的帖子不够清楚,这里有扩展的解释和问题。 我的站点托管在 Linux/Apache/PHP 服务器上。我有 FLV/F4V 格式的视频文件。
这是我用于缓冲和转换传入事件的代码: public Publisher> logs(String eventId) { ConnectableObservable connectableObs
我是一名优秀的程序员,十分优秀!