Linux文件编程——文件的创建读写等操作

Linux文件编程概述

Linux操作系统可以帮助我们自动化的完成文件修改的一些相关操作,他给我们提供了一些API来帮助我们操作文件

下面是一些文件编程的常用的一些API

打开文件/创建文件 open/creat

读文件write

写文件read

光标移动lseek

关闭文件close

这些API的头文件

open

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

write read和close

#include<unistd.h>

lseek

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

Linux系统下的文件编程API使用

open

open函数有两种形式

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

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

返回值是文件描述符,是一个非负的整数,打开成功返回文件描述符来代指这个文件,没有这个文件则打开失败返回-1。第一个参数是要打开的文件名,传参时需要加入路径,如果不写路径则默认本路径,第二个参数是对该文件操作的权限。

基础权限有3种,3个宏,O_RDONLY(只读),O_WRONLY(只写),O_RDWR(可读可写)

基础权限只能选其中一种,选完基础权限后还可以或上(|)其他可选权限。

可选权限有4种O_CREAT,O_EXCL,O_APPEND,O_TRUNC

O_CREAT:当文件不存在时创建文件,文件存在时则直接打开文件,使用了O_CREAT后需要指明第三个参数mode,指明文件的访问权限(创建的文件能否读写)。

关于mode权限,可读可写可执行rwx,可读可写rw,可读r,可写w,可执行x,用数字代替7-rwx,6-rw,4-r,2-w,1-x,一般传参传4个数字,第一个数字为文件类型,第二个数字是文件拥有者权限,第三个数字是文件拥有者所在组的权限,第三个数字是其他组的权限。所以比如0600就给文件的访问权限设置为拥有者可读可写。

O_EXCL:在使用了O_CREAT权限后,如果再使用O_EXCL,可以检测文件是否存在,如果不存在则允许创建文件并打开,如果已经存在就不会允许创建文件,并且不会打开已存在的文件,并且返回值-1

O_APPEND:每次写入文件时,都在文件尾端写入。如果不加O_APPEND,写入的文件会从头开始写,并且写入的数据会覆盖原有位置的数据。注意使用O_APPEND之后 lseek后再写入将会无效,写入的时候只会在末尾写入

O_TRUNC:打开文件时,会把之前文件的内容删去,再进行读写操作

注意:如果你想在程序中获得文件的权限,方法如下 

1、Linux中每个文件都对应的有相应的属性,这些属性都保存在一个叫struct stat的结构体,如果你想获得文件的权限,那么就可以调用stat函数

函数原型int stat(const char *path,struct stat *buf)

第一个参数是文件名,第二个参数是存放的文件属性的结构体指针,调用成功return 0,失败return -1

头文件#include<sys/types.h>;#include<sys/stat.h>;#include<unistd.h>

调用成功后,buf里面就存放了文件的属性,文件的权限信息存放在buf.st_mode下,类型是mode类型,可以直接传参使用

更多关于stat的信息请移步至这里:

Linux如何用C代码获取文件的权限_一只青木呀的博客-CSDN博客

Linux(四)函数获知文件、目录的属性、权限_顾语心的博客-CSDN博客_linux 获取目录属性

2、或者调用access函数确定文件的访问权限

函数原型int access(const char* filename,int mode),满足条件return 0,不满足return -1;

第一个参数是文件名,第二个参数是检测的文件的权限4种,F_OK(存在性),X_OK(执行性),R_OK(可读性),W_OK(可写性)

creat

int creat(const char* filename,mode_t mode)

返回值是文件描述符,第一个参数是要创建的文件名,第二个参数是访问权限(是否可读写)

访问权限还可以用宏表示S_IRUSR(可读-4),S_IWUSR(可写-2),S_IXUSR(可执行-1),S_IRWXU(可读可写可执行-7)

write

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

返回值是写入的字节数,写入失败返回-1,第一个参数是目的文件的文件描述符,第二个参数是缓冲区的指针,相当于源地址,缓冲区指针里面的内容可以是任意类型,所以写入文件的内容不一定是字符串,可以是任意类型的内容,第三个参数是写入的字节数

注意:写入的内容不一定能显示正确,因为显示的时候都是显示的字符,如果写入的是字符,显示出的也是字符,但是如果写入的是数字,那么显示的时候就不是正确的数字,而是该数字在ascii码中对应的字符。read同理

         写入了文件之后,如果保存退出,那么系统会在文件末尾添加换行符,导致文件的末尾成了下一行开头,下次写文件如果再末尾写入,那么就会在下一行开头写入。但是只要不保存直接退出,就不会自动添加换行符

read

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

返回值是读入的字节数,读入失败返回-1,第一个参数是源文件的文件描述符,第二个参数是缓冲区的指针,相当于目的地址,缓冲区指针里面的内容可以是任意类型,所以读入缓冲区的内容不一定是字符串,可以是任意类型的内容,第三个参数是读入的字节数

注意read是从光标的当前位置开始读,写入完文件,光标可能在文件尾部,如果不移动光标,读出的字节数是0

要想从头读入,可以是写完后关闭文件再打开文件,或者写完后调用lseek移动光标

lseek

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

lseek的作用是将文件的读写指针移动到相对whence位置移动offset个字节的位置,返回值是针对头指针的偏移值

第三个参数可以传入的宏有SEEK_SET(头),SEEK_END(尾巴),SEEK_CUR(当前光标位置)

close

int close(int fd)

返回值为0,如果关闭失败返回-1,传参是要关闭文件的文件描述符,关闭文件后,打开文件后的所有对文件的操作都会被保存在硬盘。

Linux系统下文件操作的相关原理

操作文件的流程

在Linux下,要操作磁盘的文件需要在Linux内核的管理下,先打开文件,得到文件描述符后,再读写文件,完毕之后再关闭文件。

所以必须打开成功了才能操作文件,而且操作完成后一定要关闭文件,不然可能造成文件损坏

文件又分静态文件和动态文件,静态文件就是保存磁盘中的文件,动态文件就是在一个进程中打开的文件,此文件是从磁盘中的文件拷贝而来,放在内存中。在进程中对文件的所有操作都是针对的动态文件,在动态文件没有关闭的时候,动态文件的内容和静态文件的内容是不同步的,只有当close文件后,动态文件的内容才会更新到静态文件中。

流程如此设计是因为cpu对内存操作比对硬盘操作要快,而且更灵活。硬盘按块读取,一个块可能就100个字节比较大,不好灵活修改;而内存按字节读取,可以更方便的修改

文件描述符

当一个进程调用open或creat打开或创建文件后,Linux内核会在内存的缓存里面为文件创建一个数据结构来表示这个动态文件,这个动态文件里面包括了文件内容等文件相关信息,然后返回给应用程序一个数字作为文件描述符,文件描述符就和动态文件绑定上了,在该进程中操作该动态文件就只需要用文件描述符区分,所以文件描述符相当于该动态文件的索引,找到了文件描述符就找到了该文件。

文件描述符的作用于仅仅限于该进程中

对于Linux内核而言,所有打开的文件都由文件描述符引用,文件描述符是非负的整数,当调用open或creat打开或创建文件后,返回值就是该文件的文件描述符。读写文件时,用文件描述符来引用文件,并且当成参数传递

默认的文件描述符有三个0,1,2,用宏STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO分别代表标准输入,标准输出,标准错误

如果向从标准输入里面读入数据到buffer,那么当我们输入数据时,buffer的空间就会有数据;再从buffer中向标准输出写入数据,shell中就会显示写入的数据。

标准c库下的文件编程API使用

另外标准c库函数也提供了类似Linux系统下的文件操作相关API,用法和Linux系统下的各文件操作类似

头文件都在#include<stdio.h>

fopen

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

返回值是打开的文件,第一个参数是要打开的文件名,第二个参数的是文件权限

mode可传的参数是r,rb,r+,rb+,w,wb,w+,wb+,a,ab,a+,ab+

r+表示可读可写打开一个文件

w+表示可读可写创建一个文件

a+表示可读可惜追加打开一个文件

不带+,r表示只读,w表示只写,a表示追加
带b表示打开二进制文件,不带b表示打开文本文件

fread

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

返回值是实际读的次数,第一个参数是目标缓冲区,第二个参数是一次读入的大小,第三个参数是需要读入的次数,第四个参数是源文件指针
如果目标文件读完了之后,读的次数就不会增加了

fwrite

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

返回值是实际写入的次数,第一个参数的源缓冲区,第二个参数是一次写入的大小,第三个参数是需要写入的次数,第四个参数是目标文件指针

fseek

 int fseek(FILE *stream, long offset, int whence);
返回值是针对头指针的偏移值,第一个参数是文件指针,第二个参数光标移动相对于whence的偏移值,第三个参数是调用fseek的时候光标的位置

whence可选SEEK_SET,SEEK_CUR,SEEK_END

fclose

int fclose(FILE *fp);

关闭成功return 0,传入的参数是文件指针

fgetc

 int fputc(int c, FILE *stream);

将一个字符写入文件,写入一个光标往后移一个,第一个参数写入的字符,第二个参数是要写入的文件,写入成功return写入字符的ascii码,失败return -1

fputc

 int fgetc(FILE *stream);
从源文件读取一个字符,读取一个字节后,光标位置后移一个字节,读取成功return读出字符的ascii码,失败return -1

feof

int feof(FILE *stream);
判断光标是否到了文件的尾部,如果到了尾部return 非0值,还没到尾部return 0;

小应用:自己实现cp命令

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

int main(int argc, char* argv[]){
	int fdsrc;
	int fddes;
	struct stat quan;
	if(argc!=3){
		printf("parm number error\n");
		return -1;
	}
	fdsrc=open(argv[1],O_RDONLY);
	if(fdsrc<=-1){
		printf("open sourcefile filed,no such file\n");
		return -1;
	}
	stat(argv[1],&quan);
	if(!access(argv[1],R_OK)){
		printf("src file can read\n");
	}else printf("src file can not read\n");
	if(!access(argv[1],W_OK)){
		printf("src file can write\n");
	}else printf("src file can not write\n");
	if(!access(argv[1],X_OK)){
		printf("src file can execute\n");
	}else printf("src file can not execute\n");
	int size=lseek(fdsrc,0,SEEK_END);
	lseek(fdsrc,0,SEEK_SET);
	char* buf=(char*)malloc(size*sizeof(char)+8);
	int readsize=read(fdsrc,buf,size+8);
	fddes=open(argv[2],O_WRONLY|O_CREAT|O_EXCL,quan.st_mode);
	if(fddes<=-1){
		printf("Creat destinationfile filed,such filename already exited\n");
		return -1;
	}
	int writesize=write(fddes,buf,readsize);

	printf("cp success!\n");
	close(fdsrc);
	close(fddes);
	return 0;
}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

做台无人机

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

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

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

打赏作者

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

抵扣说明:

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

余额充值