一、Linux文件编程的一般步骤
在Linux底下要操作一个文件,需要先open一个文件,获得一个文件描述符,然后对文件进行读写操作,最后在关闭文件即可;
对文件进行操作时,一定要先打开文件,文件成功打开之后才能操作,如果打开失败,那就不用进行后面的操作了,最后读写完成之后一定要关闭文件;
文件平时是存放在块设备中的系统文件中的,称之为静态文件;当我们去打开一个文件,Linux的内核进程会先建立一个打开文件的数据结构,然后内核在内存管理中申请一段内存,再将静态内存的内容从块设备读取到内核指定地址管理存放;
打开文件后,对于这个文件的读写操作,都是针对于内存中的一份动态文件,当我们进行读写操作时,静态文件和动态文件其实是不同步的,只有在动态文件关闭之后,动态文件的内容才会更新到静态文件中。
二、读取/创建文件
open函数原型
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const cahr *pathname, int flags, mode_t mode );
int creat(const char *pathname, mode_t mode);
参数说明
pathname:要打开文件的名字(含路径,缺省为当前路径);
flags(权限):O_RDONLY(只读打开);
O_WRONLY(只写打开);
O_RDWR(可读可写打开);
以上flags的三个参数只能选用一个,下列的参数是可选择的;
O_CREAT:若文件不存在则创建文件,使用该项需要配置mode,说明文件的存取许可权限;
O_EXCL:如果文件已存在,则返回错误;
O_APPEND:每次写时都写到文件的尾端;
O_TRUNC:会将文件原本的内容全部丢弃,文件大小变为0;
mode:创建模式,在flags中使用了O_CREAT标志;
常见创建模式:
宏表示 数字
S_IRUSR 4 可读
S_IWUSR 2 可写
S_IXUSR 1 可执行
S_IRWXU 7 可读、可写、可执行
返回值:
open:打开成功返回一个文件描述符,失败返回-1;
creat:创建成功返回一个文件描述符,失败返回-1。
demo编写
//这个demo在当前文件夹打开文件,如果文件不存在,则创建文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd; //file description,文件描述符,定义一个文件描述符
fd = open("./file_1",O_RDWR);
if(fd == -1){
printf("open file_1 failed!\n");
fd = open ("./file_1",O_RDWR|O_CREAT,0600); //0600是文件的权限
if(fd > 0){
printf("creat file_1 success!!\n");
}
}
printf("fd = %d\n",fd);
return 0;
}
三、读写文件
write函数原型
SYNOPSIS
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);
参数说明
fd:文件描述符;
*buf:指定内存的指针,也可以是一个数组
count:读写的字节数。
返回值
write
当有错误时,返回-1,错误代码可以用errno捕捉;
成功写入,会返回实际写入的字节数(len)。
read
返回值为实际读取到的字节数,如果返回0,则表示读取到了文件尾部或者无可读取的数据;
对于网络套接字接口,返回值可能小于count,但是这并不是错误。
demo编写
#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; //file description,文件描述符
char *buf = "DaQiangYYDS";
fd = open("./file_1",O_RDWR); //打开file文件
//打开失败,则创建文件
if(fd == -1){
printf("open file_1 failed!\n");
fd = open ("./file_1",O_RDWR|O_CREAT,0600); //0600是文件的权限
if(fd > 0){
printf("creat file_1 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 file_1\n",n_write);
}
//重新定位光标
lseek(fd,0,SEEK_SET);
//读取文件内容
char *readBuf;
readBuf = (char *)malloc(sizeof(char)*n_write + 1);
int n_read = read(fd,readBuf,n_write);
printf("read byte : %d\ncontext : %s\n",n_read,readBuf);
//关闭文件
close(fd);
return 0;
}
四、文件光标
lseek函数原型
SYNOPSIS
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int where);
参数
fd:文件描述符
offset:偏移量,以字节为单位
where:用于定义offest偏移量对应的参考值,且选择以下其中一个参数;
// 宏定义
// SEEK_SET 文件头
// SEEK_CUR 当前位置
// SEEK_END 文件尾
返回值
成功返回文件头部到参数where的位置的偏移量(字节为单位);
错误返回-1,并设置errno值
应用
调整当前光标的位置,保证读写操作的正常运行;
计算文件的大小,将where设置为SEEK_END,则lseek的返回值就是文件的大小。
demo编写
参考第三部分的demo;
五、关闭文件
close函数原型
SYNOPSIS
#include <unistd.h>
int close(int fd);
参数
fd:文件描述符
返回值
成功:返回0;
错误:返回-1,并设置errno值。
六、cp指令的实现demo
实现思路
C语言的参数:./a.out [file1] [file2]
代码思路:
打开src(源文件)
读取src(源文件)到buf(缓冲区)
打开/创建des(目标文件)
将buf(缓冲区)写道des(目标文件)
close(关闭)两个文件
demo编写
//头文件区
#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 fd_Src; //源文件标识符
int fd_Des; //目标文件标识符
char *readBuf = NULL; //读取文件的区域指针
printf("pararm number : %d\n",argc);
//如果参数输入错误,则退出程序
if(argc != 3){
printf("pararm error!\n");
exit(-1);
}
//读取源文件
fd_Src = open(argv[1],O_RDWR);
int size = lseek(fd_Src,SEEK_SET,SEEK_END); //利用光标定位的返回值计算文件的大小
lseek(fd_Src,SEEK_SET,SEEK_SET); //重置光标
readBuf =(char *)malloc(sizeof(char)*size + 8); //开辟相应的空间大小,并大一些
int n_read = read(fd_Src,readBuf,size); //读取size的内容
//读取正常,返回值为非负整数
if(n_read != -1){
printf("read success\n");
printf("read Byte : %d\n",n_read);
}
//读取异常,返回值为-1
else{
printf("read failed\n");
}
close(fd_Src);
//写入目标文件
fd_Des = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);
int n_write = write(fd_Des,readBuf,strlen(readBuf));
//写入正常,返回值为非负整数
if(n_write != -1){
printf("write success\n");
printf("write Byte : %d\n",n_write);
}
//写入异常,返回值为-1
else{
printf("write failed\n");
}
close(fd_Des);
return 0;
}
运行效果
传入两个参数,源文件,目标文件
对比两个文件的不同用vimdiff指令;
退出输入“:qall“即可
七、修改配置文件demo
在前文件夹内有一个TEST.config的配置文件,内容如下
将文件中的LENG=9改成LENG=5
demo编写
//头文件区
#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 fd_Src; //源文件标识符
char *readBuf = NULL; //读取文件的区域指针
//如果参数输入错误,则退出程序
if(argc != 2){
printf("pararm error!\n");
exit(-1);
}
//读取源文件
fd_Src = open(argv[1],O_RDWR);
int size = lseek(fd_Src,SEEK_SET,SEEK_END); //利用光标定位的返回值计算文件的大小
lseek(fd_Src,SEEK_SET,SEEK_SET); //重置光标
readBuf =(char *)malloc(sizeof(char)*size + 8); //开辟相应的空间大小,并大一些
int n_read = read(fd_Src,readBuf,size); //读取size的内容
//读取正常,返回值为非负整数
if(n_read != -1){
printf("read success\n");
printf("read Byte : %d\n",n_read);
}
//读取异常,返回值为-1
else{
printf("read failed\n");
}
char *p = strstr(readBuf,"LENG="); //查找“LENG=”字符串,并返回第一个字符的地址
if(p==NULL){
printf("not found\n");
exit(-1);
}
p = p+strlen("LENG=");
*p = '5';
lseek(fd_Src,SEEK_SET,SEEK_SET);
int n_write = write(fd_Src,readBuf,strlen(readBuf));
close(fd_Src);
return 0;
}
运行效果