Liunx C 语言文件编程
打开创建文档->编辑文档->保存文档->关闭文档
操作系统提供了一系列的API:
打开 open 、
读写 write/read、
光标定位 lseek、
关闭 close
以上均为系统IO,操作文件是无缓存的
一 . 打开 / 创建文件
1 . 涉及函数
【打开/创建api】
相关头文件
#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);
参数解释 :
pathname:
要打开的文件名(含路径,缺省为当前路径, 缺省示例:./file代表当前路径下的file文件 )
flags:
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 可读可写打开
下列为可配置选项
O_CREAT 若文件不存在则创建它,在使用此选项时,需要同时说明第三个参数mode,用其来说明该新文件的存取许可权限
O_EXCL 和O_CREAT同时指定时,但如果文件存在则出错
O_APPEND 每次写时都加在文件的尾端
O_TRUNC 如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0
mode:
一定是在flags中使用了O_CREAT标志才需要设置mode,mode记录待创建文件的访问权限0600为可读可写 ,4可读 2可写 1可执行 所以0600为可读可写权限
返回值:成功返回文件描述符fd(非负整数),失败返回-1
----------------------------------------------------------------------------------------
【创建文件api】
相关头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
函数含义: 创建文件
int creat(const char *pathname, mode_t mode);
参数解释:
pathname:
要打开的文件名(含路径,缺省为当前路径,缺省示例:./file代表当前路径下的file文件)
mode:
S_IRUSR 可读
S_IWUSR 可写
S_IXUSR 可执行
S_IRWXU 可读可写可执行
返回值:成功返回文件描述符(非负整数),失败返回-1
2 . 示例代码
2-1 文件打开
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
int ds = -1 ;
ds = open("./test.txt",O_RDWR);
if(ds != -1 ){
printf("file test.txt open success ! \r\n");
}else{
printf("file test.txt open fail !\r\n");
}
return 0 ;
}
2-2 文件创建与打开
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// 文件打开失败就创建文件,文件权限为 4 + 2 可读可写
int main(){
int ds = -1 ;
// 文件打开失败就创建文件,文件权限为 4 + 2 可读可写
ds = open("./new.txt",O_RDWR|O_CREAT,0600);
if(ds == -1 ){
ds = open("./new.txt",O_RDWR);
if(ds != -1 ){
printf("file test.txt open success 2 ! \r\n");
}else{
printf("file test.txt open fail ! \r\n");
}
}else{
printf("file test.txt open suc 1 ! \r\n");
}
return 0 ;
}
2-3 文件创建
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(){
int ds = creat("./creat.txt",0600);
if(ds != -1 ){
printf("creat file success ! \r\n");
}
return 0 ;
}
二 . 文件的写入与读取
1. 涉及函数
写入文件
头文件:
#include <unistd.h>
函数含义: 向文件中写入数据
ssize_t write(int fd,const void *buf,size_t count);
参数解释:
fd:文件描述符,由open()或creat()函数获得
buf:写入的数据的头指针
count:写入数据的数量
返回值:成功返回写入数据的数量,失败返回-1
-------------------------------------------------------------------------------------
读取文件
头文件:
#include <unistd.h>
函数含义:向文件中读取数据
ssize_t read(int fd, void *buf, size_t count);
参数解释:
fd:文件描述符,由open()或creat()函数获得
buf:读取出来的数据放入该指针
count:读取数据的数量
返回值:成功返回读取数据的数量,失败返回-1
2. 示例代码
2-1. 文件写入
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int num , char *args[]){
// 参数判断
if(num < 2){
printf("number is not tow \r\n");
return -1 ;
}
char *msg = "hello world !\r\n";
// 获得文件描述
int ds = open(args[1],O_RDWR|O_CREAT);
if(ds == -1 ){
printf("create file fail !! \r\n");
return -1 ;
}else{
printf("create file success !! \r\n");
}
// 写入数据
int ret = write(ds,msg,strlen(msg));
if(ret != -1 ){
printf("write data:%d success !! \r\n",ret);
}else{
printf("write data fail !! \r\n");
return -1 ;
}
return 0 ;
}
2-2. 文件读取
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(){
int ds = open("write.txt",O_RDWR);
if(ds == -1 ){
printf("file not find \r\n");
return -1 ;
}
// 读取数据
char msg[15] = {};
// 这里先用固定长度接收
int ret = read(ds,msg,15);
if(ret != 0 ){
printf("read file success !! \r\n");
printf("data is : %s",msg);
}else{
printf("read file fail / no data !! \r\n");
}
return 0;
}
三 . 光标定位
1. 涉及函数
光标定位
头文件:
#include <sys/types.h>
#include <unistd.h>
函数含义:控制文件的光标
off_t lseek(int fd, off_t offset, int whence);
参数解释:
fd:
文件描述符,由open()或creat()函数获得
offset:
偏移值,正值向后偏移,负值向前偏移
whence:基准值
SEEK_SET文件头
SEEK_CUR文件当前光标
SEEK_END文件尾
返回值:成功返回偏移了多少个单位,失败返回-1
2.代码示例
2-1. 基本使用
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main(){
int ds = open("./write.txt",O_RDWR);
if(ds == -1 ){
printf("error: file open fail \r\n");
return -1 ;
}
int where = lseek(ds,0,SEEK_END);
printf("data size is %d bit \r\n",where);
return 0 ;
}
2-2. 配合文件读写
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char *msg = "hello this is laopi\r\n";
int ds = open("./write.txt",O_RDWR|O_TRUNC);
if(ds == -1 ){
printf("file open fail \r\n");
return -1 ;
}
int rwt = write(ds,msg,strlen(msg));
if(rwt == -1 ){
printf("file write fail \r\n");
return -1 ;
}
int rset= lseek(ds,0,SEEK_END);
lseek(ds,0,SEEK_SET);
if(rset == -1 ){
printf("file lseek fail\r\n");
return -1 ;
}
char *rdmsg = (char *) malloc(sizeof(char) * rset);
int reat = read(ds,rdmsg,rset);
if(reat == -1 ){
printf("file read fail \r\n");
return -1;
}
printf("data is :%s ,data size %d ,read data %d \r\n",rdmsg,rset,reat);
return 0 ;
}
四. 相关案例
1. 实现 cp 指令
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
读取源文件数据
*/
int inputResFileInfo(char *filename,char **msg){
int resfd = open(filename,O_RDWR);
if(resfd == -1 ){
printf("res file not find \r\n");
return -1 ;
}
//
int resnum =lseek(resfd,0,SEEK_END);
//
lseek(resfd,0,SEEK_SET);
*msg = (char * ) malloc(sizeof(char) * resnum );
int rdt = read(resfd,*msg,resnum);
//printf("read data is %s , size is %d \r\n",*msg,resnum);
if(rdt == -1 ){
printf("read fail\r\n");
}
close(resfd);
return resnum;
}
/*
目标文件创建并写入数据
*/
int outputDesFileInfo(char *filename,char *msg){
int desfd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0600);
if(desfd == -1 ){
printf("des file not find \r\n");
return -1 ;
}
lseek(desfd,0,SEEK_SET);
//printf("msg size %d\r\n",strlen(msg));
int wrt = write(desfd,msg,strlen(msg));
if(wrt == -1 ){
printf("write fail\r\n");
return -1 ;
}
close(desfd);
return wrt ;
}
int main(int num , char *filename[]){
if(num < 3 ){
printf("arg not\r\n");
return -1 ;
}
char *msg ;
int size = inputResFileInfo(filename[1],&msg);
if(size == -1 ){
printf("input fail \r\n");
return -1 ;
}
// printf("msg is %s\r\n",msg );
int wrt = outputDesFileInfo(filename[2],msg);
if(size > 0){
printf("cp success \r\n");
}
return 0 ;
}
2. 配置文件修改
配置文件如下 :
path=/usr/home
name=zhangsan
data=2023/4/28
代码如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
1. 文件打开
2. 文件读取
3. 数据查找
4. 数据修改
5. 数据写入
运行例子 : ./a.exe peizhi.txt path /usr/my
*/
int main(int num , char *arg[]){
if(num < 4){
printf("error: arg fail \r\n");
return -1 ;
}
/*
arg[1] 文件名称
arg[2] 配置名称
arg[3] 配置数据
*/
int fd = open(arg[1],O_RDWR);
if(fd == -1 ){
printf("open fail \r\n");
return -1 ;
}
int size =lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);
char *msg = (char * ) malloc(sizeof(char) * size);
int rdt = read(fd,msg,size);
if(rdt == -1 ){
printf("error: read fail\r\n");
return -1 ;
}
// printf("data is : \r\n %s\r\n",msg);
// printf("=========================\r\n");
// 根据回车来分割
char *tk = strtok(msg,"\r\n") ;
int i = 0 ;
// 可以优化为动态数组 , 存储读取数据
char *dst[10] = {};
// 查找状态
int start = 0 ;
// 存储临时变量
char *tmp = "";
// 分割存储
while(tk != NULL){
dst[i] = tk ;
// 拼接查找配置
if(!start && strstr(tk,arg[2]) != NULL){
// printf("find is %d\r\n",i);
// 内存扩展方便拼接
tmp = (char * )malloc(sizeof(char) * (strlen(arg[2]) + strlen(arg[3]) + 1 ));
tmp = strcat(tmp,arg[2]);
tmp = strcat(tmp,"=");
tmp = strcat(tmp,arg[3]);
printf("update data is %s \r\n",tmp);
dst[i] = tmp ;
start = 1 ;
}
tk = strtok(NULL,"\r\n");
i++;
}
close(fd);
if(!start){
printf("error : not find config \r\n");
return -1 ;
}
// 用于清除文件内容
fd =open(arg[1],O_RDWR | O_CREAT | O_TRUNC , 0600);
// 写入数据
int j = 0 ;
for(;j < i ;j++){
write(fd,dst[j],strlen(dst[j]));
write(fd,"\n",strlen("\n"));
}
close(fd);
printf("done\r\n");
return 0 ;
}
五. 标准 C 库(fopen)
1. open 与 fopen 区别
a . 来源
open是UNIX系统调用函数(包括LINUX等),返回的是文件描述符(File Descriptor),它是文件在文件描述符表里的索引。
fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api。返回的是一个指向文件结构的指针。
b . 移植性
fopen
是C标准函数,因此拥有良好的移植性;
open
是UNIX系统调用,移植性有限。
c . 适用范围
open 返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作普通正规文件(Regular File)。
fopen 是用来操纵普通正规文件(Regular File)的。
d . 文件 IO 层次
如果从文件IO的角度来看,前者(open)属于低级IO函数,后者(fopen)属于高级IO函数。低级和高级的简单区分标准是:谁离系统内核更近。低级文件IO运行在内核态,高级文件IO运行在用户态。
e . 缓冲
缓冲文件系统
缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用;当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓冲区”依此读出需要的数据。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。
非缓冲文件系统
缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。open, close, read, write, getc, getchar, putc, putchar等。
2. 代码示例
相关函数
fopen,fwrite,fread,fclose,fseek (与前面类似具体可以查看菜鸟教程: https://www.runoob.com/cprogramming/c-file-io.html )
标准IO操作文件是有缓存的
文件使用方式由r,w,a,t,b,+六个字符拼成,各字符的含义是:
r(read): 只读
w(write): 只写
a(append): 追加
t(text): 文本文件,可省略不写
b(binary): 二进制文件
+: 读和写
示例代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char *str = "zhang shuai!";
char readBuf[128]={'\0'};
//FILE *fopen(const char *path, const char *mode);
fp = fopen("./peng.txt","w+");
//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
//fwrite(str,sizeof(char),strlen(str),fp);
fwrite(str,sizeof(char)*strlen(str),1,fp);
//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);
printf("read data: %s\n",readBuf);
//int fclose(FILE *fp);
fclose(fp);
return 0;
}
好啦liunx 文件编程就分享到这里了,如果你有什么建议或意见可以评论或私信┗|`O′|┛ 嗷~~