Linux文件的相关操作

1.1关于文件(应用为王!!!)

关于文件,理论内容繁多,文件系统原理以及访问机制,文件在内核中的管理机制,什么是文件信息节点inode,文件的共享,文件权限以及用户对其权限等等。。等等。。。

在实际的编程应用过程中,时常需要运用到文件的打开、保存、关闭等等步骤来保存一些进程进行过程中所产生的数据。例如:游戏进程的存档、银行ATM机打印消费流水等等。都是需要在程序运行的过程中打开其他文件的数据进行访问操作。因此,在此对于编程者而言,需要更多的是使用操作系统提供的相关API进行操作、编程实现功能。

首先,我们在实际使用操作系统的过程中是如何进行文件的相关操作的:使用鼠标双击打开文件、找到文件相应位置编辑文件内容、保存并退出文件。在编程中,如何运用程序进行相关操作让计算机自动完成上述操作?

在Linux操作系统中提供了一系列的API助于我们完成上述操作:

打开 open;读写 write/read 光标定位 lseek;关闭 close;

1.2文件的打开与创建(open/creat)

       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

       int open(const char *pathname, int flags);//文件路径名(字符串)/文件的权限//第一条
       int open(const char *pathname, int flags, mode_t mode);//第二条

       int creat(const char *pathname, mode_t mode);//第三条

描述:
给定一个相应文件的路径,open()函数返回的是一个整形变量(文件描述符),一个小的非负整数。该描述符用于之后对于该文件操作作为索引。若打开失败,返回值则是-1。当进程成功打开一个文件后,会为该文件创建一个结构体,以便于随后对于文件进行相关操作,那么文件描述符可作为入口进行操作。

pathname:要打开的文件名(含路径,缺省为当前路径);

flags: O_RDONLY 只读打开;O_WRONLY 只写打开;O_RDWR 可读可写打开;

当我们附带了权限后,打开的文件就只能是按照这种权限来操作!!!

第一条代码编程:

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

int main()
{
        int fd;//定义文件描述符(file descriptor)

        fd = open("./file1",O_RDWR);//尝试打开file1(权限为可读可写)
        printf("fd = %d\n",fd);
        if(fd == -1){
                printf("creat failed\n");
                if(fd >0){
                        printf("creat sucess\n");
                }
        }
        return 0;
}

 由上述程序运行结果可知:当file1不存在的时候返回值是:-1,因此提示打开失败。

在上述情况下,当文件不存在的原因打开失败时,需要重新创建一个文件,因此就需要用到第二条函数。

O_CREAT 若文件不存在的情况下,则需要创建它。因此使用此项时,需要同时说明第三个参数mode,用其说明该新文件的存取许可权限。(mode一定是在flags中使用了O_CREAT标志,mode记录着待创建文件的访问权限。)

 第二条代码编程:

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

int main()
{
        int fd;
        fd = open("./file1",O_RDWR);//尝试打开file1
        if(fd == -1){
                printf("creat failed\n");//文件不存在打开失败
                fd = open("./file1",O_RDWR|O_CREAT,0600);//重新创建
                if(fd >0){
                        printf("creat sucess\n");//创建成功
                }
        }
        return 0;
}

 

 上述程序执行后,file1则成功创建。

关于0600则代表该待创建文件的访问权限。

 

如上图,第一行 - 代表是一个普通文件,rwxr:r代表用户对该文件可读;w代表用户对该文件可写;x则代表用户对该文件可执行。

在Linux中,可读为4(r),可写为2(w),可执行为1(x),在刚刚创建的文件中为rw(可读可写)因此这个数字和为6。0600代表的是该未创建文件的访问权限。 

1.3文件的写入操作(write();close();3)

如何将指定的数据写入到创建的文件当中?因此就需要用到write函数。

 描述:使用write函数,将buf中的数据,按照count中的字节数,通过文件描述符fd写入到file文件中。若写入成功,则返回写入的字节数。若写入失败,则返回-1。

int main()
{
        int fd;
        char* buf = "Hello World!";

        fd = open("./file1",O_RDWR);
        if(fd == -1){
                printf("creat failed\n");
                fd = open("./file1",O_RDWR|O_CREAT,0600);
                if(fd >0){
                        printf("creat sucess\n");
                }
        }
        printf("fd = %d\n",fd);
        write(fd,buf,sizeof(buf));//write(fd,buf,strlen(buf);
        close(fd);
        
        return 0;
}

 //在此会出现一个错误,buf是一个字符串的同时,也是一个指针,在Linux64位当中,指针代表8个字节,因此在写入时count = 8,就只会写入8个字节的字符串内容,导致写入数据的缺失!!!!

如何改正?使用到strlen()函数,strlen(buf);

改正后运行结果如下:

最后完整写入完成字符串。

1.4 文件的读取操作以及光标的移动操作(read();lseek();)

 

 描述:read()函数,将fd所指向的文件中的内容按照count的大小读入到buf所指向的内存空间当中。如果读入成功则返回成功读入的大小,若读入失败,则返回-1。

代码如下:

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

int main()
{
        int fd;
        char* buf = "Hello World!";

        fd = open("./file1",O_RDWR);
        if(fd == -1){
                printf("creat failed\n");
                fd = open("./file1",O_RDWR|O_CREAT,0600);
                if(fd >0){
                        printf("creat sucess\n");
                }
        }

        int n_write = write(fd,buf,strlen(buf));
        printf("write %d byte\n",n_write);//打印成功写入的大小

        char* readBuf = (char*)malloc(sizeof(char)*n_write);

        //ssize_t read(int fd, void *buf, size_t count);
        int n_read = read(fd,readBuf,n_write);
        printf("read %d byte,content: %s",n_read,readBuf);
        return 0;
}

运行结果:

 在此,在写入字符串到file1文件后直接读入文件内容至字符串后,发现结果与预期不符,打印结果显示未读入字符。

如何修改?出现问题与我们使用windows系统编辑word文档相同,打开文件并且在文件中写入内容后,光标会随着字符移动,当成功写入后光标移动到了末尾,若在此处开始读取内容读到的将会是后续空白的内容,因此出现这样的结果也就不足为奇了。

为了解决上述问题,需要让光标回到最开始的位置,解决方法是:1、关闭文件重新打开。 2、使用光标函数。

1、代码如下:

在写入后加入以下代码即可。

        close(fd);
        fd = open("./file1",O_RDWR);

运行结果:

 这样就完整读入file1文件的内容了。

2、使用光标移动函数操作

 描述:

 关于whence:

 SEEK_SET:表示光标位置为文件内容的开头。

SEEK_CUR:表示光标位置为当前位置。

SEEK_END:表示光标位置为文件内容的末尾。

offset:表示光标相对whence的偏移量。

返回值:若函数执行成功,则返回光标函数执行后的位置相对于文件内容开头的位置的偏移量。执行失败,则返回-1。

在读入函数前加入以下代码:

lseek(fd,0,SEEK_SET); 
lseek(fd,-(n_write),SEEK_END);
lseek(fd,-(n_write),SEEK_CUR);//任意选择一条即可。

运行结果如下:

 关于lseek()函数,还可通过该函数的返回值,反应出文件的大小。

代码如下:

int main()
{
        int fd;
        fd = open("./file1",O_RDWR);
        if(fd == -1){
                printf("open filed\n");
        }

        int len = lseek(fd,0,SEEK_END);
        printf("The file size is %d\n",len);
        close(fd);

        return 0;
}

运行结果:

可以看到显示的结果与文件运行打印的结果相同。

1.5 关于文件打开创建的补充

open函数中,关于flags三个常数中应当只指定一个。下列常数是可选择的:

        1、O_CREAT;若文件不存在则创建它。使用此选项是,同时需要说明第三个参数mode,用其说明该新文件的课存取许可权限。

        2、O_EXCL;如果同时指定了O_CREAT,而文件已经存在,则会返回-1。

        3、O_APPEND; 每次写时都加到文件的尾端。

        4、O_TRUNC;属性去打开文件是,如果用这个文件本来就是有内容的,而且为只读或只写成功打开,则将其长度截断为0。

2、该函数主要用于检验当前待创建的的文件是否已经存在,若未存在则成功创建该文件且返回一个文件描述符,若希望创建的文件已经存在,则返回值是-1。

代码如下:

int main()
{
        int fd;
        fd = open("./file1",O_RDWR);
        if(fd == -1){
                printf("open filed\n");
        }
        int test = open("./file1",O_RDWR|O_CREAT|O_EXCL,0600);
        printf("test is %d\n",test);

        close(fd);

        return 0;
}

运行结果:

 在file1已经存在的情况下,返回值为-1。

3、O_APPEND函数用于若希望往指定文件中写入内容,但是不希望将原有内容覆盖,则可以在open()函数中加入该函数。

 在file1的文件中有这样一段内容,编辑代码如下:

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

int main()
{
        int fd;
        char* buf = "This is a beutiful day!";

        fd = open("./file1",O_RDWR);

        int n_write = write(fd,buf,strlen(buf));//将该字符串写入打开的文件
        printf("write %d byte\n",n_write);
        close(fd);
        return 0;
}

查看运行的结果:

可见原先的内容已经被完全覆盖。

那若不希望将写入的内容覆盖,则可加入该函数。将代码修改后如下:

fd = open("./file1",O_RDWR|O_APPEND);

 4、使用O_TRUNC则是将原先文件中的内容全部删除后,重新写入write();函数中的内容。

在原先file1文件当中有这样的内容:

代码如下:

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

int main()
{
        int fd;
        char* buf = "Test";

        fd = open("./file1",O_RDWR|O_TRUNC);

        int n_write = write(fd,buf,strlen(buf));
        printf("write %d byte\n",n_write);
        close(fd);
        return 0;
}

结果:

 只剩下了Test。

5、创建文件creat函数

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

参数与open的第二条函数大体相同。

pathname:要创建的文件名(包含路径,缺省为当前路径)

mode:创建模式

常见的创建模式:

S_IRUSR     4    可读

S_IWUSR    2    可写

S_IXUSR     1     可执行

S_IRWXU    7     可读、可写、可执行

1.6 文件操作原理简述

关于文件描述符:

1、对于内核而言,所以打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或者创建一个新文件时,内核向进程返回一个文件描述符。当读写一个文件时,用open和creat返回的文件描述符标识该文件,将其作为参数传递给read和write。

按照惯例,UNIX shell使用文件描述符0与进程标准输入相结合,文件描述符1与标准输出相结合,文件描述符2与标准错误输出相结合。STDIN_FILEN0、STDOUT_FILEN0、STDERR_FILEN0这几个宏代替了0、1、2这几个魔术。

2、文件描述符,这个数字在一个进程中表示一个特定的含义,当我们open一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回给应用程序一个数字作为文件描述符,这个数字就和我们内存中维护的这个动态文件的这些数据结构绑定上了,以后我们应用程序如果要操作这个动态文件就只需要这个文件描述符区分。

3、文件描述符的作用域就是当前进程,出了这个进程,文件描述符就没有意义了。


文件操作的基本步骤:

打开/创建文件  读取文件/写入文件  关闭文件

我们对文件进行操作时,一定要先打开文件,打开成功之后才能操作,如果打开失败,就不能进行后边的操作了,最后读写完成后,一定要关闭文件,否则会造成文件损坏

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

打开文件以后,对这个文件的读写操作,都是针对内存中的这一份动态文件的,而并不是针对静态文件的。当然我们对动态文件进行读写以后,此时内存中动态文件和块设备文件中的静态文件就不同步了,当我们close关闭动态文件时,close内部内核将内存中的动态文件的内容去更新(同步)块设备中的静态文件。

因为块设备本身读写非常不灵活,是按块读写的,而内存是按照字节单位操作的,而且可以随时操作,很灵活。

仅为个人学习笔记!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值