系统调用read和write的疑问

问题背景:

现在我有一个中文文档,里面是一些中文的句子,然后我有一个char buffer[1]的缓冲区,我通过read中文文档,然后把数据写入到标准输出中,此时终端却正常打印,而不是显示乱码。

代码展示:

#include "unistd.h"
#include 
#include "stdio.h"
#include "stdlib.h"
int main()
{
    // 打开
    int fd = open("test.txt",O_RDONLY);
    if(fd<0)
    {
        perror("open");
    }

    char buffer[1]={0};
    ssize_t bytes_read;
    while((bytes_read=read(fd,buffer,sizeof(buffer)))>0)
    {
        write(STDOUT_FILENO,buffer,sizeof(buffer));
    }
    if(bytes_read==-1)
    {
        perror("read");
        close(fd);
        exit(EXIT_FAILURE);
    }
    close(fd);
    return 0;
}

个人疑惑

系统调用是没有缓冲区的,当我们通过read读取的时候,由于buf的限制,我们每次只能读取一个字节,而对于中文来说,大部分的中文都不是一个字节组成的,因此我们每次应该只读取一个中文的一个字节就直接显示在终端上了,这样的显示不应该是乱码吗,但是实际上终端输出的结果却是正常的中文。

问题截图

系统调用read和write的疑问_第1张图片

具体解释

read/write处理的是原始字节流,而终端显示时进行的字符解码是两个独立阶段。也就是说,我们read和write的过程确实是如同我们刚刚分析的一样,但是并不是我们一旦写入到标准输出之后,终端上就立刻对数据进行解码然后显示的。

系统调用层面
read系统调用从文件获取的是原始字节序列
write系统调用输出的也是原始字节序列
内核不进行任何编码转换,只保证字节传输的完整性

终端处理机制
输入缓冲:终端维护接收缓冲区(默认行缓冲模式)
编码检测:根据LANG环境变量确定解码方式(如zh_CN.UTF-8)
多字节组合:

示例:显示"中"字需要3个字节
字节1: 0xE4 → 进入缓冲区(等待后续字节)
字节2: 0xB8 → 继续等待
字节3: 0xAD → 组合为完整UTF-8字符 → 调用字体渲染引擎

时序保证
即使逐字节读写,只要字节到达终端的顺序正确,终端就能正确重组
内核保证系统调用的执行顺序与程序调用顺序一致

产生乱码的情况

  1. 场景1:中间插入异常字节
    原始流:[0xE4][0x00][0xB8][0xAD] → 解码失败显示�符号

  2. 场景2:终端错误编码配置
    export LANG=C # 强制使用单字节编码
    → 每个字节独立解码为ASCII字符,显示"中"

  3. 场景3:非连续写入
    lseek(fd, 1, SEEK_CUR); # 跳过第二个字节
    → 输出[0xE4][0xAD] → 非法UTF-8序列

现代终端的智能处理

最新终端(如iTerm2、Windows Terminal)包含以下保护机制:

编码自愈:短暂接收非法字节会等待后续数据
错误替换:持续无法解码时才显示替换符号(�)
编码探测:自动检测非默认编码的字节流

也就是说,对于终端来说,不论系统当前是什么编码,他都会尽全力去解析,一旦符合某种编码,他就能正确解析。

你可能感兴趣的:(疑问篇,linux)