Linux 文件系统

前言

Linux修改文件步骤其实和Windows系统相似,步骤如下:
Linux 文件系统_第1张图片
操作系统提供了一系列的API
如Linux系统:
打开 open
读写 write/read
光标定位 lseek
关闭 close

什么是文件标识符?
文件描述符即索引,通过文件描述符来区分不同文件,并对相应文件进行操作。

静态文件:存放在块设备中的文件系统中。
动态文件:当我们去open打开一个文件时,linux内核做的操作包括:内核在进程中建立一个打开文件的数据结构,记录下我们打开的这个文件;内核在内存中申请一段内存,并且将静态文件的内容从块设备中读取到内核特定地址管理存放的。

为什么要使用close函数关闭文件?
当我们close动态文件时,close内部内核将内存中的动态文件的内容去更新块设备中的静态文件。如果没有使用close函数关闭文件,会导致文件发生破损。

为什么这么设计,不直接对块设备直接操作?
块设备本身读写非常不灵活,是按块读写的,而内存是按字节单位操作,而且可以随机操作,很灵活。


API介绍

一、打开文件

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

头文件
#include
#include
#include

参数
pathname:要打开的文件名(含路径,缺省为当前路径)
flags:O_RDONLY 只读打开 O_WRONLY 只写打开 O_RDWR 可读可写打开
以上三种常数只能指定一个。下列常数是可选择的:

常数 功能
O_APPEND 以追加的方式打开文件
O_CREAT 创建一个文件
O_EXCL 如果使用了O_CREAT而且文件已经存在,就会发生一个错误
O_TRUNC 如果文件已经存在,则删除文件的内容

(ps: ls -l 指令可查看所在目录所有文件的权限)
mode:权限设置
Linux总共用5个数字来表示文件的各种权限:第一位表示设置用户ID;第二位表示设置组ID;第三位表示用户自己的权限位;第四位表示组的权限;最后一位表示其他人的权限。每个数字可以取1(执行权限)、2(写权限)、4(读权限)、0(无)或者是这些值的和。例如,要创建一个用户可读、可写、可执行,但是组没有权限,其他人可以读、可以执行的文件,并设置用户ID位。那么,我们应该使用的模式是0(不设置用户ID)、0(不设置组ID)、6(2+4,读、写、不可执行)、0(没有权限)、0(没有权限)即00600:

返回
文件描述符

二、关闭文件

int close(int fd);

头文件
#include

参数
文件标识符

返回
成功的话,返回0;失败的话,返回-1。

三、写操作

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

头文件
#include

参数
fd:文件标识符
buf:写入缓冲指针
count:写入字节大小

返回
成功的话,返回已经写入字节大小;失败的话,返回-1。

四、读操作

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

头文件
#include

参数
fd:文件标识符
buf:读出缓冲指针
count:读出字节大小
返回:成功的话,返回已经读出字节大小;失败的话,返回-1。

五、光标定位

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

头文件
#include
#include

参数
fd:文件标识符
offset:相对于whence的偏移值
正数往文件尾位置走,负数往文件头位置走。
whence:当前光标位置

参数 功能
SEEK_SET 文件头位置
SEEK_CUR 文件当前位置
SEEK_END 文件尾位置

返回
当前位置相对于文件头位置的第几个字节数


程序编写

例程1:编写一个程序,在当前目录下打开用户可读写文件“test",如果不存在该文件,创建文件。在其中写入“hello linux!”,关闭该文件。再次打开该文件,读取其中的内容并输出在屏幕上。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(){
     
        int fd; 
        fd=open("test",O_RDWR);
        char *write_buf="hello linux!";
        if(fd==-1)
        {
     
                printf("no file\n");
                fd=open("test",O_RDWR|O_CREAT,0600);
                printf("file creat success\n");
        }
        int n_write=write(fd, write_buf, strlen(write_buf));
        char *read_buf=(char*)malloc(sizeof(char)*n_write+1);
        if(n_write==-1)
                printf("write fail!\n");
        close(fd);
        fd=open("test",O_RDWR);
        int n_read=read(fd,read_buf,n_write);
        if(n_read==-1)
                printf("read fail");
        printf("fd=%d\n",fd);
        printf("read_count:%d context:%s\n",n_read,read_buf);
        close(fd);
        return 0;
} 

例程2:编写一个程序,在当前目录下打开用户可读写文件“test",如果不存在该文件,创建文件。在其中写入“hello linux!”,移动光标到文件头位置,读取其中的内容并输出在屏幕上。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(){
     
        int fd; 
        fd=open("test",O_RDWR);
        char *write_buf="hello linux!";
        if(fd==-1)
        {
     
                printf("no file\n");
                fd=open("test",O_RDWR|O_CREAT,0600);
                printf("file creat success\n");
        }
        int n_write=write(fd, write_buf, strlen(write_buf));
        char *read_buf=(char*)malloc(sizeof(char)*n_write+1);
        if(n_write==-1)
                printf("write fail!\n");
        lseek(fd,0,SEEK_SET);
        int n_read=read(fd,read_buf,n_write);
        if(n_read==-1)
                printf("read fail");
        printf("fd=%d\n",fd);
        printf("read_count:%d context:%s\n",n_read,read_buf);
        close(fd);
        return 0;
}  

例程3:编写一个程序,通过lseek函数,可以巧妙地获取文件大小,即字节数大小,并输出在屏幕上。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(){
     
        int fd;
        fd=open("test",O_RDWR);
        char *write_buf="hello linux!";
        if(fd==-1)
        {
     
                printf("no file\n");
                fd=open("test",O_RDWR|O_CREAT,0600);
                printf("file creat success\n");
        }
        printf("fd=%d\n",fd);
        int size=lseek(fd,0,SEEK_END);
        printf("file size=%d\n",size);
        close(fd);
        return 0;
}

open函数补充
对于打开文件open函数,flag参数我们只使用了O_RDWR 和O_CREAT,下面我们对其他常数进行验证。

常数 功能
O_APPEND 以追加的方式打开文件
O_CREAT 创建一个文件
O_EXCL 如果使用了O_CREAT而且文件已经存在,就会发生一个错误
O_TRUNC 如果文件已经存在,则删除文件的内容

例程4:使用O_APPEND常数在文件尾部位置添加数据。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(){
     
        int fd;
        fd=open("test",O_RDWR|O_APPEND);
        char *write_buf="hello linux!\n";
        if(fd==-1)
        {
     
                printf("no file\n");
                fd=open("test",O_RDWR|O_CREAT|O_APPEND,0600);
                printf("file creat success\n");
        }
        printf("fd=%d\n",fd);
        int size=lseek(fd,0,SEEK_END);
        printf("file size=%d\n",size);
        int n_write=write(fd, write_buf, strlen(write_buf));
        if(n_write==-1)
                printf("write fail!\n");
        close(fd);
        return 0;
}

例程5:使用O_EXCL常数判断文件是否存在。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(){
     
        int fd;
        fd=open("test",O_RDWR|O_CREAT|O_EXCL,0600);
        if(fd==-1)
        {
     
                printf("file already exist\n");
                return -1;

        }
        else
        {
     
                printf("file creat success\n");
        }
        close(fd);
        return 0;
}

例程6:使用O_TRUNC常数覆盖原文件。

#include 
#include 
#include 
#include 
#include 
#include  
#include  
int main(){
     
        int fd; 
        fd=open("test",O_RDWR|O_TRUNC);
        char *write_buf="hello linux!\n";
        if(fd==-1)
        {
     
                printf("no file\n");
                fd=open("test",O_RDWR|O_CREAT,0600);
                printf("file creat success\n");
        }
        printf("fd=%d\n",fd);
        int size=lseek(fd,0,SEEK_END); 
        printf("file size=%d\n",size);
        int n_write=write(fd, write_buf, strlen(write_buf));
        if(n_write==-1)
                printf("write fail!\n");
        close(fd);
        return 0;
}

例程7:实现复制文件cp指令。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(int argc,char** argv){
     
        int src_fd,des_fd;
        if(argc!=3)
        {
     
                printf("arguments errors!\n");
                return -1;
        }
        src_fd=open(argv[1],O_RDWR);
        if(src_fd==-1)
        {
     
                printf("src file don't exist\n");
                return -1;
        }
        int size=lseek(src_fd,0,SEEK_END);
        lseek(src_fd,0,SEEK_SET);
        des_fd=open(argv[2],O_RDWR|O_CREAT,0600);
        char *read_buf=(char*)malloc(sizeof(char)*size+1);
        int n_read=read(src_fd,read_buf,size);
        if(n_read==-1)
                printf("read fail\n");
        printf("read_count:%d context:%s\n",n_read,read_buf);
        int n_write=write(des_fd, read_buf, strlen(read_buf));
        if(n_write==-1)
                printf("write fail!\n");
        close(src_fd);
        close(des_fd);
        return 0;
}

例程8:实现配置文件的配置。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(int argc,char** argv){
     
        int fd;
        char* find_str=malloc(128);
        char* value=malloc(128);
        if(argc!=3)
        {
     
                printf("arguments errors!\n");
                return -1;
        }
        strcpy(find_str,argv[1]);
        strcpy(value,argv[2]);
        fd=open("config",O_RDWR);
        if(fd==-1)
        {
     
                printf("no config file\n");
                return -1;
        }
        int size=lseek(fd,0,SEEK_END);
        lseek(fd,0,SEEK_SET);
        char *read_buf=(char*)malloc(sizeof(char)*size+1);
        int n_read=read(fd,read_buf,size);
        if(n_read==-1)
                printf("read fail");
        char* str_start=strstr(read_buf,find_str);
        if(str_start==NULL)
        {
     
                printf("no designative argument!\n");
                return -1;
        }
        str_start+=strlen(find_str)+1;
        while(1)
        {
     
                if(*str_start=='\n')
                        break;
                *str_start=*value;
                str_start++;
                value++;
        }
        printf("read_count:%d context:\n%s\n",n_read,read_buf);
        lseek(fd,0,SEEK_SET);
        int n_write=write(fd, read_buf, strlen(read_buf));
        if(n_write==-1)
                printf("write fail!\n");
        close(fd);
        return 0;
}

例程9:写一个整数到文件。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(){
     
        int fd;
        int data1=0;
        int data2=75;
        fd=open("test",O_RDWR);
        if(fd==-1)
        {
     
                printf("no file\n");
                fd=open("test",O_RDWR|O_CREAT,0600);
                printf("file creat success\n");
        }
        int n_write=write(fd, &data2,sizeof(data2));
        if(n_write==-1)
                printf("write fail!\n");
        lseek(fd,0,SEEK_SET);
        int n_read=read(fd,&data1,sizeof(data1));
        if(n_read==-1)
                printf("read fail");
        printf("fd=%d\n",fd);
        printf("read_count:%d context:%d\n",n_read,data1);
        close(fd);
        return 0;
}

例程10:写一个结构体到文件。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
typedef struct Stu{
     
        int age;
        char* name;
}stu,*pstu;
int main(){
     
        int fd;
        pstu stu1=(pstu)malloc(sizeof(stu));
        stu1->age=21;
        stu1->name="xiaoming";
        pstu stu2=(pstu)malloc(sizeof(stu));
        fd=open("test",O_RDWR);
        if(fd==-1)
        {
     
                printf("no file\n");
                fd=open("test",O_RDWR|O_CREAT,0600);
                printf("file creat success\n");
        }
        int n_write=write(fd, stu1,sizeof(stu));
        if(n_write==-1)
                printf("write fail!\n");
        lseek(fd,0,SEEK_SET);
        int n_read=read(fd,stu2,sizeof(stu));
        if(n_read==-1)
                printf("read fail");
        printf("fd=%d\n",fd);
        printf("read_count:%d context:%d %s\n",n_read,stu1->age,stu1->name);
        close(fd);
        return 0;
}

小结

Linux提供的虚拟文件系统为多种文件系统提供了统一的接口,Linux的文件编程有两种途径:基于Linux系统调用;基于C库函数。这两种编程所涉及到文件操作有新建、打开、读写和关闭,对随机文件还可以定位。本章对基于Linux系统调用方法给出了非常具体的实例。

你可能感兴趣的:(Linux学习笔记,linux)