【Linux】基础IO流(上)
创始人
2025-06-01 00:51:24

文章目录

    • 1. 预备知识
    • 2. 回忆C接口
      • fopen
      • fputs
      • fprintf
      • snprintf
      • 追加方式—— a
      • 以读方式—— r
    • 3.操作系统如何进行读写文件操作
      • open
        • 操作系统是如何让用户给自己传递标志位的
          • 理解标记位的问题
        • 新创建文件权限不正确
        • 解决 umask的权限
      • write
      • 默认不会对原始文件清空
      • 系统层面追加
      • 系统层面 读取
      • 总结

1. 预备知识

文件= 内容+属性
对应文件的操作,对内容的操作,对属性的操作
当文件没有被操作的时候,一般在磁盘中
当对文件进行操作的时候,一般在内存中,因为冯诺依曼体系规定
当我们对文件进行操作的时候,文件需要提前加载到内存中,提前加载的是属性
当我们对文件进行操作的时候,文件需要提前加载到内存中,不只有你在load,内存中一定存在大量的不同文件属性

  • 打开文件本质就是将需要的属性加载到内存中,OS内部一定会同时存在大量的被打开的文件,操作系统就会通过先描述,在组织的方式管理这些被打开的文件
  • 先描述,构建在内存中的文件结构体 struct file{ 文件属性,struct
    file*next},表明被打开的文件 每一个被打开的文件,都要在OS内对应 文件对象的struct
    结构体,可以将所有的struct结构体通过某种数据结构链接起来,在OS内部,对被打开的文件进行管理,就会转换为对链表的增删查改

结论:文件被打开,OS要为被打开的文件,创建对应的内核数据结构,struct file结构体 ,该结构体包含各种属性,各种链接关系

2. 回忆C接口

fopen

FILE *fopen(const char *path, const char *mode);
第一个参数为 打开文件对应的路径
第二个参数为 打开文件对应的权限
如果打开成功,返回FILE指针,否则返回NULL


创建myfile.c文件

E>#include    #define LOG "log.txt"    
E>int main()    {    FILE*fp= fopen(LOG,"w");    //默认写方式 打开文件,如果文件不存在,就创建它                                                                                                                                         if(fp==NULL)    {    perror("fopen");//报错    return 1;    }    fclose(fp); //关闭文件    return 0;                                                                                                                                                                           }  

fputs

int fputs(const char *s, FILE *stream);
你想要写的字符串,写入特定的流当中,成功返回字符串字符个数,失败返回-1


#include                                                                                                                                                                         #define LOG "log.txt"    
int main()    {    FILE*fp= fopen(LOG,"w");    //默认写方式 打开文件,如果文件不存在,就创建它    if(fp==NULL)    {    perror("fopen");//报错    return 1;    }        //进行文件操作    const char*msg="bbb\n";      fputs(msg,fp);    fclose(fp); //关闭文件                          return 0;                                     } 

将msg字符串中的数据写入fp流中

fprintf

int fprintf(FILE *stream, const char *format, …);
指定文件流,向文件打印

指定文件流fp,而fp打开的文件为log.txt,所以将msg数据打印到log.txt文件中


因为Linux中一切皆文件,所以也可以传入stdout(标准输出流)中,stdout也对应一个文件,即显示器文件


运行可执行程序,结果显示到显示器了

snprintf

int snprintf(char *str, size_t size, const char *format, …);
通过格式化流的方式,把字符串信息自定义格式化到字符串缓冲区中,并规定大小


将msg中的数据打印到buffer字符串中,同时使用fputs将buffer中的数据写入刚刚打开的文件log.txt中

追加方式—— a

追加,不会清空文件,而是每一次写入都是从文件尾部写入的


修改myfile.c文件内容

#include    
#define LOG "log.txt"    
int main()    
{    FILE*fp= fopen(LOG,"a");    //默认写方式 打开文件,如果文件不存在,就创建它    if(fp==NULL)    
{    perror("fopen");//报错    return 1;    
}    //进行文件操作    
const char*msg="bbb\n";    int cnt=1;    while(cnt)    
{    fputs(msg,fp);    cnt--;    
}    
fclose(fp); //关闭文件    return 0;                                                                                                                                                                           
}    

多次运行可执行程序,发现可追加

以读方式—— r

char *fgets(char *s, int size, FILE *stream);
从特定的文件流中按行所取对应的文件,将读到的内容放到缓冲区中


修改myfile.c文件内容

#include    
#define LOG "log.txt"    
int main()    
{    FILE*fp= fopen(LOG,"r");                                                                                                                                                                  if(fp==NULL)    
{    perror("fopen");//报错    return 1;    
}    //进行文件操作    
while(1)    
{    char line[128];    if(fgets(line,sizeof(line),fp)==NULL)    break;    else    {    printf("%s",line);    }    
}    
fclose(fp); //关闭文件    return 0;    
}  

从fp中读取到line中,如果当前读取返回NULL说明读取失败 ,返回break

此时运行可执行程序,即可看到对应文件中的内容

3.操作系统如何进行读写文件操作

open

#include
#include
#include
int open(const char *pathname, int flags);
第一个参数代表 文件路径+文件名
第二个参数 代表 文件对应的选项(选项的问题后面会提)
如果打开成功了,就会返回新的文件描述符,如果打开失败,返回 -1

操作系统是如何让用户给自己传递标志位的

1. 我们怎么做
通过写一个 函数 若 int XXX (int flag) ,传递参数flag flag=1/2/3 ,将flag进行赋值

2. 系统怎么做
操作系统存在系统调用接口 int YYY (int flag),flag作为一个整数,有32个比特位,可以用一个比特位表示一个标志位
,一个int 就可以同时传递至少32个标记位
此时的flag 就可以看作数据类型 位图 看待

理解标记位的问题

创建test.c文件

#include    
//分别代表从右向左的每个比特位    
#define ONE  0x1    
#define TWO  0x2    
#define THREE 0x4    
#define FOUR 0x8    
void print(int flag)    
{    if(flag & ONE )    printf("hello 1\n");//充当函数的不同行为    if(flag & TWO)    printf("hello 2\n");    if(flag & THREE)    printf("hello 3\n");    if (flag & FOUR)    printf("hello 4\n");    }                                                                    
int main()                                                           
{                                                                    printf("-------------------------------------\n");                 print(ONE);     //打印one                                                    printf("-------------------------------------\n");                 print(ONE|TWO); //打印one two                                      printf("-------------------------------------\n");                 print (ONE|TWO|THREE);//打印 one two three                         printf("-------------------------------------\n");                 print (ONE|TWO|THREE|FOUR);  //打印 one two three four                                    printf("-------------------------------------\n");                 return 0;                                                          
} 

通过整数flag 一次传递多个标志位
0000 0000
将最后的四个比特位通过宏的方式分别记录下来
再与flag 按位与 ,若为真,则说明传递的flag 是 这4个比特位中的其中一个


执行可执行程序,此时分别打印出了 one two three four的运行结果


类比上述 open的第二个参数flag ,存在多个标志位,同通过宏来实现,每一个标志位都代表不同的值

新创建文件权限不正确


  • O_CREAT :文件不存在就打开,不存在就创建一个文件
  • O_WRONLY: 以写方式打开文件

在myfile.c文件中重新输入代码

#include    
#include    
#include    
#include    
#define LOG "log.txt"    
int main()    
{    int fd=open(LOG, O_WRONLY| O_CREAT);//打开一个文件,若文件不存在则重新创建一个if(fd==-1)//说明打开失败{printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息}else                                                                                                                                                                                      printf("fd :%d\n",  fd);                                   close(fd); //关闭文件                                      return 0;                                                  
} 

运行可执行程序,发现


假设log.txt文件不存在,通过创建文件并打开文件,发现新文件的权限不正常


因为在Linux中创建一个文件需要有对应的权限的
int open(const char *pathname, int flags, mode_t mode);
所以在文件不存在时,一般采用有三个参数接口的open
mode代表权限


修改myfile.c文件的内容

  #include    #include    #include    #include    #include    #include#define LOG "log.txt"    int main()    {    int fd=open(LOG, O_WRONLY| O_CREAT,0666);//打开一个文件,若文件不存在则重新创建一个                                                                                                      if(fd==-1)//说明打开失败    {    
E>    printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息    }    else    printf("fd :%d\n",  fd);    close(fd); //关闭文件    return 0;    } 

0666 :拥有者 所属组 other都有读写权限


此时log.txt文件拥有正常的权限
但是输入的是666 ,显示的却是664,即other没有写权限
因为创建一个文件时,默认权限受到umask的影响

解决 umask的权限

使用 man 2 umask 查看
#include
#include
mode_t umask(mode_t mask);
可以影响当前进程启动时,属于自己的umask,采取就近原则,因为自己设置离的更近所以使用自己设置的umask
而不是系统的umask


修改myfile.c文件的内容

  #include    #include    #include    #include    #include    #include    #define LOG "log.txt"    int main()    {    umask (0);//将权限掩码设置成0                                                                                                                                                           int fd=open(LOG, O_WRONLY| O_CREAT,0666);//打开一个文件,若文件不存在则重新创建一个                                if(fd==-1)//说明打开失败                                                                                          {                                                                                                                 printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息                               }                                                                                                                 else                                                                                                              printf("fd :%d\n",  fd);                                                                                          close(fd); //关闭文件                                                                                             return 0;                                                                                                         }  

使用umask (0) 将权限掩码设置成0



此时log.txt文件的权限为 666

write

通过 man 2 write 查看文件写入接口
ssize_t write(int fd, const void *buf, size_t count);
fd代表文件描述符
buf代表 缓冲区
count代表 缓冲区大小
write将缓冲区的count大小的数据写入 fd中
返回值代表实际写入多少字节


修改myfile.c文件内容

include    
#include    
#include    
#include    
#include    
#include    
#include    
#define LOG "log.txt"    
int main()    
{    umask (0);//将权限掩码设置成0    int fd=open(LOG, O_WRONLY| O_CREAT,0666);//打开一个文件,若文件不存在则重新创建一个    if(fd==-1)//说明打开失败    {    printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息    }    else    printf("fd :%d\n",  fd);    const char* msg="hello world";                                                                                                                                                            int cnt=5;    while(cnt)    {    char line[128];    snprintf(line,sizeof(line),"%s,%d\n",msg,cnt);//将msg和cnt写入line缓冲区中    write(fd,line,strlen(line)+1);//将line写入fd中    cnt--;    }    close(fd); //关闭文件    return 0;    
}    

若 strlen(line)+1 ,则打开log.txt文件时发现出现乱码,因为数字0在ASCII表中属于不可显示字符
在这里插入图片描述
所以为了不出现乱码,所以strlen(line) 不应该+1,因为\0是c语言的规定,不是文件的规定


修改myfile.c文件内容

#include    
#include    
#include    
#include    
#include    
#include    
#include    
#define LOG "log.txt"    
int main()    
{    umask (0);//将权限掩码设置成0    int fd=open(LOG, O_WRONLY| O_CREAT,0666);//打开一个文件,若文件不存在则重新创建一个    if(fd==-1)//说明打开失败                                              {                                                                     printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息    }                                                                     else                                                                  printf("fd :%d\n",  fd);                                              const char* msg="hello world";                                        int cnt=5;                                                            while(cnt)                                                            {                                                                     char line[128];                                                     snprintf(line,sizeof(line),"%s,%d\n",msg,cnt);//将msg和cnt写入line缓冲区中    write(fd,line,strlen(line));//将line写入fd中 strlen不要+1                                                                                                                               cnt--;                                                          }                                                                 close(fd); //关闭文件                                             return 0;    
} 

此时strlen不加1

默认不会对原始文件清空

修改myfile.c文件内容,msg和cnt的数据内容

#include    
#include    
#include    
#include    
#include    
#include    
#include    
#define LOG "log.txt"    
int main()    
{    umask (0);//将权限掩码设置成0    int fd=open(LOG, O_WRONLY| O_CREAT,0666);//打开一个文件,若文件不存在则重新创建一个    if(fd==-1)//说明打开失败    {    printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息    }    else    printf("fd :%d\n",  fd);    const char* msg="aaaaa";    int cnt=1;                                                                                                                                                                                while(cnt)                              {                                       char line[128];    snprintf(line,sizeof(line),"%s,%d\n",msg,cnt);//将msg和cnt写入line缓冲区中    write(fd,line,strlen(line));//将line写入fd中 strlen不要+1    cnt--;    }    close(fd); //关闭文件    return 0;    
}  

在这里插入图片描述
O_WRONLY | O_CREAT 默认不会对原始文件清空


O_TRUNC : 将文件做清空


修改myfile.c文件内容

#include    
#include        
#include        
#include        
#include        
#include        
#include        
#define LOG "log.txt"        
int main()        
{        umask (0);//将权限掩码设置成0        int fd=open(LOG, O_WRONLY| O_CREAT| O_TRUNC,0666 );//打开一个文件,若文件不存在则重新创建一个        if(fd==-1)//说明打开失败        {                                                                                                                                                                                         printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息                  }                                                                                                    else                                                                                                 printf("fd :%d\n",  fd);                                                                             const char* msg="aaaaa";                                                                             int cnt=1;                                                                                                                                                                                  while(cnt)                                                                                           {                                                                                                    char line[128];                                                                                    snprintf(line,sizeof(line),"%s,%d\n",msg,cnt);//将msg和cnt写入line缓冲区中                         write(fd,line,strlen(line));//将line写入fd中 strlen不要+1                                          cnt--;                                                                                             }                                                                                                    close(fd); //关闭文件                                                                                return 0;                                                                                            
}

此时再次调用log.txt文件,就会将之前文件中内容清空’

系统层面追加

O_APPEND 追加
O_WRONLY: 以写方式打开文件
O_WRONLY | O_APPEND | O_CREAT 若文件存在就以写的方式追加,若文件不存在则创建


修改myfile.c文件内容

#include    
#include    
#include    
#include    
#include    
#include    
#include    
#define LOG "log.txt"        
int main()    
{    umask (0);//将权限掩码设置成0        int fd=open(LOG,O_WRONLY |  O_CREAT | O_APPEND  ,0666 );//打开一个文件,若文件不存在则重新创建一个                                                                                         if(fd==-1)//说明打开失败                                                                             {                                                                                                    printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息                  }                                                                                                    else                                                                                                 printf("fd :%d\n",  fd);                                                                             const char* msg="bbb";                                                                                                                                                                      int cnt=1;                                                                                                                                                                                  while(cnt)                                                                                           {                                                                                                    char line[128];                                                                                    snprintf(line,sizeof(line),"%s,%d\n",msg,cnt);//将msg和cnt写入line缓冲区中                         write(fd,line,strlen(line));//将line写入fd中 strlen不要+1                                          cnt--;                                                                                             }                                                                                                    close(fd); //关闭文件                                                                                return 0;                                                                                            
} 

此时重复运行可执行程序,打开log.txt文件 ,发现可以追加

系统层面 读取

O_RDONLY : 读取

输入 man 2 read
ssize_t read(int fd, void *buf, size_t count);
从文件描述符fd中将我们想要的数据,按照数据块的方式读取出来
返回值代表多少字节,读取到文件结尾为0,失败为-1

#include    
#include    
#include    
#include    
#include    
#include    
#include    
#define LOG "log.txt"        
int main()    
{    umask (0);//将权限掩码设置成0        int fd=open(LOG, O_RDONLY  );//打开一个文件,若文件不存在则重新创建一个        if(fd==-1)//说明打开失败        {    printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息        }    else    printf("fd :%d\n",  fd);                                                                                                                                                                  char buffer[1024];    ssize_t n= read(fd,buffer,sizeof(buffer)-1);//使用系统接口来进行IO的时候,一定要注意\0的问题    if(n>0)//成功了,实际读到了多少字节    {    buffer[n]='\0';    printf("%s\n",buffer);    }    close(fd); //关闭文件        return 0;    
}

运行可执行程序,可以直接读取到数据

总结

在这里插入图片描述
操作系统不相信任何用户,所以操作系统给用户提供系统调用
程序员调用库的接口,而库的接口必定要调用系统调用
打开文件的本质是文件相关的内容加载到内存里
把数据触发从磁盘到内存
把数据从自己的程序写入硬盘上,一定会涉及到对硬件的访问
用户不能使用c/c++库绕过操作系统去访问
软硬件各种资源属于操作系统的,操作系统是硬件的管理者

相关内容

热门资讯

13寸电脑尺寸是多少厘米,13... 13寸电脑尺寸是多少厘米目录13寸电脑尺寸是多少厘米13英寸等于多少厘米13寸大概有多大?13.3寸...
管理员的英文缩写是什么,管理员... 管理员的英文缩写是什么目录管理员的英文缩写是什么管理员英文怎么写admn具体指的是什么?管理员的英文...
为什么喊张艺兴孙艺兴,张艺兴为... 为什么喊张艺兴孙艺兴目录为什么喊张艺兴孙艺兴张艺兴为什么叫孙兴?,孙艺兴和张艺兴是同一个人吗为什么喊...
肉沫土豆泥的做法,土豆泥怎么做... 肉沫土豆泥的做法目录肉沫土豆泥的做法土豆泥怎么做?土豆泥怎么做好吃,肉末土豆泥的家常做法土豆打成泥怎...
洛阳市区有哪些大学,洛阳有几所... 洛阳市区有哪些大学目录洛阳市区有哪些大学洛阳有几所大学求洛阳各大高校地址洛阳的大学有哪些洛阳市区有哪...
霎时间的近义词是什么,“ 霎时... 霎时间的近义词是什么目录霎时间的近义词是什么“ 霎时间 ”的近义词与“霎时间”意思相近的词有什么?霎...
如何画机器猫的简笔画,机器猫的... 如何画机器猫的简笔画目录如何画机器猫的简笔画机器猫的简笔画是怎样的?如何画哆啦a梦叮当的图案-如何画...
磁卡没有磁了小妙招,交通卡没有... 磁卡没有磁了小妙招目录磁卡没有磁了小妙招交通卡没有磁性怎么办磁卡消磁了怎样让其恢复?磁卡没有磁了怎么...
华为畅享6s是什么处理器,华为... 华为畅享6s是什么处理器目录华为畅享6s是什么处理器华为畅享6s:参数详解华为畅享6S外观及性能评测...
京东方普工干什么活,北京京东方... 京东方普工干什么活目录京东方普工干什么活北京京东方茶谷累不累合肥京东方一线员工做什么京东方普工,特工...
燕城是哪个城市,我的人间烟火燕... 燕城是哪个城市目录燕城是哪个城市我的人间烟火燕城是哪个城市?秦国燕城是现在的哪里燕城是哪个城市燕城是...
什么是黑洞谢谢告诉我,黑洞的基... 什么是黑洞谢谢告诉我目录什么是黑洞谢谢告诉我黑洞的基本性质?黑洞是什么?什么是黑洞什么是黑洞谢谢告诉...
光疗美甲怎么卸除,光疗甲怎么卸... 光疗美甲怎么卸除目录光疗美甲怎么卸除光疗甲怎么卸光疗甲要怎么卸下来?光疗甲怎么卸掉光疗美甲怎么卸除 ...
巧克力是怎么做成的,巧克力是用... 巧克力是怎么做成的目录巧克力是怎么做成的巧克力是用什么做成的 巧克力是用啥做的巧克力是什么做的巧克力...
感慨生活不易但励志的句子,关于... 感慨生活不易但励志的句子目录生活很苦的励志说说 励志开心的说说关于在艰难的路上的励志句子生活不易下一...
等腰三角形三线合一怎么证明,如... 等腰三角形三线合一怎么证明目录等腰三角形三线合一怎么证明如果只告诉三角形是等腰三角形,那么直接能证明...
番禺有哪些公园好玩的,广州市番... 番禺有哪些公园好玩的目录番禺有哪些公园好玩的广州市番禺区有哪些公园广州番禺有哪些公园好玩番禺旅游必去...
研究生读几年研究生的介绍,研究... 研究生读几年研究生的介绍目录研究生读几年研究生的介绍研究生读几年学制研究生是啥啊?国内研究生读几年研...
擦什么可以让纹身变淡,抹点什么... 擦什么可以让纹身变淡目录擦什么可以让纹身变淡抹点什么可以淡化纹身什么可以淡纹身不花钱去掉纹身的小窍门...
61键电子琴各个琴键代表什么,... 61键电子琴各个琴键代表什么目录61键电子琴各个琴键代表什么如何认识61键电子琴电子琴上的按钮分别是...
汽车钣金是什么意思(汽车钣金是... 今天给各位分享汽车钣金是什么意思的知识,其中也会对汽车钣金是什么意思的照片进行解释,如果能碰巧解决你...
40尺的高柜集装箱尺寸是多少(... 本篇文章极速百科给大家谈谈40尺的高柜集装箱尺寸是多少,以及40尺的高柜集装箱尺寸是多少寸对应的知识...
斗罗大陆唐三的魂环分别是什么,... 斗罗大陆唐三的魂环分别是什么目录斗罗大陆唐三的魂环分别是什么唐家三少的《斗罗大陆》一书中,主角唐三的...
浅色硅胶手机壳脏了怎么清洗,硅... 1. 准备工具:洗洁精、牙膏、牙刷、风油精、棉签、橡皮擦和抹布。 以上内容仅供参考,可阅读硅胶...
英雄联盟lng是哪个战队,ln... 英雄联盟lng是哪个战队目录英雄联盟lng是哪个战队lng是哪个国家的战队lng打野tarzan哪国...
有没有学习美妆的软件,有什么教... 有没有学习美妆的软件目录有没有学习美妆的软件有什么教化妆的app?有什么美妆的APP有什么教化妆的a...
黑芝麻一天吃多少合适,每天吃多... 黑芝麻一天吃多少合适目录黑芝麻一天吃多少合适每天吃多少黑芝麻为宜黑芝麻每天吃多少合适?黑芝麻每天吃多...
东风标志307三厢车多长(东风... 今天给各位分享东风标志307三厢车多长的知识,其中也会对东风标志307三厢车多长多宽进行解释,如果能...
法国百科法国女人最钟爱的香水是... 本篇文章极速百科给大家谈谈法国百科法国女人最钟爱的香水是?,以及法国的什么香水最有名对应的知识点,希...
自然灾难电影有哪些 极速百科网... 自然灾难电影有哪些目录自然灾难电影有哪些自然灾难电影有哪些自然灾难片都有那些?像(后天)(烈火雄心)...