Linux系统编(文件)

一.文件编程概述

1.1重点

文件编程内容超多如:
文件系统原理及访问机制
文件在内核中的管理机制
什么是文件信息节点inode
文件的共享
文件权限,各种用户对其权限

应用为王

实际上,我们只要关心如何用代码操作文件,实现文件的创建,打开,编辑等自动化执行。

1.2文件的修改

Windows/Linux下手动修改文档没有任何区别:
(1)打开/创建文档——>编辑文档——>保存文档——>关闭文档
如何自动实现文件操作:
操作系统提供了一系列的API:
如Linux系统的:
打开open
读写write/read
光标定位lseek
关闭close

二.文件的打开和创建(函数原型)

 ## Linux 命令
man 2 open

在这里插入图片描述
2.1 => open

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

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

以上权限常数只能选择一个,下列常数选择:

	O_CREAT:若文件不存在则创建它,使用时需说明第三个mode
	O_EXCL:如果同时指定了OCREAT,而文件已存在,则出错,用于判断文件是否存在
	O_APPEND每次写时都要加到文件尾部,防止覆盖前面的内容
	O_TRUNC属性去打开文件时,如果文件已有内容的,而且为只读或只写成功打开,则将其长度截短为0,把之前所有的内容干掉,再写入
 mode:以什么模式方式打开,一定是flags时,使用了O_CREAT标志,mode记录待创建文件的访问权限,0600表示可读可写权限,ls -l可以列出文件清单,查看权限
 1.可读			r			4
 2.可写			w			2
 3.可执行		x			1

2.2 => creat
pathname;文件路径,和open一样
mode:以什么方式创建,具体可以使用man命令查看

 	   S_IRWXU  00700 user (file owner) has read, write, and execute permission

       S_IRUSR  00400 user has read permission

       S_IWUSR  00200 user has write permission

文件的写入和读取

## Linux 命令
man   2  write
```![在这里插入图片描述](https://img-blog.csdnimg.cn/2a58c7a8721a41a8a26cf1a13cc2cfda.png)
fd:文件描述符
buf:你要写入的内容
count:buf的长度,指你要写入的大小
注意:write完毕后,光标在尾端

```c
man 2 read
```![在这里插入图片描述](https://img-blog.csdnimg.cn/ac569dd758454d5c852ce81af8c28956.png)
fd:文件描述符
buf:读取的内容放到buf中
count:buf的长度,指娘要读取内容的大小
注意:read是从光标的位置开始读,所以要重新打开文件,或者lseek把光标移到文件头

```c
man 2 lseek

在这里插入图片描述
fd:描述符

offset:偏移值

whence:位置,有下列三个值

SEEK_SET:文件头
       The file offset is set to offset bytes.

SEEK_CUR:当前位置
       The file offset is set to its current location plus offset bytes.

SEEK_END:文件尾
       The file offset is set to the size of the file plus offset bytes.

返回值:返回相对于文件头的偏移量

四.文件操作原理描述

4.1文件描述符

1.对于内核而言,所有打开文件都由文件描述符引用,文件描述符是一个非负整数。
2.文件描述符,这个数字在一个进程中表示一特定含义,当我们open一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回应用程序一个数字作为文件描述符,这个数字就和我们内存中维护动态文件的数据结构绑定上了,以后我们应用程序要操作这个动态文件,只需要用这个文件描述符来区分。
3.文件描述符作用域就是当前进程,出了这个进程文件描述符就没有意义了。
4.open函数打开文件,打开成功返回一个文件描述符,失败返回-1。
5.系统中默认0表示标准输入,1表诉标准输出,3表示标准错误。

4.2文件操作流程

在这里插入图片描述
1.在Linux中要操作一个文件,一般是先open打开一个文件,得到文件描述符,然后对文件进行读写操作(或其他操作),最后是close关闭文件即可。
2.只有打开成功,才能操作,读写完成,最后一定要close,否则会造成文件损坏。
3.文件平时放在快设备的文件系统中,叫静态文件。当open一个文件时,内核在进程中建立一个打开文件的数据结构,用来记录打开的文件,内核在内存申请一段内存,并将静态文件里的内容从块设备读取到内核中特定地址管理存放(动态文件)。
4.打开文件以后,我们对文件的读写操作,都是在动态文件中进行的,此时内存中的动态文件和块设备中的静态文件中的内容就不同步了,当我们close关闭文件时,close内部内核将内存中的动态文件的内容同步更新到块设备中的静态文件中去。
5.为什么不直接对块设备中的文件进行操做呢?
块设备本身的读写非常不灵活,是按块读写的,而内存是按字节单元进行操作的,而且可以随机操作,很灵活。

五.文件操作应用实例

5.1实现cp指令:cp src des

5.1.1 思路

1.命令行 先touch一个空文件file,调试用,随便写一些内容进去,再往下编辑cp指令
2. 打开源文件src,即file
3. 读取源文件中的内容到BUFF
4. 打开/创建目标文件des
5. 将BUFF写入到目标文件中去
6. close源文件和目标文件

5.1.2代码

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

int main(int argc,char **argv)
{
    
    

	int fd1;
	int fd2;
	char *buff = NULL;

	if(argc != 3){
    
    
	
		printf("parama error\n");
		exit(-1);
	
	}

	fd1 = open(argv[1],O_RDWR);

	if(fd1 == -1){
    
    
		
                printf("file not exsit\n");
                exit(-1);
	}

	int size = lseek(fd1,0,SEEK_END);
	lseek(fd1,0,SEEK_SET);

	buff = (char *) malloc(sizeof(char)*size );

	int n_read = read(fd1,buff,sizeof(char)*size);

	fd2 = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);

	int n_write = write(fd2,buff,sizeof(char)*size );

	close(fd1);
	close(fd2);



	return 0;

}

lseek是为了计算file中内容的长度,因为我们不知道file的大小,所以无法确定buff的大小,需要先计算
fd2中使用了O_TRUNC,打开目标文件时删除目标文件中的内容
## 5.1.3参数

 int main(int argc,char **argv)

argc:参数的个数,此时argc = 3
argv:数组指针,此时指向argv[0] ,argv[1], argv[2],分别对应cp src des ,他们每一项都是一个字符数组(字符串或者指针),argv是所有数组的指针,所以是二级指针

5.2修改配置文件

5.2.1 思路

1.命令行 先创建一个配置文件test.config
打开文件
读取文件中的内容到BUFF
利用strstr查找子串,找到要修改的地方,返回指针p,利用地址的连续性和p,修改配置文件
将BUFF重新写入到文件中去
close文件

5.2.2代码

test.config

speed=9
leng=9
score=9
level=9
~         

demo.c

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

int main(int argc,char **argv)
{
    
    

	int fd1;
	char *buff = NULL;

	if(argc != 2){
    
    
	
		printf("parama error\n");
		exit(-1);
	
	}

	fd1 = open(argv[1],O_RDWR);

	int size = lseek(fd1,0,SEEK_END);
	lseek(fd1,0,SEEK_SET);

	buff = (char *) malloc(sizeof(char)*size );

	int n_read = read(fd1,buff,size);

	lseek(fd1,0,SEEK_SET);

	char *p = strstr(buff,"leng=");

	if(p == NULL){
    
    
	
		printf("not found\n");

	}else{
    
    
	
		p = p+strlen("leng=");
		*p = '3';
	
	}


	int n_write = write(fd1,buff,size );

	close(fd1);


	return 0;

}

5.3写一个整数,结构体,结构体数组到文件,结构体链表,并读出来验证正确性

   #include <unistd.h>

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

5.3.1 注意

1.我们知道,write的原型第二个参数buff,是一个无类型的指针,当我们写入一个字符串到文件时,由于字符串本身也是一个指针,所以我们能够正常写入。但如果要写入其他类型的数据时,就需要传数据的地址了。
2.写结构体链表到文件时,注意文件储存在块设备中,而链表的地址是不连续的,需要遍历链表,一个个写进去。

5.3.2 写整数到文件

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

int main()
{
    
    

       int fd;
       int a = 999;
       int b;

       fd = open("./file",O_RDWR|O_CREAT,0600);

       int n_write = write(fd,&a,sizeof(int));

       lseek(fd,0,SEEK_SET);

       int n_read = read(fd,&b,sizeof(int));

       printf("a = %d,b = %d\n",a,b);

       close(fd);

       return 0;
}

执行结果

a = 999,b = 999

1.代码

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


struct test {
    
    

	int a ;
	char b ;


};




int main()
{
    
    

	int fd;
	struct test A = {
    
    666,'b'};
	struct test B;

	fd = open("./file",O_RDWR|O_CREAT,0600);

	int n_write = write(fd,&A,sizeof(struct test));

	lseek(fd,0,SEEK_SET);

	int n_read = read(fd,&B,sizeof(struct test));

	printf("B.a = %d,B.b = %c\n",B.a,B.b);

	close(fd);

	return 0;

}

运行结果

B.a = 666,B.b = b

5.3.4写结构体数组到文件

1.代码

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


struct test {
    
    

	int a ;
	char b ;


};




int main()
{
    
    

	int fd;
	struct test data1[3] ={
    
    {
    
    666,'b'},{
    
    777,'a'},{
    
    888,'c'}};
	struct test data2[3];

	fd = open("./file",O_RDWR|O_CREAT,0600);

	int n_write = write(fd,&data1,sizeof(struct test)*3);

	lseek(fd,0,SEEK_SET);

	int n_read = read(fd,&data2,sizeof(struct test)*3);

	printf("data2: %d %c   %d %c   %d %c\n ",data2[0].a,data2[0].b,data2[1].a,data2[1].b,data2[2].a,data2[2].b);

	close(fd);

	return 0;

}

运行结果

data2: 666 b   777 a   888 c
  ## 代码
#include<stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdlib.h>
#include<string.h>


struct test {
    
    

	int a ;
	char b ;
	struct test *next;


};

struct test  *writedata1(struct test *data1,int n,int fd){
    
    

	data1 = (struct test *)malloc(sizeof(struct test));
	data1->next = NULL;

	struct test *p = data1;

	while(n != 0){
    
    
	
		printf("p->a:");
		scanf("%d",&(p->a));
		printf("p->b:");
		getchar();
		scanf("%c",&(p->b));
		getchar();

		write(fd,p,sizeof(struct test));
		
		if(n >1){
    
    

			p->next = (struct test *)malloc(sizeof(struct test));
			p = p->next;
			p->next = NULL;

		}
		n = n-1;
		
	
	}

	return data1;

}

struct test  *readdata1(struct test *data2,int n,int fd){
    
    

        data2 = (struct test *)malloc(sizeof(struct test));
        data2->next = NULL;

        struct test *p = data2;

        while(n != 0){
    
    

                read(fd,p,sizeof(struct test));
		if(n>1){
    
    
			
              		 p->next = (struct test *)malloc(sizeof(struct test));
               		 p = p->next;
              		 p->next = NULL;

		}

                n = n-1;

        }

        return data2;

}


void  printfdata2(struct test *data2){
    
    

	struct test *p = data2;

	while(p != NULL){
    
    
	
		printf("p->a = %d,p->b = %c\n",p->a,p->b);

		p = p->next;
	
	}




}



int main()
{
    
    

	int fd;
	struct test *data1 = NULL;
	struct test *data2 = NULL;


	fd = open("./file",O_RDWR|O_CREAT|O_TRUNC,0600);

	data1 = writedata1(data1,3,fd);

	lseek(fd,0,SEEK_SET);

	data2 = readdata1(data2,3,fd);

	printfdata2(data2);

	close(fd);

	return 0;

}

运行结果

ztj@ubuntu:~/part2$ ./a.out
p->a:1
p->b:q
p->a:2
p->b:s
p->a:3
p->b:e
p->a = 1,p->b = q
p->a = 2,p->b = s
p->a = 3,p->b = e

六.标准C库对文件操作

6.1 open与fopen的区别

 ## 1.来源
 open:UNIX的系统调用函数,返回文件描述符,是文件的索引。
 fopen:ANSIC标准中的C语言库函数,在不同的系统调用不同的API,返回指向文件结构的指针。
## 2.移植性
open仅限于UNIX系统调用,而fopen是C语言库函数,在不同的系统环境下,可以调用不同的API,移植性强。
## 3.适用范围
open:返回文件描述符,文件描述符是UNIX系统下一个重要概念,UNIX下一切设备都是以文件的形式存在,如网络套接字,硬件设备     等,同时open也可以操作普通文件。
fopen:操作普通正规文件
## 4.文件IO层次
谁里内核近,谁就是低级IO。open运行在内核态,而fopen运行在用户态
## 5.缓冲
fopen:文件操作经过文件缓冲区(内核开辟的一个空间),内核态和用户态间的切换少,缓冲区越大,操作外存次数越少,执行速度越快,效率越高。
open:文件操作只发生在非文件缓冲系统,用户态和内核态间的切换多,借助文件结构体指针管理文件,依赖操作系统,只能读写二进制文件,但效率高,速度快。
所以,如果顺序访问文件,fopen效率更高,如果随机访问文件,则open效率更高。

6.2 fopen,fwrite,fread的使用

6.2.1fopen原型

## Linux快捷键
man 3 fopen

函数原型

在这里插入图片描述

mode权限:

r: 以 只读方式打开文件,该文件必须存在。
r+: 以可读可写方式打开文件,该文件必须存在。
w: 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
w+: 打开可读可写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
a: 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。( EOF符保留)
a+: 以附加方式打开可读可写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留 。 (原来的EOF符不保留)

注意:mode是字符串,要加”“双引号

6.2.2fwrite,fread原型

## Linux快捷键
man 3 fwrite
man 3 fread

在这里插入图片描述
##参数类别
1.ptr:你要写入/读取的内容
2.size:每次写入/读取内容的大小
3.nmemb:写/读多少次
4.stream:fopen返回值,指向文件结构的指针

6.2.3fopen,fwrite,fread (代码实例)

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

int main(){
    
    

	FILE *fp;

	int size;

	char *str = "192.168.4.12";

	char readbuf[128] = {
    
    0}; 

	fp = fopen("./file","w+");

	fwrite(str,sizeof(char),strlen(str),fp);

	size = ftell(fp);

	fseek(fp,0,SEEK_SET);

	fread(readbuf,sizeof(char),size,fp);

	puts(readbuf);
//	printf("%s\n",readbuf);

	fclose(fp);	

	return 0;

}

6.2.4注意

1.fseek()不像lseek()会返回读写位置, 因此必须使用ftell()来取得目前读写的位置.
2.fwrite的返回值,和size保持一致,fread的返回值,是实际读取的size次数

6.3补充fgetc,fpuc,feof

fgetc;从文件读取一个字符 在这里插入图片描述

2.fputc:写入一个字符到文件 在这里插入图片描述

3.feof:判断是否到达文件尾部,到达为真,即返回非零整型数 在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_48321071/article/details/124798590
今日推荐