- 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/
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!