Linux系统编程——文件编程

本文详细介绍了C语言中对文件的操作,包括使用open和fopen打开文件,write和read进行文件读写,如何实现cp功能的代码以及修改程序配置文件的示例。还讨论了标准C库中的文件操作函数,如fseek和fclose,并提供了多个代码示例来展示具体操作。
摘要由CSDN通过智能技术生成

目录

一、文件打开及创建

二:写入文件

三:文件读取

四、基于上述文件编程,编写实现cp(复制)功能的代码

五、基于上述文件编程,编写“修改程序的配置文件”的代码 

六、写一个整数到文件

七、写一个结构体到文件

八、写一个结构体数组到文件

九、标准C语言库的文件操作(open与fopen的区别)

十、标准C库打开创建文件读写文件以及光标移动

十一、标准C库其他函数

一、文件打开及创建

1、int open(const char *pathname,int flags);

包含3个头文件:#include <sys/types.h>
                           #include <sys/stat.h>
                           #include <fcntl.h>

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

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

返回值:一个非负整数(文件描述符)

例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;
}

显示结果为:fd = 3

2、int open(const char *pathname,int flags,mode_t mode);

参数说明:

flags:

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

O_EXCL 如果同时指定了OCREAT,而文件已经存在,则出错返回值为-1。       

O_APPEND 每次写时都加到文件的尾端。(写入文件时,不会覆盖原文件内容,加在原文件结尾。如果没有O_APPEND,则从头开始覆盖和新内容相同字节的原始内容。)

O_TRUNC 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0。(原内容全部删除,只有新写入的内容)

Mode:一定是在flags中使用了O_CREAT标志,mode记录待创建的文件的访问权限

例2:打开一个不存在的文件,获得一个返回值,并创建这个文件

如果不存在file1,则例1结果为:fd = -1

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

int main()
{
	int fd;
	
	fd = open("./file1",O_RDWR);
	if(fd == -1){
		printf("open file failed\n");	
		fd = open("./file1",O_RDWR|O_CREAT,0600);
		if(fd > 0){
			printf("create file1 success\n");
		}
	}
	
	return 0;
}


//此时不存在file1,显示结果为open file failed,之后新建了file1,显示create file1 success

关于“0600”的设置:(给文件所有者的权限)

可读:r  对应数字为4

可写:w 对应数字为2

可执行: x 对应数字为1

0600即4+2,可读可写

创建creat的使用

1、int creat(const char *filename,mode_t mode)

参数说明:filename:要创建的文件名(包含路径,缺省为当前路径)

                  mode:创建模式

常见模式:

宏表示数字释义
S_IRUSR4可读
S-IWUSR2可写
S_IXUSR1可执行
S_IRWXU7可读可写可执行

二:写入文件

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

参数说明:fd:哪个文件(文件描述符)

                  buf:缓冲区数据

                  count:数据字节数

返回值:写入数据的字节数,错误返回-1

例3: 打开一个文件,在文件中输入”WY is handsome!“

//打开文件所需的3个头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

//打印所需要的头文件
#include <stdio.h>

//写和关闭文件所需头文件
#include <unistd.h>

//strlen所需头文件
#include <string.h>

int main()
{
	int fd;
	char *buf = "WY is handsome!"; //数据

	fd = open("./file1",O_RDWR);
	if(fd == -1){
		printf("open file failed\n");	
		fd = open("./file1",O_RDWR|O_CREAT,0600);
		if(fd > 0){
			printf("create file1 success\n");
		}
	}
	printf("open success:fd=%d\n",fd);

    //写文件操作,将buf内的内容写入fd
    //注意:此处不用sizeof,sizeof是buf指针的长度,strlen是内容字符串长度
	write(fd,buf,strlen(buf));

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

三:文件读取

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

参数说明:从fd中读取count个数据放入buf

返回值:读了多少个就返回字节数;如果什么都没有读到,则返回0;错误返回-1;

例4:将例3写入的内容读取出来

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

//malloc所需的头文件
#include <stdlib.h>

int main()
{
	int fd;
	char *buf = "WY is handsome!"; 
    
//--------打开文件
	fd = open("./file1",O_RDWR);
	if(fd == -1){
		printf("open file failed\n");	
		fd = open("./file1",O_RDWR|O_CREAT,0600);
		if(fd > 0){
			printf("create file1 success\n");
		}
	}
	printf("open success:fd=%d\n",fd);

//--------写入文件
    int n_write = write(fd,buf,strlen(buf));
	if(n_write != -1){
		printf("write %d byte to file1\n",n_write);
	}
	
//--------读取文件
	char *readBuf;
    //给readBuf开辟空间,malloc返回的是void *,需要强转为char *
	readBuf =(char *)malloc(sizeof(char)*n_write + 1);

    //read函数返回值
	int n_read = read(fd,readBuf,n_write);	

    //打印读取的字节数以及内容
	printf("read %d,context:%s\n",n_read,readBuf);

	close(fd);
	return 0;
}

例4结果如下图:

出现问题:读取了0,内容也是空的

原因: 写入内容后,光标在内容后面,read的时候从光标处开始读取,所以什么都读取不到

解决:

写入内容后,先关闭文件,再打开文件,此时读取就是从头开始读取,如下例5

例5:

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

int main()
{
	int fd;
	char *buf = "WY is handsome!"; 

	fd = open("./file1",O_RDWR);
	if(fd == -1){
		printf("open file failed\n");	
		fd = open("./file1",O_RDWR|O_CREAT,0600);
		if(fd > 0){
			printf("create file1 success\n");
		}
	}
	printf("open success:fd=%d\n",fd);

    int n_write = write(fd,buf,strlen(buf));
	if(n_write != -1){
		printf("write %d byte to file1\n",n_write);
	}
    
    //写入之后先关闭文件,再打开文件
	close(fd);
	fd = open("./file1",O_RDWR);

    //读取文件
	char *readBuf;
	readBuf =(char *)malloc(sizeof(char)*n_write + 1);
	int n_read = read(fd,readBuf,n_write);	
	printf("read %d,context:%s\n",n_read,readBuf);

	close(fd);
	return 0;
}

例5结果如下图:

重新定位光标,移动光标至头部,如下例6

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

参数说明:fd:文件描述符

                  offset:偏移值

                  whence:固定点位置

将文件读写指针相对whence移动offset个字节

offset:负数往前偏移,正数往后偏移

whence:SEEK_SET:头部位置;SEEK_END:尾部位置;SEEK_CUR:当前位置

 例6:

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

int main()
{
	int fd;
	char *buf = "WY is handsome!"; 

	fd = open("./file1",O_RDWR);
	if(fd == -1){
		printf("open file failed\n");	
		fd = open("./file1",O_RDWR|O_CREAT,0600);
		if(fd > 0){
			printf("create file1 success\n");
		}
	}
	printf("open success:fd=%d\n",fd);

    int n_write = write(fd,buf,strlen(buf));
	if(n_write != -1){
		printf("write %d byte to file1\n",n_write);
	}
    
    //例5的做法注释掉
	//close(fd);
	//fd = open("./file1",O_RDWR);
	
	char *readBuf;
	readBuf =(char *)malloc(sizeof(char)*n_write + 1);
	
    //例6做法
	lseek(fd,0,SEEK_SET);//头部偏移0
	
	int n_read = read(fd,readBuf,n_write);	
	printf("read %d,context:%s\n",n_read,readBuf);

	close(fd);
	return 0;
}

基于lseek,可以计算文件大小,如下例7

例7:计算文件大小

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

int main()
{
	int fd;
	char *buf = "WY is handsome!";

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

//lseek返回值是“针对文件头偏移的字节数”
    int filesize = lseek(fd,0,SEEK_END);
	printf("file's size is %d\n",filesize);

	close(fd);
	return 0;
}

四、基于上述文件编程,编写实现cp(复制)功能的代码

1、实现步骤

①打开源文件(src.c)

②读src到buf

③打开/创建目标文件(des.c)

④将buf写入到des

⑤close两个文件

2、编程实现

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

int main(int argc,char **argv)
{
	int fdSrc;//原文件
	int fdDes;//目标文件

	char *readBuf = NULL;//存放数据的指针,指向空,防止野指针

    //判断原文件是否正确,不正确直接中止程序
	if(argc != 3){
		printf("pararm error\n");
		exit(-1);
	}


    //打开原文件
	fdSrc = open(argv[1],O_RDWR);

    //通过lseek读取文件内数据大小,读取完此时光标在末尾
	int sizeSrc = lseek(fdSrc,0,SEEK_END);

    //把光标移回到最前面
	lseek(fdSrc,0,SEEK_SET);


    //给数据保存区动态开辟空间
	readBuf = (char*)malloc(sizeof(char)*sizeSrc + 8);


    //将原文件内的内容读到数据保存区
	read(fdSrc,readBuf,sizeSrc);

    //打开/创建目标文件
	fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);

    //将数据保存区的数据写入到目标文件中
	write(fdDes,readBuf,strlen(readBuf));

    //关闭两个文件
	close(fdSrc);
	close(fdDes);
	
	return 0;
}

五、基于上述文件编程,编写“修改程序的配置文件”的代码 

1、实验说明

有一个file1文件,里面有如下内容:

SPEED=3
LENG=3
SCORE=9
LEVEL=5

现要修改LENG后面的3为5

2、编程实现

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

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

	char *readBuf = NULL;

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

	fdSrc = open(argv[1],O_RDWR);
	int sizeSrc = lseek(fdSrc,0,SEEK_END);
	lseek(fdSrc,0,SEEK_SET);

	readBuf = (char *)malloc(sizeof(char)*sizeSrc + 8);

	read(fdSrc,readBuf,sizeSrc);

    //将指针p指向LENG的开头
	char *p = strstr(readBuf,"LENG=");
	if(p==NULL){
		printf("not found\n");
		exit(-1);
	}
    //指针偏移到=后面
	p = p+strlen("LENG=");
    //指针取内容后修改为5
	*p = '5';

    //光标移动到开头
	lseek(fdSrc,0,SEEK_SET);
	write(fdSrc,readBuf,strlen(readBuf));

	close(fdSrc);
	
	return 0;
}

六、写一个整数到文件

直接整代码

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

int main()
{
	int fd;
	
//两个数据
	int data1 = 100;
	int data2 = 0;

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

//将data1写入fd
	write(fd,&data1,sizeof(int));

//光标移到头部
	lseek(fd,0,SEEK_SET);

//读取fd,将数据保存在data2中
	read(fd,&data2,sizeof(int));

	printf("read:%d\n",data2);
	close(fd);
		
	return 0;
}

结果:

read:100

七、写一个结构体到文件

直接整代码

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

//结构体
struct Test
{
	int a;
	char b;
};

int main()
{
	int fd;
	
	struct Test data1 = {100,'w'};
	struct Test data2;

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

    //结构体长度
	write(fd,&data1,sizeof(struct Test));

	lseek(fd,0,SEEK_SET);

	read(fd,&data2,sizeof(struct Test));

	printf("read:%d,%c\n",data2.a,data2.b);
	close(fd);
		
	return 0;
}

结果:

read:100,w

八、写一个结构体数组到文件

直接上代码:

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

struct Test
{
	int a;
	char b;
};

int main()
{
	int fd;
	
	struct Test data1[2] = {{100,'w'},{101,'y'}};
	struct Test data2[2];

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

	write(fd,&data1,sizeof(struct Test)*2);

	lseek(fd,0,SEEK_SET);

	read(fd,&data2,sizeof(struct Test)*2);

	printf("read:%d,%c\n",data2[0].a,data2[0].b);
	printf("read:%d,%c\n",data2[1].a,data2[1].b);
	close(fd);
		
	return 0;
}

结果:

read:100,w
read:101,y

九、标准C语言库的文件操作(open与fopen的区别)

1、来源不同

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

2、移植性

fopen是标准C库函数,具有良好的可移植性,open函数是UNIX系统调用,移植性有限

3、适用范围

  • open返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作普通正规文件(Regular File)。
  • fopen是用来操纵普通正规文件(Regular File)的。

4、文件IO层次

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

5、缓冲

①缓冲文件系统 
缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用;当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓冲区”依此读出需要的数据。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。

②非缓冲文件系统 
缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。open, close, read, write, getc, getchar, putc, putchar等。

十、标准C库打开创建文件读写文件以及光标移动

1、打开文件

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

参数说明:

path:路径

mode:打开模式

模式说明
r只读方式打开一个文本文件
rb只读方式打开一个二进制文件
w只写方式打开一个文本文件
wb只写方式打开一个二进制文件

追加方式打开一个文本文件

ab追加方式打开一个二进制文件
r+可读可写方式打开一个文本文件
rb+可读可写方式打开一个二进制文件
w+可读可写方式创建一个文本文件
wb+可读可写方式生成一个二进制文件
a+可读可写追加方式打开一个文本文件
ab+可读可写方式追加一个二进制文件

 2、写入文件

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

参数说明:

ptr:缓冲区

size:一个字符的大小

nmemb:个数

stream:文件

返回值:第三个参数(个数)

3、读取文件

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

参数说明:

ptr:缓冲区

size:一个字符的大小

nmemb:个数

stream:文件

返回值:第三个参数(个数)

4、光标

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

与lseek参数说明相同 

5、 关闭文件

fclose

6、实验:打开一个文件并写入数据,读取数据

代码实现:

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

int main()
{
    
	FILE *fp;//文件
	char *str = "wy is handsome";//数据
	char readbuf[128] = {0};//缓冲区

	fp = fopen("./wy.txt","w+");//打开文件

	fwrite(str,sizeof(char),strlen(str),fp);//写入文件,一次写一个,写n次
//	fwrite(str,sizeof(char)*strlen(str),1,fp);//另一种写法,一次写n个,写1次

	fseek(fp,0,SEEK_SET);//光标重定位

	fread(readbuf,sizeof(char),strlen(str),fp);//读文件到缓冲区

	printf("data:%s\n",readbuf);
	return 0;
}

十一、标准C库其他函数

 1、fputc

int fputc(int c,FILE *stream);

 将w写入文件

#include <stdio.h>

int main()
{
	FILE *fp;
	
	fp = fopen("./test.txt","w+");
	fputc('w',fp);
	fclose(fp);
	return 0;
}

写入字符串

#include <stdio.h>
#include <string.h>
int main()
{
	FILE *fp;
	int i;
	char *str = "wy is handsome!";
	int len = strlen(str);
	fp = fopen("./w.txt","w+");
	for(i=0;i<len;i++){
		fputc(*str,fp);
		str++;
	}
	fclose(fp);
	return 0;
}

 2、feof(判断是否到文件尾部)

int feof(FILE *stream);

如果没有到达尾部,则返回0;反之则返回非0;

3、fgetc

int fgetc(FILE *stream);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值