一篇文章搞懂Linux文件操作

1、打开文件
(1)  int open(const char *pathname, int flags);//文件存在时用这种方式打开
(2)  int open(const char * pathname, int flags, mode_t mode);//不存在时用这种方式先创建再打开
2、写入文件
(3)ssize_t write(int fd, const void *buf, size_t count);
(4)close(fd)
3、读取文件
(5)ssize_t read(int fd, void *buf, size_t count);
(6)creat(const char *pathname, int flags);
4、文件内光标移动
off_t lseek(int fd, off_t offset, int whence);


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
        int fd;
        fd = open("./file2",O_RDWR);
        if(fd<0)
        {
                printf("open failed\n");
                fd = open("./file2",O_RDWR|O_CREAT,0600);
                if(fd>0)
                {
                        printf("creat file2\n");
                }
        }

        return 0;
}

打开函数:open
读写函数:write/read
光标定位:lseek
关闭:close
man 2 open:在man手册第二页查看open函数
Linux下 0是标准输入,1是标准输出,2是标准错误。
一、打开文件
(1) int open(const char *pathname, int flags):
const char *pathname:是一个字符串,表示的是要打开的文件地址;
flags:包含以下标志位
O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开文件
O_RDWR 以可读写方式打开文件. 上述三种旗标是互斥的, 也就是不可同时使用, 但可与下列的旗标利用OR(|)运算符组合.
O_CREAT: 若⽂件不存在,则创建它,需要使⽤mode选项。来指明新⽂件的访问权限。
O_EXCL:如果同时0_CREAT如果文件存在则创建失败,返回-1。
open有返回值,返回3表示打开成功,返回-1表示打开失败,定义fd为返回值,也用于read函数里面的函数索引
(2) int open(const char * pathname, int flags, mode_t mode);
mode_t mode:代表文件权限
可读:r,数字4代表
可写:w,数字2代表
可执行:x,数字1代表
二、写文件
(3)ssize_t write(int fd, const void *buf, size_t count);给fd所指向的文件写数据
fd:文件标志返回符
buf:要往fd所指向的文件写入的东西
count:写入文件的大小
写入成功函数返回往文件写入的字节数
三、关闭文件
(4)close(fd):关闭fd所指向的文件
四、读文件
ssize_t read(int fd, void *buf, size_t count);
从fd指向的文件中读取coubt个字节放入buf中
读取成功返回读到的文件大小
!!!读写文件之前必须先打开文件
五、创建文件
creat(const char *pathname, int flags);
pathname:在该路径下创建文件
flags:该文件的权限有:S_IRURE:可读
S_IWURE:可写
S_IXURE:可执行
S_IRWXU:该文件可读可写可执行

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

        fd = creat("/home/CLC/file3",S_IRWXU);

        return 0;
}

编译运行程序后我们可以在该目录下看见创建了一个名为file3的文件

六、文件偏移
off_t lseek(int fd, off_t offset, int whence);
fd:对fd所指向的文件进行光标偏移
offset:往后偏移这么多字节
count:从哪里偏移;
SEEK_SET :光标移到文件头开始偏移
SEEK_CUR:从光标当前位置开始偏移
SEEK_END:从文件末尾开始偏移
lseek返回值是从文件头到偏移到当前位置所偏移的值(反应的是文件偏移量)。
int size = lseek(fd,0,SEEK_SET);

巧妙计算文件大小
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
int main()
{
	int fd;
	fd = open("./file",O_RDWR);
	int file_size = lseek(fd,0,SEEK_END);
	printf("The file size is %d byte\n",file_size);
	return 0;
}
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 #include <unistd.h>
int main()
{
        int fd;
        char* buf = "ChenLiChen Handsome!";
        fd = open("./file",O_RDWR);
        if(fd < 0)
        {
                fd = open("./file",O_RDWR|O_CREAT,0600);
                if(fd > 0)
                {
                        printf("creat file success\n");
                }
        }
        int n_write = write(fd,buf,strlen(buf));//重新打开写入文件
        //close(fd);
        //fd = open("./file",O_RDWR);//读完文件以后光标已经移到文件末尾,(1)重新打开(2)移动光标
        lseek(fd,0,SEEK_SET);
        char* read_buf;
        read_buf = (char*)malloc(sizeof(char)*n_write);
        int n_read = read(fd,read_buf,n_write);//返回读到的字节数
        close(fd);
        printf("read %d byte contest:%s\n",n_read,read_buf);
}     

注意:!!!O_RDWD与O_APPEND在对文件写入操作时的区别的区别:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
int main()
{
	int fd;
	char* buf = "ChenLiChen Handsome!";
	fd = open("./file",O_RDWR);
	
	write(fd,buf,strlen(buf));
	close(fd);
	return 0;
}

位对file文件写入数据时,file文件里面内容是:
在这里插入图片描述

对file文件写入数据时,file文件里面内容是:
在这里插入图片描述
从这里我们看出,直接对文件写入时,默认是从文件头开始写入数据,会覆盖掉原来的信息。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
int main()
{
	int fd;
	char* buf = "ChenLiChen Handsome!";
	fd = open("./file",O_RDWR|O_APPEND);//从文件末端写入数据
	
	write(fd,buf,strlen(buf));
	close(fd);
	return 0;
}

在这里插入图片描述
O_APPEND:每次写时都加入文件的末端,不覆盖原来的数据
O_TRUNC:每次写入数据时,把原先文件截短为0,并重新写入数据

linux下有三个数作为特定返回值:
0:标准输入
1:标准输出
2:标准错误
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
        char readbuf[20];
        read(0,readbuf,10);
        write(1,readbuf,strlen(readbuf));//把readbuf里面的值写到标准输出。
        return 0;
}

!!!自己实现linux下cp指令:
我们先来了解一下main函数原型:
main 函数的标准原型应该是 int main(int argc, char *argv[]);
argc 是命令行参数的个数。而 argv 是一个指向指针的指针,为什么不是指针数组呢?因为前面讲过,函数原型中的[]表示指针而不表示数组,等价于 char **argv 。这个指针数组分别存放第1–n个命令行参数,参数不限。

#include <stdio.h>
int main(int argc,char* argv[3])
{
	printf("total params is %d\n",argc);
	printf("NO.1 Param is %s\n",argv[0]);
	printf("NO.2 Param is %s\n",argv[1]);
	printf("NO.3 Param is %s\n",argv[2]);
	return 0;
}

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

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char* argv[3])
{
	char* readbuf = {'\0'};//定义字符串初始化
	int fdDes;
	int fdSrc;
	if(argc != 3)
	{
		printf("input error\n");
		exit(-1);
	}
	fdSrc = open(argv[1],O_RDWR);//打开源文件
	int size = lseek(fdSrc,0,SEEK_END);//求文件大小
	lseek(fdSrc,0,SEEK_SET);
	readbuf = (char*)malloc(sizeof(char)*size+8);
	int n_read = read(fdSrc,readbuf,size);
	
	fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);//文件不存在就创建存在就清空。
	write(fdDes,readbuf,n_read);
	
	close(fdDes);
	close(fdSrc);
	return 0;
}

这里我们的思路是:首先了解main函数的原型;我们先打开一个源文件,利用lseek巧妙读取文件大小,再将光标移向文件头,读取源文件里面的字节放入readbuf里面,接着我们打开目标文件(打开时清空目标文件内容,没有就创建,以可读可写方式打开),将readbuf里面的内容写入目标文件。
文件操作原理:
1.在linux中要操作一个文件,一般是先open打开一个文件,得到文件描述符,然后对文件进行读写操作(或其他操作),最后是close关闭文件即可。

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

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

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

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

文件应用:
!!!接下来我们来验证一下从键盘获取标准输入然后输出。从键盘获取标准输入存到readbuf里面,把读到的文件从标准键盘输出。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char* argv[3])
{
	char readbuf[128];
	
	read(0,readbuf,5);//从键盘读取5个字节
	
	write(1,readbuf,strlen(readbuf));//输出到标准输出上

	return 0;
}

在这里插入图片描述

修改文件配置:
假如有这么一段文件:
SPEED=5;
LENG=3;
HIGH=8;
我们要修改LENG=3为LENG=5;注意写到文件里面的都是字符
我们了解一下strstr的用法:
char *strstr(const char *haystack, const char *needle);
在haystack字符串里面查找needle字符串。如果找到则返回到要找的字符串的开始位置处;查找失败返回空指针。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char* argv[2])
{
        char* readbuf;
        int fdScr;

        if(argc != 2)命令行必须输入两个操作命令
        {
                printf("input error\n");
                exit(-1);
        }
        
        fdScr = open(argv[1],O_RDWR);
        int size = lseek(fdScr,0,SEEK_END);//lseek反应的是文件偏移量
        lseek(fdScr,0,SEEK_SET);//光标重新移到文件头
        readbuf = (char*)malloc(sizeof(char)*size);//而readbuf需要开辟(偏移量*字节数)
        read(fdScr,readbuf,size*sizeof(char));//把目标文件读到readbuf里面

        char* p = strstr(readbuf,"LENG=");//在目标文件里面查找“LENG=”字符
        if(p == NULL)
        {
                printf("Not Found\n");
                exit(-1);
        }
        p = p + strlen("LENG=");//如果找到该字符串,则strstr函数返回该字符串开始的位置,我们让该字符串偏移到我们想要的位置
        *p = '9';//修改我们需要的文件配置,以上均是把静态数据区的文件复制到动态数据区,修改以后的值是在动态数据区的readbuf,文件里面存的都是字符
        lseek(fdScr,0,SEEK_SET);//光标移到文件头
        write(fdScr,readbuf,strlen(readbuf));//把readbuf里面的值重新写到该文件从头覆盖
        close(fdScr);//关闭该文件,并将数据同步更新到源文件
        return 0;
}


这是修改文件配置前文件的内容。
在这里插入图片描述
修改文件后文件的内容:
在这里插入图片描述

文件缓冲区不止会写字符,也会写数字,只会影响人类的判断,不会影响机器的判断。

但是文件内部却是这样的,因为我们查看文件时,看到的都是字符,这里我们写入的是真实的数字,读取时也是%d格式打印的数字,影响了人类的判断,机器却能认识。
!!!C语言中文件的操作:
fopen与open的区别:
fopen具有很好的移植性,是C标准函数;open是unix下的系统调用函数,移植性有限。
fopen配套fwrite,fread一起使用;open配套write,read一起使用。不能互相使用。

FILE *fopen(const char *path, const char *mode);//返回的是文件标识符
fopen函数用的是标准C语言库,第一个参数是文件路径,第二个参数是文件权限。
r:以只读方式打开文件,该文件必须存在。
r+:以读/写方式打开文件,该文件必须存在。
rb+:以读/写方式打开一个二进制文件,只允许读/写数据。
rt+:以读/写方式打开一个文本文件,允许读和写。
w:打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。
w+:打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。
a:以附加的方式打开只写文件。若文件不存在,则会创建该文件;如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF 符保留)。
a+:以附加方式打开可读/写的文件。若文件不存在,则会创建该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF符不保留)。
wb:以只写方式打开或新建一个二进制文件,只允许写数据。
wb+:以读/写方式打开或新建一个二进制文件,允许读和写。
wt+:以读/写方式打开或新建一个文本文件,允许读和写。
at+:以读/写方式打开一个文本文件,允许读或在文本末追加数据。
ab+:以读/写方式打开一个二进制文件,允许读或在文件末追加数据。

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
参数一:要往文件写入的内容,是字符串格式
参数二:一次写入的字节数
参数三:写多少次
参数四:目标文件标识符

下面我们来写一个用fopen、fread、fwrite、fseek来给一个文件写入结构体。

#include <stdio.h>
#include <string.h>
struct data
{
        int a;
        char b;
};
int main()
{
        struct data test2 = {1,'q'};
        struct data test1;
        FILE* fp;
        fp = fopen("./file2","w+");//返回文件标识符
        int n_write = fwrite(&test2,sizeof(struct data)*2,1,fp);//每次写多少数据
,写多少次
        fseek(fp,0,SEEK_SET);//光标移到文件头
        int n_read = fread(&test1,sizeof(struct data)*2,1,fp);
        fclose(fp);
        printf("fwrite is return %d\n",n_write);
        printf("fread is return %d\n",n_read);
        printf("test1.a = %d test1.b = %c\n",test1.a,test1.b);
        return 0;
}

前面我们验证过unix下我们可以通过读写往文件写入一个结构体数组,这里使用C语言环境进行代码编写,却不可以了这个我们进行后续研究。
fwrite、fread均是在目标文件中进行读写,返回值是读写的次数,这里有两种读写的方式;
(1)可以读写一次,一次读写完全部的数据
(2)可以一次写入一个数据类型大小,读写n次

文件操作中其他API:
fputc(str,fp),往目标文件写入一个字符。

#include <stdio.h>
#include <string.h>

int main()
{
	char a = 'A';
	FILE* fp = fopen("./qaz","w+");
	fputc(a,fp);
	return 0;
}

往目标文件写入一个字符串:

#include <stdio.h>
#include <string.h>

int main()
{
	char* str = "chenlichen shuai o !";
	int i;
	FILE* fp = fopen("./qaz","w+");
	int len = strlen(str);
	for(i=0;i<len;i++)
	{
		fputc(*str,fp);//每次往目标文件写入一个字符
		str++;//写完一个字符++
		
	}
	return 0;
}

feof(fp)//没到达文件末尾,返回值是0,到达文件末尾,返回值不为0
从文件每次读取一个字符打印出来,

#include <stdio.h>
#include <string.h>

int main()
{
	FILE* fp = fopen("./qaz","r");//以只读方式打开文件
	int i;
	char c;
	while(!feof(fp))
	{
		c = fgetc(fp);//每次从文件里面读取一个字符存到c,读完以后自动后移
		printf("%c",c);
	}
	fclose(fp);
	return 0;
}
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux系统中,inotify是一种文件系统监控机制,它可以检测文件系统事件的发生,例如文件的创建、修改、删除等等。在本篇文章中,我们将介绍如何使用inotify-tools库来实现对文件dump路径的实时监控,并且将其写成一个经验案例。 ## 准备工作 在开始之前,我们需要先安装inotify-tools库。在Ubuntu系统中,你可以使用以下命令进行安装: ```bash sudo apt-get install inotify-tools ``` ## 编写脚本 打开你的终端,使用你最喜欢的文本编辑器创建一个脚本文件。在这个例子中,我们将使用Bash脚本来进行实现。在你的脚本中添加以下内容: ```bash #!/bin/bash # 监控dump目录下的文件变化 while true; do inotifywait -r -e modify,create,delete /path/to/dump/ # 在这里执行你需要执行的操作 done ``` 这个脚本将会实时监控`/path/to/dump/`目录下的文件变化,并且只会关注modify、create和delete事件。当有任何文件发生变化时,脚本将会执行你需要执行的操作。 ## 运行脚本 保存你的脚本文件,使用终端将其运行起来: ```bash ./your_script.sh ``` 现在,你的脚本将会一直运行,实时监控`/path/to/dump/`目录下的文件变化。如果有任何文件发生变化,脚本将会执行你需要执行的操作。 ## 总结 在本篇文章中,我们介绍了如何使用inotify-tools库来实现对文件dump路径的实时监控。你可以根据你的实际需求来修改这个脚本,并且可以将其加入到系统的自启动脚本中,以便在系统启动时自动启动这个脚本。inotify是一个非常有用的工具,它可以帮助我们监控文件系统的变化,并且在文件发生变化时进行相应的处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

￴ㅤ￴￴ㅤ9527超级帅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值