基础IO

本文深入探讨了C语言文件输入输出操作,详细解释了fwrite和fread函数的使用及注意事项,同时对比了C文件IO与系统文件IO的区别,包括open、read、write等系统调用的介绍。此外,还解析了文件描述符和FILE结构体的关系,以及硬链接和软链接的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      首先这里将对Linux下文件调用相关接口进行介绍,然后对比fd与FILE, 这里也会简单介绍下文件描述符和软硬链接相关的知识。首先复习C文件IO相关的操作。

C文件IO 

    FILE* fp = fopen("file", "rwa+");     //打开文件

    fgetc(fp);                           fputc()  //字符输入输出                              

    fgets(buf,len,fp);               fputs();  //字符串输入输出

    fscanf(fp,"%s",buf);           fprintf(); //流输入输出

    fread(buf,size,num,fp);      fwrite();  //文件读写

    fclose(f);                                     //关闭文件

详见:C语言文件IO相关操作

fwrite()函数:

    1.作用:在C语言中fwrite()函数常用语将一块内存区域中的数据写入到本地文本。

       注意:返回值随着调用格式的不同而不同:

            (1) 调用格式:fwrite(buf,sizeof(buf),1,fp);

                  成功写入返回值为1(即count)

            (2)调用格式:fwrite(buf,1,sizeof(buf),fp);

                 成功写入则返回实际写入的数据个数(单位为Byte)

注:写完数据后要调用fclose()关闭流,不关闭流的情况下,每次读或写数据后,文件指针都会指向下一个待写或者读数据位置的指针。

fread()函数:
      1. 作用:从一个文件流中读取数据

          注意:返回值随着调用格式的不同而不同:
              (1) 调用格式:fread(buf,sizeof(buf),1,fp);
             读取成功时:当读取的数据量正好是sizeof(buf)个Byte时,返回值为1(即count)

              否则返回值为0(读取数据量小于sizeof(buf))
              (2)调用格式:fread(buf,1,sizeof(buf),fp);
              读取成功返回值为实际读回的数据个数(单位为Byte)

实例:

  1 //使用fwrite给文件myfile写入数据

    #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 
  6 int main()
  7 {
  8     FILE* fp = fopen("myfile","w");
  9     if(!fp)
 10     {
 11         perror("fopen");
 12         exit(1);
 13     }
 14 
 15     const char* msg="hello world\n";
 16     fwrite(msg, strlen(msg),1,fp);
 17     return 0;
 18 }

    //使用fread读出myfile的数据
    
    #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<string.h>
  5 
  6 int main()
  7 {
  8     FILE* fd = fopen("myfile", "r");
  9     if(!fd)
 10     {
 11         perror("fopen");
 12         exit(1);
 13     }
 14 
 15     char buf[1024];
 16     ssize_t s=fread(buf,1,sizeof(buf),fd);
 17 
 18     buf[s]=0;
 19     printf("%s",buf);
 20     fclose(fd);
 21     return 0;
 22 }
 
    //3中方式输出信息到显示屏
    #include<stdio.h>
  2 #include<string.h>
  3 
  4 int main()
  5 {
  6     const char* msg = "hello fwrite\n";
  7     fwrite(msg,strlen(msg),1,stdout);
  8     printf("hello printf\n");
  9     fprintf(stdout,"hello fprintf\n");
 10 
 11     return 0;
 12 }
           

注:如果在一个函数中实现文件中读入数据在读出需要定义了两个FILE变量,一个用于write,一个用于read,写完后要close掉,然后再打开,然后读。如果直接使用一个FILE变量,会出错!

系统文件IO

      1. int open(const char* path, int flags);

         功能: 1. 打开文件 2. 创建文件

         参数:path :要打开的文件

         flag: 打开方式 //前三个只能选择其中一个

            O_RDONLY:只读方式打开  、O_WRONLY: 只写方式打开、 O_RDWR: 读写方式打开 、O_TRUNC : 清空文件、O_APPEND: 追加

        返回值: 失败-1 成功:文件描述符

       //创建文件

         int open(const char* path, int flags, mode_t mode);

        参数:path: 要创建的文件名    flags: O_CREAT    mode: 给文件的权限 0644

        创建文件还要受unmask影响。 若文件存在,则不会清空文件。

        如果文件存在不创建,如果文件不存在则创建。 flag : O_CREAT | O_RAWR | O_EXCL

      2. int read(int fd, char* buf , size_t len);

         功能:从fd文件中读取数据到buf所指向的空间,该空间的大小为len   注:没超过len有多少读多少

         返回值:实际读取的字符个数

       3. int write(int fd, const char* buf, size_t buf)

         功能:往fd所指向的文件中写入数据,数据的起始地址为buf, 大小为len

       4. int close(int fd )

         功能:关闭读取的文件描述符

       5. //定位

          int lseek(int fd, off_t offset, int whence);

        参数:offset : 偏移量     whence :SEEK_SET  / SEEK_CUR   /  SEEK_END

        返回值:从文件开头偏移多少字节。

对比FILE与fd

文件描述符

     文件描述符就是从0开始的小整数。

     当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。又因为每个进程和文件关联起来,所以每个进程都有一个指针*files, 指向一张表files_struct , 该表一个指针数组,每个元素都是一个指向打开文件的指针。本质上,文件描述符就是该数组的下标。

      

FILE结构体

      IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访问的。 所以C库当中的FILE结构体内部,必定封装来了fd. 库函数会自带缓冲区。

struct FILE
{
    char *_ptr;//文件输入的下一个位置
    int _cnt;//当前缓冲区的相对位置  (减少用户到内核的切换)
    char *_base;//指基础位置(文件的起始位置)
    int _flag;//文件标志
    int _file;//文件的有效性验证
    int _charbuf;//检查缓冲区状况,如果缓冲区则不读取
    int _bufsiz;//文件的大小
    char *_tmpfname;//临时文件名
    int _fileno; //封装的文件描述符
};

      

总结:fd与FILE

    1. fd是一个就是一个小整数

   2. FILE结构体中,封装了文件描述符。

理解文件系统与inode

   

  从上图可以看到,文件系统将属性和数据分开存放,那我们创建一个新文件又执行了那些操作。

  1. 存储属性

      内核先找到一个空闲的i结点。内核把文件信息记录到其中

  2. 存储数据

     该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800. 将内核缓冲区的第一块数据复制到300.

  3. 记录分配的请况

  4. 添加文件名到目录

     

硬链接和软链接

    硬连接

   从上面分析可以看出,真正找到磁盘上文件的并不是文件名,而是inode. 

注:当我们在删除文件时干了连接事情:

1. 在目录中将对应的记录删除   2. 将硬连接数-1, 如果为0,则将对应的磁盘释放

软链接

    硬连接通过inode引用另一个文件,软链接是通过名字引用另外一个文件。(所以两个文件的inode不同)

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值