Linux系统编程—文件

news2024/12/24 2:59:09

一、文件编程概述

之前在windows中对文件的操作是:打开文档——>编辑文档——>保存文档——>关闭文档

我们的Linux文件编程主要是利用代码对文件进行操作:文件创建、打开、编辑等自动化执行等

在Linux我们要使用编程调用api函数的方式进行文档的编辑:

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

 

二、文件打开与创建

2.1 文件打开创建函数open原型和头文件:

/*
	Linux下:man 2 open可以查看对应手册
*/
#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);

返回值     文件描述符
pathname (含路径,缺省为当前路径)
flags     权限 O_RDONLY:只读打开        O_WRONLY:只写打开        O_RDWR:可读可写打开
mode 	  权限模式
1.可读:        r         4
2.可写:        w         2
3.可执行        x         1
0600:6代表4+2(可读可写)

2.2 open函数打开一个文件:

  • 利用open函数打开file1文件,如果文件存在则返回3,否则返回-1

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

int main()
{
	int fd;

	fd = open("./file1",O_RDWR);
	
	printf("fd = %d\n",fd);
	return 0;
}

 

我们刚开始touch了一个file1文件,用open函数可以打开这个文件,返回3

我们rm删除了file1文件,用open函数打开这个文件就失败了,返回-1

2.3 open函数打开文件失败创建一个文件:

  • 使用open函数打开file1文件失败后,就创建一个file1文件

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

int main()
{
	int fd;

	fd = open("./file1",O_RDWR);					//使用open函数打开file1文件
	if(fd == -1){									//如果打开失败
		printf("file1 no failed\n");				//输出文件1号失败	
		fd = open("./file1",O_RDWR|O_CREAT,0600);	//文件不存在则创建它,需要同时说明第三个参数mode,权限为可读可写
		if(fd > 0){
			printf("create file1 success!\n");		//若文件描述符>0则代表创建文件成功!
		}
	}
		
	return 0;
}

最终我们可以看到创建file1文件成功!

//我们创建的file1文件权限为:可读可写
查看文件权限指令:ls -l
r 代表“可读”
w 代表“可写”
x 代表“可执行”
    
mode       权限模式
1.可读:        r         4
2.可写:        w         2
3.可执行        x         1
0600:6代表4+2(可读可写)

2.4 查看文件是否存在:

/*O_EXCL如果同时指定了O_CREAT,而文件已经存在,那么打开文件失败*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main()
{
	int fd;

	fd = open("./file1",O_RDWR|O_CREAT|O_EXCL,0600);
	if(fd == -1){				//如果O_EXCL和O_CREAT同时使用时,文件已经存在就返回-1代表文件存在
		printf("file cunZai\n");
	}
	return 0;
}

2.5 每次写内容都到文件的尾部:

当前我们file1文件中的内容是:

如果直接往里面添加内容会出现错误,会从头开始添加,我们不希望破坏之前的内容,我们可以在open函数的可读可写权限后面或上O_APPEND

/*O_APPEND 每次写时都加到文件的尾端*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

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

	fd = open("./file1",O_RDWR|O_APPEND);	//添加O_APPEND后写入的内容就会从file1文件的尾部添加

	printf("open susceess:fd = %d\n",fd);

	//size_t write(int fd, const void *buf, size_t count);
	int n_write = write(fd,buf,strlen(buf));		 		//将buf中的内容写入到fd对应的文件中
    if(n_write != -1){										//如果函数返回值不是-1代表写入成功
		printf("success write %d byte to file1\n",n_write);	//输出写入到file1文件中多少个自己
	}
	
	close(fd);										//关闭刚写入的文件
	return 0;
}

2.6 O_TRUNC打开已有内容的文件并删除所有内容:

当前我们file1文件中的内容是:

O_TRUNC 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0

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

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

	fd = open("./file1",O_RDWR|O_TRUNC);	//O_TRUNC打开已有内容的文件并删除所有内容

	printf("open susceess:fd = %d\n",fd);

	//size_t write(int fd, const void *buf, size_t count);
	int n_write = write(fd,buf,strlen(buf));		 		//将buf中的内容写入到fd对应的文件中
    if(n_write != -1){										//如果函数返回值不是-1代表写入成功
		printf("success write %d byte to file1\n",n_write);	//输出写入到file1文件中多少个自己
	}
	
	close(fd);										//关闭刚写入的文件
	return 0;
}

我们可以看到使用O_TRUNC打开已有内容的文件,会将文件中的内容全部删除,我们又重新写入了test内容

2.7 文件创建creat函数原型和头文件:

/*
	Linux下:man creat可以查看对应手册
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

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

返回值		  	  文件描述符
pathname		  要创建的文件名(含路径、缺省为当前路径)	
mode_t mode       创建模式
   宏表示   数字    
1.S_IRUSR	4	可读
2.S_IWUSR	5	可写
3.S_IXUSR	1	可执行
4.S_IRWXU	7	可读、可写、可执行   

2.8 使用creat函数创建一个文件:

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

int main()
{
	int fd;
	
	fd = creat("/home/CLC/file1",S_IRWXU);	//使用creat函数在绝对路径下创建了file1文件,权限为可读、可写、可执行
	printf("creat file:fd = %d\n",fd);		//文件描述符
	return 0;
}

三、文件写入操作编程

3.1 文件写入函数write和文件关闭函数close原型和头文件:

/*
	Linux下:man 2 write可以查看对应手册
*/

#include <unistd.h>

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

int fd 		     写入到刚打开的文件中
const void *buf  无符号类型的字符缓冲区
size_t count     写入的字节大小
ssize_t          若成功写入文件,函数返回值为写入字节个数,若失败,返回-1。
    
/*
	Linux下:man 2 close可以查看对应手册
*/
 
#include <unistd.h>
    
int close(int fd);

int fd           关闭刚写入的文件,一般在写入文件后执行文件的关闭

3.2 对文件写入内容:

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

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

	fd = open("./file1",O_RDWR);					//使用open函数打开file1文件		
	if(fd == -1){									//如果打开失败
		printf("file1 no failed\n");				//输出文件1号失败	
		fd = open("./file1",O_RDWR|O_CREAT,0600);	//文件不存在则创建它,需要同时说明第三个参数mode,权限为可读可写
		if(fd > 0){
			printf("create file1 success!\n");		//若文件描述符>0则代表创建文件成功!
		}
	}
	printf("open susceess : fd = %d\n",fd);			//输出创建或者打开的文件的文件描述符
    
	//ssize_t write(int fd, const void *buf, size_t count);
	int n_write = write(fd,buf,strlen(buf));		 		//将buf中的内容写入到fd对应的文件中
    if(n_write != -1){										//如果函数返回值不是-1代表写入成功
		printf("success write %d byte to file1\n",n_write);	//输出写入到file1文件中多少个自己
	}
	
	close(fd);										//关闭刚写入的文件
	return 0;
}

通过open函数成功打开了file1文件,并将内容chenlichen handsom(19个字节)写入到文件中

 

 通过open函数打开file1文件失败后,创建了一个file1文件,创建的文件文件描述符是3,并将内容chenlichen handsome(19个字节)写入到文件中

四、文件读取操作编程

4.1 文件读取函数read函数原型和头文件:

/*
	Linux下:man 2 read可以查看对应手册
*/

#include <unistd.h>

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

fd				文件描述符
void *buf		待读入缓冲区
size_t count	读出字节个数
ssize_t			若成功读取文件,函数返回值为读出字节个数,若失败,返回-1 
    
read函数作用:从fd指向的文件读取count个字节的数据放到buf缓冲区里面

4.2 使用read函数读取文件中的内容:

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

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

	fd = open("./file1",O_RDWR);							//使用open函数打开file1文件		
	if(fd == -1){											//如果打开失败
		printf("file1 no failed\n");						//输出文件1号失败	
		fd = open("./file1",O_RDWR|O_CREAT,0600);	//文件不存在则创建它,需要同时说明第三个参数mode,权限为可读可写
		if(fd > 0){
			printf("create file1 success!\n");				//若文件描述符>0则代表创建文件成功!
		}
	}
	printf("open susceess : fd = %d\n",fd);					//输出创建或者打开的文件的文件描述符
    
	//ssize_t write(int fd, const void *buf, size_t count);
	int n_write = write(fd,buf,strlen(buf));		 		//将buf中的内容写入到fd对应的文件中
    if(n_write != -1){										//如果函数返回值不是-1代表写入成功
		printf("success write %d byte to file1\n",n_write);	//输出写入到file1文件中多少个自己
	}

	char *readBuf;

	readBuf = (char *)malloc(sizeof(char) * n_write + 1);	//写入了多少个字节就开辟多少个字节的空间
	//ssize_t read(int fd, void *buf, size_t count);
	int n_read = read(fd,readBuf,n_write);			//从fd指向的文件读取n_write个字节的数据放到readBuf缓冲区里面

	printf("read %d,context:%s\n",n_read,readBuf);			//读取了多少字节,读取到文件中的内容
	close(fd);												//关闭文件
	return 0;
}

我们可以看到我们向file1文件中写入了chenlichen handsome,但是使用read函数读取文件中的内容到readBuf中,但是读取到的字节为0,并且也没有读取到内容,这是因为我们往file1文件中写入了chenlichen handsome后,文件中光标的位置已经到了尾巴,如果想要读取成功需要将光标移动到头,后面再使用此方法

这次我们这样:把写入内容到file1文件中后把文件关闭,读取的时候再重新的打开

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

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

	fd = open("./file1",O_RDWR);							//使用open函数打开file1文件		
	if(fd == -1){											//如果打开失败
		printf("file1 no failed\n");						//输出文件1号失败	
		fd = open("./file1",O_RDWR|O_CREAT,0600);	//文件不存在则创建它,需要同时说明第三个参数mode,权限为可读可写
		if(fd > 0){
			printf("create file1 success!\n");				//若文件描述符>0则代表创建文件成功!
		}
	}
	printf("open susceess : fd = %d\n",fd);					//输出创建或者打开的文件的文件描述符
    
	//ssize_t write(int fd, const void *buf, size_t count);
	int n_write = write(fd,buf,strlen(buf));		 		//将buf中的内容写入到fd对应的文件中
    if(n_write != -1){										//如果函数返回值不是-1代表写入成功
		printf("success write %d byte to file1\n",n_write);	//输出写入到file1文件中多少个自己
	}

	close(fd);												//往file1文件中写入内容成功后“关闭文件”
	fd = open("./file1",O_RDWR);							//读取前重新打开,目的就是让光标回到头

	char *readBuf;

	readBuf = (char *)malloc(sizeof(char) * n_write + 1);	//写入了多少个字节就开辟多少个字节的空间
	//ssize_t read(int fd, void *buf, size_t count);
	int n_read = read(fd,readBuf,n_write);			//从fd指向的文件读取n_write个字节的数据放到readBuf缓冲区里面

	printf("read %d,context:%s\n",n_read,readBuf);			//读取了多少字节,读取到文件中的内容
	close(fd);	
	return 0;
}

使用这种方式让光标回到头还是比较“蠢”的,关于光标回到头还是有更好的方式的,下次再解决!

五、文件光标移动操作

5.1 文件光标移动函数lseek函数原型和头文件:

/*
	Linux下:man 2 lseek可以查看对应手册
*/

#include <sys/types.h>
#include <unistd.h>

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

off_t			若成功移动光标,函数返回值为光标移动个数,若失败,返回-1
fd				文件描述符
off_t offset	针对whence光标偏移个数 
int whence		光标的绝对位置        
1.SEEK_SET  文件头	      The offset is set to offset bytes.	
2.SEEK_CUR  光标当前位置	The offset is set to its current location plus offset bytes.	
3.SEEK_END  文件内容末尾	The offset is set to the size of the file plus offset bytes.
				
lseek函数作用:将文件读写指针相对whence移动offset个字节

5.2 使用lseek函数对文件进行操作:

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

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

	fd = open("./file1",O_RDWR);							//使用open函数打开file1文件		
	if(fd == -1){											//如果打开失败
		printf("file1 no failed\n");						//输出文件1号失败	
		fd = open("./file1",O_RDWR|O_CREAT,0600);	//文件不存在则创建它,需要同时说明第三个参数mode,权限为可读可写
		if(fd > 0){
			printf("create file1 success!\n");				//若文件描述符>0则代表创建文件成功!
		}
	}
	printf("open susceess : fd = %d\n",fd);					//输出创建或者打开的文件的文件描述符
    
	/*ssize_t write(int fd, const void *buf, size_t count); write函数原型*/
	int n_write = write(fd,buf,strlen(buf));		 		//将buf中的内容写入到fd对应的文件中
    if(n_write != -1){										//如果函数返回值不是-1代表写入成功
		printf("success write %d byte to file1\n",n_write);	//输出写入到file1文件中多少个自己
	}

	char *readBuf;
	readBuf = (char *)malloc(sizeof(char) * n_write + 1);	//写入了多少个字节就开辟多少个字节的空间

	/*off_t lseek(int fd, off_t offset, int whence); lseek函数原型*/
	lseek(fd,0, SEEK_SET);		//将光标移动到头
//	lseek(fd,-19, SEEK_END);	//将光标从尾巴移动到头
//	lseek(fd,-19, SEEK_CUR);	//将光标从当前位置移动到头
    
	/*ssize_t read(int fd, void *buf, size_t count); read函数原型*/
	int n_read = read(fd,readBuf,n_write);			//从fd指向的文件读取n_write个字节的数据放到readBuf缓冲区里面

	printf("read %d,context:%s\n",n_read,readBuf);			//读取了多少字节,读取到文件中的内容
	close(fd);	
	return 0;
}

针对于我们读取文件时遇到的问题,我们通过lseek函数将光标移动到头,成功读取到file1文件中的内容

5.3 使用lseek函数可以的巧妙的计算文件大小:

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

int main()
{
	int fd;

	fd = open("./file1",O_RDWR);				//使用open函数打开file1文件	

	int filesize = lseek(fd, 0, SEEK_END);		//使用lseek函数计算file1文件的大小
	printf("file's size is :%d\n",filesize);	//打印输出

	close(fd);									//关闭文件
	return 0;
}

我们使用ls -l指令可以查看到file1文件的大小是19个字节,我们调用lseek函数可以巧妙的查看文件的大小

六、文件操作原理简述

文件编程的一般步骤:

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

 

Linux文件管理简述:

 

七、文件编程练手(一)实现copy指令(面试)

7.1 copy指令在Linux下的应用:  

copy 指令在Linux系统是一个常用的指令,就是这样用:

cp demo4.c demo13.c

其中 copy是指令,demo4.c是源文件,demo13.c是目标文件,下面我们就来编程

7.2 main函数的参数:

/*main函数参数功能*/
int main(int argc,char **argv)
    
int argc		argc 表示运行C文件参数的个数
char **argv 	argv是字符数组指针,每个指针都是一个数组,在这里表示每个参数的内容

下面我们验证一下:

#include <stdio.h>

int main(int argc, char **argv)
{
	printf("total params: %d\n",argc);		//C文件参数个数有三个
	printf("No.1 params: %s\n",argv[0]);	//第一个
	printf("No.2 params: %s\n",argv[1]);	//第二个
	printf("No.3 params: %s\n",argv[2]);	//第三个
	return 0;
}

我们搞清楚main函数的参数是:./a.out src des
这样我们就可以把文件名传进去进行响应的拷贝操作如:cp demo13.c new.c

7.3 文件编程实现copy指令:

用文件编程实现copy指令的编程思路:

  1. 打开源文件src.c

  2. 读源文件src.c到buf

  3. 打开/创建目标文件des.c

  4. 将buf写入到目标文件des.c

  5. 关闭两个文件

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

int main(int argc, char **argv)
{
	int fdSrc;
	int fdDes;

	char *readBuf = NULL;
	
	if(argc != 3){										//判断C文件参数是不是有三个,如果不是程序退出
		printf("param error\n");
		exit(-1);
	}

	fdSrc = open(argv[1],O_RDWR);						//打开源文件demo13.c
	
	int size = lseek(fdSrc,0, SEEK_END);				//计算源文件有多少个字节
	lseek(fdSrc, 0, SEEK_SET);							//让源文件光标回到头
	
	readBuf = (char *)malloc(sizeof(char) * size + 8);	//动态开辟readBuf的内存空间

	int n_read = read(fdSrc,readBuf,size);				//把源文件的size个字节的内容读取到readBuf里面

	fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);	//打开目标文件new.c,如果打开失败就创建目标文件new.c
														//如果存在目标文件,就把文件中的内容全部干掉,否则会出错
	int n_write = write(fdDes,readBuf,strlen(readBuf));	//将readBuf里面的内容写入到目标文件new.c中

	close(fdSrc);										//关闭源文件
	close(fdDes);										//关闭目标文件
	return 0;
}

我们可以看到打开我们cp的new.c文件,和源文件demo13.c内容是一模一样的,这样就使用文件编程实现了copy指令

八、文件编程练手(二)修改程序的配置文件(工作常用)

在工作中我们经常会遇到修改配置文件相关的问题,比如以下配置文件:

我们要把LENG修改成5,我们该怎么办呢?

8.1 使用文件编程修改配置文件的指定内容:

编程思路:

  1. 打开配置文件

  2. 读出配置文件内容

  3. 找到LENG字符串的起始位置

  4. 偏移LENG的长度,偏移到数据位置

  5. 更改数据位置的值

  6. 把读出的内容重新写入配置文件

  7. 关闭文件

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

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

	char *readBuf = NULL;
	
	if(argc != 2){											//判断C文件参数是不是有两个,如果不是程序退出
		printf("param 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);		//动态开辟readBuf的内存空间

	int n_read = read(fdSrc,readBuf,size);					//把配置文件的size个字节的内容读取到readBuf里面

	//char *strstr(const char *haystack, const char *needle);
	char *p = strstr(readBuf,"LENG=");				//字符串查找函数,返回值为要查找的字符串的第一个字符的指														      针,第一个参数为待查找的原始字符串,第二个参数为要查找的内容
	p = p + strlen("LENG=");									//偏移LENG的长度,偏移到数据位置
	*p = '5';													//更改数据位置的值

	lseek(fdSrc, 0, SEEK_SET);									//让配置文件光标回到头

	int n_write = write(fdSrc,readBuf,strlen(readBuf));			//把读出的内容重新写入配置文件

	close(fdSrc);												//关闭配置文件
	return 0;
}

8.2 字符串比较函数strstr原型和头文件:

/*
	Linux下 man strstr可以查看对应手册
*/
#include <string.h>

char *strstr(const char *haystack, const char *needle);		//字符串查找函数

char *					返回值为要查找的字符串的第一个字符的指针
const char *haystack	待查找的原始字符串
const char *needle		为要查找的内容  

 

九、写一个整数、结构体和结构体数组到文件

前面我们都是写字符串到文件中,那可不可以写入整数或者结构体呢?

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

这两个是写and读的函数原型,我们可以发现第二个参数都是:void *buf
这样我们即可以写入字符串,又可以将整数或者结构体的地址传递过去,进行读和写

9.1 写一个整数到文件:

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

int main()
{
	int fd;
	int data = 100;
	int data2;

	fd = open("./file1",O_RDWR);							//打开file1文件

	//size_t write(int fd, const void *buf, size_t count);
	int n_write = write(fd,&data,sizeof(int));				//写整数100到文件

	lseek(fd, 0, SEEK_SET);									//写完之后,光标回到文件头
	//ssize_t read(int fd, void *buf, size_t count);
	int n_read = read(fd,&data2,sizeof(data2));				//把file1文件中的内容读4个字节到data2中

	printf("read %d\n",data2);								//输出读取的结果
	close(fd);
	return 0;
}

成功向file1文件中写入了一个整数,并且把文件中的整数读取到了data2中,最终输出结果

打开我们发现是乱码的,是因为整数在文件中的体现方式并不是我们肉眼看到的那样,只要程序可以成功写入/读取即可

9.2 写一个结构体到文件:

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

struct Test
{
	int idata;
	char cdata;
};

int main()
{
	int fd;
	struct Test t1 = {100,'#'};								//定义一个结构体变量并赋初值
	struct Test t2;

	fd = open("./file1",O_RDWR);							//打开file1文件

	//size_t write(int fd, const void *buf, size_t count);
	int n_write = write(fd,&t1,sizeof(struct Test));		//写一个结构体到文件中

	lseek(fd, 0, SEEK_SET);									//写完之后,光标回到文件头
	//ssize_t read(int fd, void *buf, size_t count);
	int n_read = read(fd,&t2,sizeof(struct Test));			//读文件中的结构体到t2中

	printf("read t2 = %d,%c\n",t2.idata,t2.cdata);			//输出读取的结果
	close(fd);												//关闭文件
	return 0;
}

成功向file1文件中写入了一个结构体,并且把文件中的结构体读取到了t2中,最终输出结果

9.3 写一个结构体数组到文件:

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

struct Test
{
	int idata;
	char cdata;
};

int main()
{
	int fd;
	int i;
	struct Test arr1[2] = {									//定义一个arr1结构体数组并初始化

		{100,'#'},
		{200,'$'}
	};
	struct Test arr2[2];									//定义一个arr2结构体数组并初始化
	
	int arr1Size = sizeof(arr1) / sizeof(arr1[0]);			//计算arr1结构体数组的元素个数
	int arr2Size = sizeof(arr2) / sizeof(arr2[0]);			//计算arr2结构体数组的元素个数
		
	fd = open("./file1",O_RDWR);							//打开file1文件

	//size_t write(int fd, const void *buf, size_t count);
	int n_write = write(fd,&arr1,sizeof(struct Test) * arr1Size);	//把arr1结构体数组写到文件中

	lseek(fd, 0, SEEK_SET);											//写完之后,光标回到文件头
	//ssize_t read(int fd, void *buf, size_t count);
	int n_read = read(fd,&arr2,sizeof(struct Test) * arr2Size);		//把写入文件中的结构体数组读取到arr2中

	for(i=0; i<2; i++){	
		printf("read arr2 = %d,%c\n",arr2[i].idata,arr2[i].cdata);	//输出读取到的值
	}
	close(fd);														//关闭文件
	return 0;
}

成功向file1文件中写入了一个结构体数组,并且把文件中的结构体数组读取到了arr2中,最终输出结果

十、标准C库对文件操作引入

fopen与open的区别

1、来源不同 open是unix系统调用函数(包括Linux),返回的是文件描述符,它是文件描述符表里的索引。 fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调不同的内核api,返回的是一个指向文件结构的指针。

2、移植性 从来源看,fopen是C标准函数,因此拥有良好的移植性,而open是unix系统调用,移植性有限,如windows下相似的功能使用api函数CreatFile。

3、使用范围 open返回文件描述符,而文件描述符是unnix系统下的重要概念,unix下的一切设备都是文件的形式操作,如网络套接字、硬件设备等、当然包括操作普通正规文件(Regular File) Fopen是从来操纵普通正规文件(Regular File)的

4、 文件IO层次 如果从文件IO的角度来看,open属于低级IO函数,fopen属于高级IO函数,低级和高级的简单区分标准是:谁离系统内核更近,低级文件IO运行在内核态、高级文件IO运行在用户态。

5、 缓冲区 open没缓冲区(多次在用户态和内核态切换,执行速度慢,效率低),fopen有缓冲区(在缓冲区读写后一次性写入文件,执行速度快,效率高)

更多详细介绍观看此路径https://www.cnblogs.com/NickyYe/p/5497659.html,念这些啰里啰唆的概念不是我的风格!!!

主打的就是一个拽!!!

十一、标准C库打开创建文件读写关闭文件和光标移动

11.1 打开创建文件函数fopen函数原型和头文件:

/*
	Linux下 man fopen查看手册
*/
#include <stdio.h>

FILE *fopen(const char *path, const char *mode);

FILE *				返回值并不是文件描述符,若失败返回NULL,若操作成功返回FILE指针
const char *path	文件路径
const char *mode	打开方式
    
mode 打开模式:
r	只读方式打开一个文本文件
rb	只读方式打开一个二进制文件
w	只写方式打开一个文本文件
wb	只写方式打开一个二进制文件
a	追加方式打开一个文本文件
ab	追加方式打开一个二进制文件
r+	可读可写方式打开一个文本文件
rb+	可读可写方式打开一个二进制文件
w+	可读可写方式创建一个文本文件
wb+	可读可写方式生成一个二进制文件
a+	可读可写追加方式打开一个文本文件
ab+	可读可写方式追加一个二进制文件

11.2 文件写入函数fwrite函数原型和头文件:

/*
	Linux下 man fwrite查看手册
*/
#include <stdio.h>

size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

size_t				返回值若成功写入文件,函数返回值为写入次数(函数第三个参数),若失败,返回非写入字节个数或0
const void *ptr		是写的数据存放的缓冲区 
size_t size			每次写的字节数
size_t nmemb    	写入数据的次数
FILE *stream		表示要写入哪个文件(已打开文件的指针,一般就是fopen的返回值)

11.3 文件读取函数fread函数原型和头文件:

/*
	Linux下 man fread查看手册
*/
#include <stdio.h>

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
	
size_t			若成功读出文件,函数返回值为读取总共字节个数(函数第三个参数),若失败,返回非写入字节个数或0
void *ptr		读的数据存放的缓冲区
size_t size	  	每次读的字节数
size_t nmemb    读取数据的次数
FILE *stream	表示要读取哪个文件(已打开文件的指针,一般就是fopen的返回值)   

11.4 文件光标移动函数fseek函数原型和头文件:

/*
	Linux下 man fseek查看手册
*/
#include <stdio.h>

int fseek(FILE *stream, long offset, int whence);

int				函数返回值,若成功移动光标,函数返回值为0,若失败,返回-1
FILE *stream	要移动光标的文件
long offset		针对whence光标偏移个数
int whence		光标的绝对位置
    
1.SEEK_SET  文件头	      The offset is set to offset bytes.	
2.SEEK_CUR  光标当前位置	The offset is set to its current location plus offset bytes.	
3.SEEK_END  文件内容末尾	The offset is set to the size of the file plus offset bytes.

11.5 文件关闭函数fclose函数原型和头文件:

/*
	Linux下 man fclose查看手册
*/
#include <stdio.h>

int fclose(FILE *fp);

int			函数返回值,成功关闭文件则返回0,非则返回EOF
FILE *fp	表示要关闭哪个文件(已打开文件的指针,一般就是fopen的返回值)

11.6 标准C库对文件打开写入读取关闭编程实现:

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

int main()
{
	FILE *fp;
	char *str = "chenlichen handsome";
	char readBuf[128] = {0};

	//FILE *fopen(const char *path, const char *mode);
	fp = fopen("./chen.txt","w+");						//可读可写方式创建一个文本文档并打开,文件名chen.txt

	//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
	fwrite(str,sizeof(char),strlen(str),fp);			//把str中的内容写入到文件中,一次写1个字节,写strlen(str)次
	//fwrite(str,sizeof(char)*strlen(str),1,fp);		//把str中的内容写入到文件中,一次把所有内容写入到文件中
	
	//int fseek(FILE *stream, long offset, int whence);
	fseek(fp,0,SEEK_SET);								//写完之后文件中的光标回到头
	
	//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
	fread(readBuf,sizeof(char),strlen(str),fp);		//把文件中的内容读取到readBuf中,一次读一个字节,读strlen(str)次
	//fread(readBuf,sizeof(char),strlen(str),fp);		//把文件中的内容读取到readBuf中,一次把所有内容全部读出
    
	printf("read data: %s\n",readBuf);				//输出从文件中读取到readBuf的内容

	fclose(fp);										//关闭文件
	return 0;
}

十二、标准C库写入结构体到文件

12.1 写一个整数到文件:

#include <stdio.h>

int main()
{
	FILE *fp;
	int data = 100;
	int data2;

	fp = fopen("./file1","w+");							//打开file1文件,没有的话就创建

	//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
	fwrite(&data,sizeof(int),1,fp);						//写一个整数到文件中

	fseek(fp, 0, SEEK_SET);								//写完之后,光标回到文件头

	//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
	fread(&data2,sizeof(int),1,fp);						//把文件中的整数读取到data2中
	
	printf("read %d\n",data2);							//输出读取到的内容
	fclose(fp);											//关闭文件
	return 0;
}

12.2 写一个结构体到文件:

#include <stdio.h>

struct Test
{
	int idata;
	char cdata;
};

int main()
{
	FILE *fp;
	struct Test t1 = {100,'#'};						//定义一个结构体变量并赋值
	struct Test t2;

	fp = fopen("./file1","w+");						//打开file1,如果没有就创建

	//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
	fwrite(&t1,sizeof(struct Test),1,fp);			//将结构体写到文件中
	
	fseek(fp, 0, SEEK_SET);							//写完之后,光标回到头

	//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
	fread(&t2,sizeof(struct Test),1,fp);			//把文件中的结构体读取到t2中

	printf("read t2 = %d,%c\n",t2.idata,t2.cdata);	//输出读取的结果
	fclose(fp);										//关闭文件
	return 0;
}

12.3 写一个结构体数组到文件:

#include <stdio.h>

struct Test
{
	int idata;
	char cdata;
};

int main()
{
	FILE *fp;
	int i;
	struct Test arr1[2] = {											//定义一个结构体数组并初始化

		{100,'#'},
		{200,'$'}
	};
	struct Test arr2[2];
	
	int arr1Size = sizeof(arr1) / sizeof(arr1[0]);					//计算arr1的元素个数
	int arr2Size = sizeof(arr2) / sizeof(arr2[0]);					//计算arr2的元素个数
		
	fp = fopen("./file1","w+");										//打开file1文件,没有就创建

	//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
	fwrite(&arr1,sizeof(struct Test)*arr1Size,1,fp);				//把arr1结构体数组写入到文件中
	
	fseek(fp, 0, SEEK_SET);											//写完之后,光标回到头

	//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
	fread(&arr2,sizeof(struct Test)*arr2Size,1,fp);					//把文件中的结构体数组读取到arr2中
	
	for(i=0; i<2; i++){	
		printf("read arr2 = %d,%c\n",arr2[i].idata,arr2[i].cdata);	//输出读取到的结构体数组
	}
	fclose(fp);														//关闭文件
	return 0;
}

十三、文件其它函数讲解及文件收尾

13.1 文件写入字符函数fputc函数原型和头文件:

/*
	Linux下 man fputc查看手册
*/
#include <stdio.h>

int fputc(int c, FILE *stream);

int 			函数返回值,若成功写入文件,函数返回值为写入文件的字符的ASCII码值,若出错,返回EOF(-1)
int c			要写入的字符   
FILE *stream	表示要写入哪个文件(已打开文件的指针,一般就是fopen的返回值)

13.2 使用fputc函数写一个字符到文件:

#include <stdio.h>

int main()
{
	FILE *fp;
	char cdata = '#';					//要写入的内容
	
	fp = fopen("test.txt","w+");		//打开file1文件,如果没有就创建
	
	fputc(cdata,fp);					//写字符到file1文件
	fclose(fp);							//关闭文件
	return 0;
}

13.3 使用fputc函数写多个字符到文件:

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

int main()
{
	FILE *fp;
	int i;
	char *str = "chenlichen handsome";		//定义一个字符串
	char readBuf[128] = {0};	

	int len = strlen(str);					//计算字符串的长度
	fp = fopen("test.txt","w+");			//打开file1文件,如果没有就创建
	
	for(i=0; i<len; i++){					//使用for循环一个一个的将字符串中的字符写入到文件中
		fputc(*str,fp);
		str++;								//指针偏移
	}
	//int fseek(FILE *stream, long offset, int whence);
	fseek(fp,0,SEEK_SET);					//让文件中光标回到头

	//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
	fread(readBuf,sizeof(char)*len,1,fp);	//将文件中的内容读取到readBuf里面
	
	printf("read %s\n",readBuf);			//输出读取到的内容
	fclose(fp);								//关闭文件
	return 0;
}

13.4 文件读取字符函数fgetc函数原型和头文件:

/*
	Linux下 man fgetc查看手册
*/
#include <stdio.h>

int fgetc(FILE *stream);

int				函数返回值,若成功读出文件,函数返回值为读出文件的内容,若出错或读到末尾,返回EOF(-1)
FILE *stream	表示要读取哪个文件(已打开文件的指针,一般就是fopen的返回值)

13.5 文件尾巴检测函数feof函数原型和头文件:

/*
	Linux下 man feof查看手册
*/
#include <stdio.h>

int feof(FILE *stream);

int 			函数返回值,若到文件末尾,函数返回值为非0,若不到末尾,返回0
FILE *stream	表示要判断的文件

13.6 使用feof函数检测是否到文件尾部并使用fgetc函数读出文件内容:

#include <stdio.h>

int main()
{
	FILE *fp;
	char c;

	fp = fopen("./test.txt","r");		//只读方式打开当前路径的test.txt文件

	while(!feof(fp)){					//判断是否到文件尾部
		c = fgetc(fp);					//没有到文件尾部就一个字符一个字符的读出文件的内容
		printf("%c",c);					//读一次输出一次
	}
	fclose(fp);							//关闭文件
	return 0;
}

  • Linux系统一切皆文件文件系统(文件夹 /文件 ) 硬件设备 管道 数据库 Socket等,文件还是非常重要的,文件的操作就先到这里!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1126192.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python之Cp、Cpk、Pp、Ppk

目录 1、Cp、Cpk、Pp、Ppk 2、python计算 1、Cp、Cpk、Pp、Ppk Cp Process Capability Ratio 可被译为“过程能力指数” Cpk Process Capability K Ratio 可被译为“过程能力K指数” Pp Process Performance Ratio 可被译为“过程绩效指数” Ppk Process Performance K Ra…

Win10/Win11系统bitlocker正在等待激活如何解决?

有同学升级Win10系统后&#xff0c;发现C盘与D盘分区盘符中出现了黄色的锁定感叹号&#xff0c;还显示“bitlocker正在等待激活”&#xff0c;这可能是用户开启了bitlocker加密所导致的。下面就来看看解决的办法吧。 一、bitlocker正在等待激活的解决方法 打开控制面板-系统和安…

浅谈uniapp中开发安卓原生插件

其实官方文档介绍的比较清楚而且详细,但是有时候他太墨迹,你一下子找不到自己想要的,所以我总结了一下开发的提纲,也是为了自己方便下次使用。 1.第一步,下载官方提供的Android的示例工程,然后倒入UniPlugin-Hello-AS工程请在App离线SDK中查找,之后Android studio,编译运行项目…

C++11新特性之十六:std::tie

在c 11标准库中&#xff0c;加入了std::tie&#xff0c;在c 14中改进&#xff0c;方便使用。 其与std::tuple关系密切&#xff0c; 主要目的是方便地使用std::tuple。 std::tie函数的作用就是从元素引用中生成一个std::tuple元组&#xff0c;其在头文件<tuple>中定义&…

Git(二)版本控制、发展历史、初始化配置、别名

目录 一、版本控制1.1 为什么要使用版本控制&#xff1f;1.2 集中化的版本控制系统1.3 分布式的版本控制系统1.3 两种版本控制系统对比集中式&#xff08;svn&#xff09;分布式&#xff08;git&#xff09; 二、发展历史三、初始化配置3.1 配置文件3.2 配置内容 四、别名 一、…

基于卷积神经网络的乳腺癌分类 深度学习 医学图像 计算机竞赛

文章目录 1 前言2 前言3 数据集3.1 良性样本3.2 病变样本 4 开发环境5 代码实现5.1 实现流程5.2 部分代码实现5.2.1 导入库5.2.2 图像加载5.2.3 标记5.2.4 分组5.2.5 构建模型训练 6 分析指标6.1 精度&#xff0c;召回率和F1度量6.2 混淆矩阵 7 结果和结论8 最后 1 前言 &…

仅手机大小!极空间T2随身数据魔盒发布:既是NAS 又是U盘

今天极空间召开新品发布会&#xff0c;带来了极空间T2随身数据魔盒&#xff0c;售价1999元起。 极空间T2随身数据魔盒体积仅手机大小&#xff0c;充电宝可供电。既是个NAS&#xff0c;又是个U盘。 其具备双M.2插槽&#xff0c;可安装两块固态硬盘。4G内存支持docker&#xff0c…

Excel宏(VBA)自动化标准流程代码

自动化流程 我们对一个报表进行自动化改造会经历的固定流程&#xff0c;这里称为“流水线”&#xff0c;通常包含以下流程&#xff1a; 打开一个表格选择打开的表格选择表格中的Sheet选择Sheet中的单元格区域 &#xff08;有时候需要按条件筛选&#xff09;复制某个区域 粘贴…

互联网Java工程师面试题·Spring篇·第二弹

目录 3、Beans 3.1、什么是 spring bean&#xff1f; 3.2、spring 提供了哪些配置方式&#xff1f; 3.3、spring 支持集中 bean scope&#xff1f; 3.4、spring bean 容器的生命周期是什么样的&#xff1f; 3.5、什么是 spring 的内部 bean&#xff1f; 3.6、什么是 spri…

Linux下编译和安装ffmpeg

本文演示Centos下面如何编译和安装ffmpeg的过程&#xff0c; 一、ffmpeg的编译和安装 1、下载解压 wget http://www.ffmpeg.org/releases/ffmpeg-5.1.tar.gz tar -zxvf ffmpeg-5.1.tar.gz2、进入压缩目录&#xff0c;编译编译和安装 cd ffmpeg-5.1./configure --prefix/usr…

酷开科技 | 酷开系统,为居家生活打开更精彩的窗口

电视在我们的日常生活中扮演着重要的角色。虽然&#xff0c;作为客厅C位的扛把子——电视的娱乐作用深入人心&#xff0c;但是&#xff0c;它的涵义和影响力却因我们每个人的具体生活环境而存在着种种差异&#xff0c;而我们的生活环境又受到我们所处的社会及文化环境的影响。 …

哈希索引(PostgreSQL 14 Internals翻译版)

概览 哈希索引提供了根据特定索引键快速查找tuple ID (TID)的功能。粗略地说&#xff0c;它只是一个存储在磁盘上的哈希表。哈希索引唯一支持的操作是根据相等条件进行搜索。 当一个值插入到索引中时&#xff0c;将计算索引键的哈希函数。PostgreSQL哈希函数返回32位或64位整…

SSM - Springboot - MyBatis-Plus 全栈体系(三十六)

第八章 项目实战 四、后台功能开发 3. 头条模块开发 3.1 登陆验证和保护 3.1.1 需求描述 客户端在进入发布页前、发布新闻前、进入修改页前、修改前、删除新闻前先向服务端发送请求携带 token 请求头后端接收 token 请求头后&#xff0c;校验用户登录是否过期并做响应前端根…

Openssl数据安全传输平台009:加密理论基础:哈希/非对称加密RSA/对称加密AES

文章目录 0. 代码仓库代码编译时候可能出现的错误 1. 哈希1.1 哈希算法的种类:1.2 使用的头文件1.3 哈希算法API1.3.1 详解md5 API1.3.2 sha1/sha224/sha256/sha384/sha512常用API 1.5 sha1代码测试1.4 在VS中添加预处理器定义1.5 哈希算法C代码封装的思路 2. 非对称加密RSA2.1…

uniapp 单选框以及多选框样式更改

radio以及checkbox默认样式不符合自身需求时&#xff0c;根据自身需求更改样式&#xff0c;以下是自身的示例&#xff1a; 单选&#xff1a; 多选&#xff1a; 由于uniapp自身包含了一套默认的样式&#xff0c;所以如果不想全局更改只想在某个单据页面使用的话&#xff0c;就…

Redis3.2.12版本服务器迁移

1.新机器更新yum源 yum -y update 2.新机器安装redis数据库 yum install redis 3.新机器下载fedora的epel仓库 systemctl enable redis 4.将旧机器上的/etc/redis.conf拷贝到新机器的/config目录下 scp -r -P22 redis.config root162.32.196.57:/config/redis.config 5.新机器启…

CentOS 编译安装TinyXml2

安装 TinyXml2 Git 源码下载地址:https://github.com/leethomason/tinyxml2 步骤1&#xff1a;首先&#xff0c;你需要下载tinyxml2的源代码。你可以从Github或者源代码官方网站下载。并上传至/usr/local/source_code/ 步骤2&#xff1a;下载完成后&#xff0c;需要将源代码解…

LrC 13 ACR 16:点颜色

Adobe Lightroom Classic 13&#xff08; 2023 年 10 月版&#xff09;及 Adobe Camera Raw 16 新增的点颜色 Point Color功能可以方便、精准地调整图像上的颜色。 LrC&#xff1a;修改照片/混色器/点颜色 Develop/Color Mixer/Point Color ACR&#xff1a;编辑/混色器/点颜色 …

希捷推出Exos系列24TB硬盘:配备增强型缓存 性能提高三倍

希捷推出了全新的Exos 24TB硬盘。其基于传统的CMR构建&#xff0c;为3.5英寸规格&#xff0c;转速为7200 RPM。 同时&#xff0c;Exos系列24TB硬盘拥有10片磁盘&#xff0c;每片磁盘的容量为2.4TB&#xff0c;是希捷存储密度最高的硬盘&#xff0c;适用于超大规模企业和数据中心…

最新Jn建站系统2.0 已集成各类源码 【附视频安装教程】

附视频安装教程|已集成各类源码 目前已集成的网站&#xff1a; 1.发卡网(最新) 2.代刷网(无需授权) 3. 博客网(自带模板) 4.易支付(稳定版) 5.个人导航网(简洁) 6.代理查询网 7.留言网 8.匿名网 9.表白墙(最新) 10.抽奖网 11.源码站 12.z-blog博客程序 13.织梦CM…