欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

linux下文件的读写操作讲解(及open函数的flags讲解)

程序员文章站 2024-01-23 18:38:52
...

1.文件的读写代码演示:

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

int main(void)
{
        int fd = -1;
        char readBuf[100] = {0};
        char read2Buf[100] = {0};
        char writeBuf[100] = "I love linux";
        int ret = 0;

        //第一步:打开文件
        //int open(const char *pathname, int flags);
        //int open(const char *pathname, int flags, mode_t mode);

        fd = open("a.txt",O_RDWR);
        if(-1 == fd)
        {
                printf("文件打开失败\n");
			_exit(-1);	
        }
        else
        {
                printf("打开成功\n");
                printf("fd = %d\n",fd);
        }

        //第二步:读文件
        //ssize_t read(int fd, void *buf, size_t count); 
        //fd表示要读取那一个文件
        //buf是应用程序自己提供的一段内存缓冲区,用来存储文件的内容
        //count是我们要读取的字节数
        //返回值ssize_t类型是内核用typedef重定义的一个类型(就是int)返回值表示成功读取的字节数
        ret = read(fd,readBuf,20);
        if(ret == -1)
        {
                printf("读取失败\n");
                _exit(-1);
        }
        else
		{
                printf("实际读取了%d个字节\n",ret);
                printf("读取文件的内容是:%s\n",readBuf);
        }

        //第三步:写文件
        //ssize_t write(int fd, const void *buf, size_t count);
        ret = write(fd,writeBuf,strlen(writeBuf));
        if(ret < 0)
        {
                printf("写入失败\n");
                _exit(-1);
        }
        else
        {
                printf("写入了%d个字节\n",ret);
                printf("写入的内容是%s\n",writeBuf);

        }

        //移动光标
        //off_t lseek(int fd, off_t offset, int whence);
        lseek(fd,0,0);

        ret = read(fd,readBuf,30);
        if(ret == -1)
        {
                printf("读取失败\n");
                _exit(-1);
        }
        else
        {
                printf("实际读取了%d个字节\n",ret);
                printf("读取文件的内容是:%s\n",read2Buf);
        }


        //第四步:关闭文件
        //int close(int fd);
        close(fd);
        printf("文件关闭\n");

        return 0;
}

注意:这里open的flags是指对文件操作的权限O_RDWR(可读可写)、O_RDONLY(只读)、O_WRONLY(只写)。

2.当打开一个已经存在并且内部有内容的文件时会怎么样?
(1)O_TRUNC属性去打开一个这样的文件时,原来文件中的内容会被丢弃。
(2)O_APPEND属性去打开一个这样的文件时,新写入的内容会在原有内容的后面。如果这两个属性同时出现,会将原有的内容删除,只打印当前写入的内容。

3.当打开一个文件时并不存在应该怎么办?
属性O_CREAT就是解决办法,当打开这个文件不存在时他会帮你创建并打开这个文件。如果这个文件已经存在,则会重新创建这个文件,原有的内容可能被消除。(这样可能会造成不好的效果,这时属性O_EXCL和O_CREAT结合使用就会避免这个错误,没有这个文件时就会创建这个文件,这个文件已经存在则会报错)。且当使用O_CREAT这个属性时open的第三个参数mode位就会给这个文件赋值相应的权限。

4.当我们程序中途出错时我们应该用exit、_exit、_Exit退出程序。
在main函数中一般用return 0;表示程序正常终止,return-1;表示程序异常终止。
正式终止进程(程序):应该使用exit或_Exit或_exit他们包含的头文件不同,用man手册查找。

5.阻塞与非阻塞(O_NONBLOCK)
(1)阻塞式:我们调用这个函数时,当前进程有可能被卡住,,实质就是函数内部要完成的事情条件不具备,要等条件成熟,这时函数不能被立即返回。
(2)非阻塞:调用这个函数后立即返回,但是函数任务是否完成不确定。
(3)操作系统提供的API和由API封装成的库函数,有些是阻塞式有些是非阻塞式,我们调用时应该要清楚。如果我们打开一个文件默认是阻塞式,但是我们希望以非阻塞方式打开,则flags中加O_NONBLOCK属性。这个属性只用于设备文件,而不用于普通文件。

6.O_SYNC
(1)write阻塞等待底层完成写入才返回到应用层
(2)无O_SYNC只是将内容写到底层缓冲区即可返回,底层就是负责实现open、write、这些操作的代码,也包含了OS中读写硬盘底层硬件的代码,在合适的时候将buf中的内容一次性同步到硬盘中,这种设计为了提升硬件操作的性能和寿命,当我们希望硬件不等待,直接将我们的内容写到硬盘中时,就可以调用O_SYNC标志;