Linux 系统编程——文件

一、打开创建文件

1.打开文件

(1)可通过查看man手册 查看相关函数的用法定义,需要引入的头文件等。

这里补充以下Linux man 1、2、3之间的区别:
1、Standard commands (标准命令)
2、System calls (系统调用)
3、Library functions (库函数)
4、Special devices (设备说明)
5、File formats (文件格式)
6、Games and toys (游戏和娱乐)
7、Miscellaneous (杂项)
8、Administrative Commands (管理员命令)
9 其他(Linux特定的), 用来存放内核例行程序的文档。

通过man 2 open 查找到需要引入的头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
在这里插入图片描述
打开文件函数:

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

参数1(const char *pathname,):所打开文件的路径
参数2(int flags):以何种方式打开(常用参数):
O_RDWR//可读可写
O_RDONLY//只读
O_WRONLY//只写

其他参数:

O_ASYNC:信号驱动输入输出方式,当每次输入或输出准备就绪后,产生一个信号。这种方式仅适用于终端、伪终端、socket、管道、fifo。

O_CREAT创建方式,如果pathname所指定的文件不存在,则创建一个新的文件。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{

        int fd;
        fd = open("./file",O_RDWR|O_CREAT,0600);
        if(fd == -1){
                printf("open faile\n");
        }else{
                printf("the fd of file is %d\n",fd);
        }

        return 0;
}

在这里插入图片描述

O_EXCL:当和O_CREAT一起使用的时候,若文件已经存在(只要文件的符号链接存在即可,无论这个符号链接指向何处),则open函数执行失败

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{

    int fd;
    int size;
    fd = open("./file",O_RDWR|O_CREAT|O_EXCL,0600);
    if(fd == -1){
        printf("打开失败,文件已经存在\n");

    }
    return 0;
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

在这里插入图片描述
O_APPEND追加方式,每次写之前,文件都会定位到末尾。
例:

  • 当不加O_APPEND时 写入的内容会覆盖掉(只覆盖一部分)之前的内容:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{

    int fd;
    int size;
    char *str = "hello!!!";
    fd = open("./file",O_RDWR|O_CREAT,0600);
    if(fd == -1){
        printf("open faile\n");
    }else{
        printf("the fd of file is %d\n",fd);
    }

    size = strlen(str);
    printf("write len is %d\n",size);
    write(fd,str,size);
    close(fd);

    return 0;
}    

操作文件之前:
在这里插入图片描述

操作文件之后:
在这里插入图片描述

  • 当加入O_APPEND后:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main()
{

    int fd;
    int size;
    char *str = "hello!!!";
    fd = open("./file",O_RDWR|O_CREAT|O_APPEND,0600);
    if(fd == -1){
        printf("open faile\n");
    }else{
        printf("the fd of file is %d\n",fd);
    }

    size = strlen(str);
    printf("write len is %d\n",size);
    write(fd,str,size);
    close(fd);

    return 0;
}
~   

操作文件后,写入的内容没有覆盖之前的内容
在这里插入图片描述
O_TRUNC:如果要打开的文件已经存在,并且是一个普通文件,并且打开方式允许写操作,那么这个文件的长度会被截断成0。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{

    int fd;
    int size;
    char *str = "hello!!!";
    fd = open("./file",O_RDWR|O_CREAT|O_TRUNC,0600);
    if(fd == -1){
        printf("open faile\n");
    }else{
        printf("the fd of file is %d\n",fd);
    }

    size = strlen(str);
    printf("write len is %d\n",size);
    write(fd,str,size);
    close(fd);

    return 0;
}
~                                                                                                                                                                                    
~       
  • 操作之前
    在这里插入图片描述

  • 操作之后
    在这里插入图片描述

O_LARGEFILE:允许打开的文件是大文件(其大小不能用off_t表示,而是用off64_t表示)。

O_NOATIME:当对文件进行读操作时,不更新文件的最后访问时间。这个标记多用在索引或备份程序中,使用这个标记可以减少磁盘操作次数,进而提高效率。这个操作不是对所有的文件系统都适用,NFS文件系统就不适用,因为NFS文件系统是在服务器端控制最后访问时间。

O_NOCTTY:如果pathname指向的是终端设备,那么此终端不会成为进程的控制终端(即使此进程没有控制某个终端)。

O_NOFOLLOW:如果pathname是符号链接,那么open函数执行失败。pathname前部的符号链接还是可以被跟踪的。

O_NONBLOCK或O_NDELAY:如果一个文件用nonblock方式打开,则无论是open操作,还是其后作用于这个文件上的其他操作,都不会阻塞等待,而后立即返回。

O_SYNC:同步方式。在对这个文件的写操作完成之前,不能对这个文件进行其他的操作。

O_DIRECT:最小化cache作用的方式。这种方式是系统的cache作用最小发挥,这可能会影响进程的性能,但是对于某些特定场景比较适合(比如,自己完成cache,而不需要系统自动完成)。

O_DIRECTORY:如果pathname是目录,则open函数失败。这个标记是linux特有的,是为了避免opendir在fifo或tape device上调用时的denial of service问题。
在打开文件之后,上面有些flags可以通过调用fcntl()来修改。

参数3(mode_t mode): mode参数只有在建立新文件时才会生效(flags中包含O_CREAT),表示新建文件的权限(r代表可读权限(0400) w代表可写权限(0200) x代表可执行权限(0100)
4+2=6代表权限可读可写)

权限赋值0600 表示创建的file文件可读可写:
在这里插入图片描述
其他参数解释:
S_IRWXU (00700) 本用户有读、写、执行的权限。

S_IRUSR (00400) 本用户有读的权限。

S_IWUSR (00200) 本用户有写的权限。

S_IXUSR (00100) 本用户有执行的权限。

S_IRWXG (00070) 本组能成员有读、写、执行的权限。

S_IRGRP (00040) 本用户组能成员有读的权限。

S_IWGRP (00020) 本用户组成员有写的权限。

S_IXGRP (00010) 本用户组的成员有执行的权限。

S_IRWXO (00007) 其他用户有读、写、执行的权限。

S_IROTH (00004) 其他用户有读的权限。

S_IWOTH (00002) 其他用户有写的权限。

S_IXOTH (00001) 其他用户有执行的权限。

2.创建文件

int creat(const char *pathname, mode_t mode);

参数1(const char *pathname,):所创建文件的路径
参数2(mode_t mode):以何种方式打开(常用参数):上面已经提及到常用参数
例:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    int fd;
    char *buf="hello world!";
    fd=creat("/home/zh1/STEP2/wenjian/file1",S_IRWXU);//建立一个路径为/home/CLC/名字为file2的文件,写是可读可写可执行的文件
    write(fd,buf,strlen(buf));
    close(fd);


    return 0;
}                                                                                                                                                                                                        

在这里插入图片描述
并可以看到file1文件的权限是可读可写可执行
在这里插入图片描述

二、文件写入操作

需要引入的头文件
#include <unistd.h>

write函数

ssize_t write(int fd, const void *buf, size_t count);

参数1(int fd):文件描述符 需要写入的文件的描述符
参数2(const void *buf):写入的的内容存放在buf中,是一个指向buf的指针
参数3(size_t count):写入内容的大小
返回值:写入字节的个数

例:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{

        int fd;
        int size;
        char *str = "hello!!!";
        fd = open("./file",O_RDWR|O_CREAT,0600);
        if(fd == -1){
                printf("open faile\n");
        }else{
                printf("the fd of file is %d\n",fd);
        }

        size = write(fd,str,strlen(str));
        printf("size = %d\n",size);
        close(fd);

        return 0;
}

在这里插入图片描述

打开file文件:
在这里插入图片描述
写入成功

三、读取文件

需要引入的头文件
#include <unistd.h>

 ssize_t read(int fd, void *buf, size_t count);

参数1(int fd):文件描述符 需要读取的文件的描述符
参数2(const void *buf):读取的的内容存放在buf中,是一个指向buf的指针
参数3(size_t count):读取内容的大小

返回值:读取字节的个数
例:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main()
{

        int fd;
        int size;
        char *str = "hello!!!";
        fd = open("./file",O_RDWR|O_CREAT,0600);
        if(fd == -1){
                printf("open faile\n");
        }else{
                printf("the fd of file is %d\n",fd);
        }

        size = write(fd,str,strlen(str));
        printf("size = %d\n",size);
        close(fd);//注意文件写入之后的光标会停留在写入内容的末尾

        char *readBuf;
        int readSize;
        readBuf = (char*) malloc(sizeof(size)+1);//由于read的第二个参数是void * 类型,因此需要用malloc 函数开辟空间并强制类型转换为char *类型
        fd = open("./file",O_RDWR);//因此需要重新的关闭打开
        readSize = read(fd,readBuf,size);
        printf("The file size is %d,context is %s\n",readSize,readBuf);
        close(fd);

        return 0;
}


运行结果:在这里插入图片描述

四、移动文件中的光标

需要引入的头文件:
#include <sys/types.h>
#include <unistd.h>

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

参数1(int fd):文件描述符
参数2(off_t offset):偏移值 (对whence的偏移值)
参数3(int whence):固定点的位置
SEEK_SET
The offset is set to offset bytes.//文件的头
SEEK_CUR
The offset is set to its current location plus offset bytes.//当前光标位置
SEEK_END:
The offset is set to the size of the file plus offset bytes.//文件尾

返回值:若成功 返回值为从头到尾的字节数
例:通过lseek,得到打开文件的字节数,并读取文件内容

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{

    int fd;
    int size;
    char *str = "hello!!!";
    fd = open("./file",O_RDWR|O_CREAT,0600);
    if(fd == -1){
        printf("open faile\n");
    }else{
        printf("the fd of file is %d\n",fd);
    }
    int readSize;
    char * readBuf;
    readSize = lseek(fd, 0, SEEK_END);//偏移光标,使之置于末尾,可返回文件大小
    lseek(fd, 0, SEEK_SET);//偏移光标,使之置于首位

    readBuf = (char*) malloc(sizeof(readSize));//由于read的第二个参数是void * 类型,因此需要用malloc 函数开辟空间并强制类型转换为char *类型

    read(fd,readBuf,readSize);
    printf("The file size is %d,context is %s\n",readSize,readBuf);//打印
    close(fd);

    return 0;
}

五、文件操作练习

1.自己实现文件拷贝

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main(int argc,char **argv)
{   
    int fdScr;//源文件操作符
    int fdDes;//目标文件操作符
    char* scrBuf=NULL;//存储源文件内容的字符串
    fdScr=open(argv[1],O_RDWR);//以可读可写的方式打开源文件 
    int size=lseek(fdScr,0,SEEK_END);//通过此函数间接得到源文件大小
    lseek(fdScr,0,SEEK_SET);//将光标移回原位
    scrBuf=(char *)malloc(sizeof(char)*size+8);//对srcBuf开辟源文件大小的内容
    read(fdScr,scrBuf,size);//将源文件的字符串读入srcBuf
    fdDes=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);//打开目的文件,并且将目的文件的内容清空
    write(fdDes,scrBuf,strlen(scrBuf));//将源文件的内容写入目的文件实现文件间的拷贝
    close(fdScr);
    close(fdDes);

    return 0;
}                                                                                                                                                                                       

在这里插入图片描述
在这里插入图片描述
可见实现了cp操作

2. 修改程序的配置文件

例 在TEST.config中修改LENG=7为LENG=4
在这里插入图片描述

#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<string.h>
#include <stdlib.h>

int main(int argc,char **argv)
{
        int fdScr;// 需要修改的源文件操作符
        char* scrBuf=NULL;//用来接受源文件的字符串
        fdScr=open(argv[1],O_RDWR);//打开源文件
        int size=lseek(fdScr,0,SEEK_END);//间接计算源文件内容
        lseek(fdScr,0,SEEK_SET);//将光标值向头
        scrBuf=(char *)malloc(sizeof(char)*size+8);//为用来接受源文件内容的字符串开辟空间
        read(fdScr,scrBuf,size);//读取源文件内容至srcBuf
        char *p=strstr(scrBuf,"LENG=");//用strstr函数索引到需要改的地方,返回的p为索引到字符串的头指针。
        if(p==NULL){
                printf("NOT FOUND!\n");
                exit(-1);
        }
        p=p+strlen("LENG=");//将指针移动到需要修改的字符串
        *p='4';//修改指定内容
        close(fdScr);
        fdScr =open(argv[1],O_RDWR|O_TRUNC);//重新打开,以清空源文件内容方式打开
        write(fdScr,scrBuf,strlen(scrBuf));//写入新的内容
        close(fdScr);
        return 0;
}

将LENG = 7修改为LENG = 4
在这里插入图片描述

3.向文件中写入一个结构体

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<string.h>
#include <stdlib.h>
struct Test
{
    int a;
    char b;
};//构建一个结构体
int main()
{       int fd;
    fd=open("./file1",O_RDWR|O_CREAT);//读写模式打开文件

    struct Test data[2]={{100,'a'},{101,'b'}};//构建有个struct Test类型的数组
    struct Test rdata[2];
    /*由于ssize_t write(int fd, const void *buf, size_t count);
      write 函数第二个参数写入的类型是一个 void*类型
      则可以直接取data的地址写入write的第二个参数*/
    write(fd,&data,sizeof(struct Test)*2);//向文件中写入结构体
    lseek(fd,0,SEEK_SET);//光标移动到首段
    read(fd,&rdata,sizeof(struct Test)*2);//再将刚写入的结构体存储到rdata中
    printf(" write %d %c \n",rdata[0].a,rdata[0].b);
    printf(" write %d %c \n",rdata[1].a,rdata[1].b);
    close(fd);
    return 0;
}

六、标准C库对文件操作的引入

1.标准c库文件操作与Linux文件操作的差别

以open和fopen为例:

(1) 来源
从来源的角度看,两者能很好的区分开,这也是两者最显而易见的区别:
open是UNIX系统调用函数(包括LINUX等),返回的是文件描述符(File Descriptor),它是文件在文件描述符表里的索引。
fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api。返回的是一个指向文件结构的指针。
PS:从来源来看,两者是有千丝万缕的联系的,毕竟C语言的库函数还是需要调用系统API实现的。

(2) 移植性
这一点从上面的来源就可以推断出来,fopen是C标准函数,因此拥有良好的移植性;而open是UNIX系统调用,移植性有限。如windows下相似的功能使用API函数CreateFile

(3) 适用范围
open返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作普通正规文件(Regular File)。
fopen是用来操纵普通正规文件(Regular File)的。

(4) 文件IO层次
如果从文件IO的角度来看,前者属于低级IO函数,后者属于高级IO函数。低级和高级的简单区分标准是:谁离系统内核更近。低级文件IO运行在内核态,高级文件IO运行在用户态。

(5)缓冲
缓冲文件系统
缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用;当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓冲区”依此读出需要的数据。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。
非缓冲文件系统
缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。open, close, read, write, getc, getchar, putc, putchar等。
一句话总结一下,就是open无缓冲,fopen有缓冲。前者与read, write等配合使用, 后者与fread,fwrite等配合使用。

使用fopen函数,由于在用户态下就有了缓冲,因此进行文件读写操作的时候就减少了用户态和内核态的切换(切换到内核态调用还是需要调用系统调用API:read,write);而使用open函数,在文件读写时则每次都需要进行内核态和用户态的切换;表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列的函数快;如果随机访问文件则相反。

2.标准C库的文件操作

(1)文件打开

 FILE *fopen(const char *path, const char *mode);

第一个参数:为打开文件的路径
第二个参数:为以何种方式打开,这里注意写打开模式是要求的是 char *类型的,所以要用双引号!
mode有以下几种情况:
r 只读方式打开一个文本文件
rb 只读方式打开一个二进制文件
w 只写方式打开一个文本文件
wb 只写方式打开一个二进制文件
a 追加方式打开一个文本文件
ab 追加方式打开一个二进制文件
x+ 可读可写方式打开一个文本文件
rb+ 可读可写方式打开一个二进制文件
W+ 可读可写方式创建一个文本文件
wb+可读可写方式生成一个二进制文件
a+ 可读可写追加方式打开一个文本文件
ab+ 可读可写方式追加一个二进制文件

(2)文件写入

size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

第一个参数:为所写入字符串的指针
第二个参数:为每一次写入多少字节,
第三个参数:为要写多少次
第四个参数‘:为FILE*类型指针变量
返回值:返回实际写入的数据块数目
注意:返回值随着调用格式的不同而不同:

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

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


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

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

(3)文件的读取

 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

第一个参数:为存放所读取字符串的指针
第二个参数:为每一次读入多少字节,
第三个参数:为要读多少次
第四个参数:为FILE*类型指针变量
注意:返回值随着调用格式的不同而不同:

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

(4)文件光标的移动

 int fseek(FILE *stream, long offset, int whence);

第一个参数:FILE*类型指针变量
第二个参数:偏移值 (对whence的偏移值)
第三个参数:固定点的位置
返回值: 成功,返回0,否则返回其他值。
例:标准库文件打开、创建、读、写、光标移动操作

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    FILE *fp;//定义一个FILE *类型的文件描述符,这点与open()函数不同,后者的文件描述符时int 类型的
    char * str="hello world!";
    char *readstr;
    size_t size;

    //       FILE *fopen(const char *path, const char *mode);
    fp=fopen("./test.txt","w+");//第一个参数为打开文件的路径,第二个参数为以何种方式打开,这里注意写打开模式是要求的是 char *类型的,所以要用双引号” ”!
    //w+:有就打开,没有则创建
    //      size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
    size = fwrite(str,sizeof(char),strlen(str),fp);//第一个参数为所写入字符串的指针,第二个参数为每一次写入多少字节,第三个参数为要写的次数,第四个参数为FILE*类型指针变量

    //       int fseek(FILE *stream, long offset, int whence);
    fseek(fp,0,SEEK_SET);//fseek的用法与lseek用法一致

    readstr = (char *)malloc(size);
    //      size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    fread(readstr,sizeof(char),strlen(str),fp);

    printf("The file context is %s\n",readstr);
    fclose(fp);

    return 0;
}                                                                                                                                                                                        

例 用标准文件操作,向文件中写入一个结构体

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Test
{
        int a;
        char b;
};
int main()
{       FILE * fd;
        fd=fopen("./file2","w+");

        struct Test data={100,'a'};
        struct Test rdata;

        fwrite(&data,sizeof(struct Test),1,fd);
        fseek(fd,0,SEEK_SET);
        fread(&rdata,sizeof(struct Test),1,fd);
        printf(" write %d %c \n",rdata.a,rdata.b);

        fclose(fd);


        return 0;
}

3.标准C库文件操作的其他函数

(1) fputc(); 一次写入一个字节

int main()
{
        FILE * fp;
        char *str="hello world!";
        int i;
        int length=strlen(str);
        fp=fopen("./file3.txt","w+");
//      int fputc(int c, FILE *stream);//fputc 函数只能一个字符串一个字符串的写入文件
        for(i=0;i<length;i++){
                fputc(*str,fp);
                str++;

        }
        fclose(fp);
        return 0;
}

在这里插入图片描述

(2)fgertc(); 从文件将字符一个一个取出来

(3)feof(); 判断是否到文件的尾巴
若到达文件尾巴则返回值为非0,没有到达文件尾巴则返回0.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    FILE * fp;
    char  getstr;
    fp=fopen("./file3.txt","r");

    while(!feof(fp)){
        getstr=fgetc(fp);
        printf("%c",getstr);

    }
    fclose(fp);
    return 0;
}    

在这里插入图片描述

七、文件操作的原理

1、对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或者创建一个新文件时,内核向进程返回一个文件描述符。当读写一个文件时,用open和creat返回的文件描述符标识该文件,将其作为参数传递给read和write。
按照惯例,UNIX shell使用文件描述符0与进程的标准输入相结合,文件描述符1与标准输出相结合,文件描述符2与标准错误输出相结合。STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO这几个宏代替了0、1、2这几个魔数.
2、文件描述符,这个数字在一个进程中表示一个特定含义,当我们open一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回给应用程序一个数字作为文件描述符,这个数字就和我们内存中维护的这个动态文件的这些数据结构绑定上了,以后我们应用程序如果要操作这个动态文件,只需要用这个文件描述符区分。
3、文件描述符的作用域就是当前进程,出了这个进程文件描述符就没有意义了
open函数打开文件,打开成功返回一个文件描述符,打开失败,返回-1。
4、在Linux中要操作一个文件,一般是先open打开一个文件,得到文件描述符,然后对文件进行读写操作(或其他操作),最后是close关闭文件即可。
5、强调一点:我们对文件进行操作时,一定要先打开文件,打开成功之后才能操作,如果打开失败,就不用进行后边的操作了,最后读写完成后,一定要关闭文件,否则会造成文件损坏。
6、文件平时是存放在块设备中的文件系统文件中的,我们把这种文件叫静态文件,当我们去open打开一个文件时,linux内核做的操作包括:内核在进程中建立一个打开文件的数据结构,记录下我们打开的这个文件;内核在内存中申请一段内存,并且将静态文件的内容从块设备中读取到内核中特定地址管理存放(叫动态文件)。
7、打开文件以后,以后对这个文件的读写操作,都是针对内存中的这一份动态文件的,而并不是针对静态文件的。当然我们对动态文件进行读写以后,此时内存中动态文件和块设备文件中的静态文件就不同步了,当我们close关闭动态文件时,close内部内核将内存中的动态文件的内容去更新(同步)块设备中的静态文件。
8、为什么这么设计,不直接对块设备直接操作。
块设备本身读写非常不灵活,是按块读写的,而内存是按字节单位操作的,而且可以随机操作,很灵活。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值