Linux修改文件步骤其实和Windows系统相似,步骤如下:
操作系统提供了一系列的API
如Linux系统:
打开 open
读写 write/read
光标定位 lseek
关闭 close
什么是文件标识符?
文件描述符即索引,通过文件描述符来区分不同文件,并对相应文件进行操作。
静态文件:存放在块设备中的文件系统中。
动态文件:当我们去open打开一个文件时,linux内核做的操作包括:内核在进程中建立一个打开文件的数据结构,记录下我们打开的这个文件;内核在内存中申请一段内存,并且将静态文件的内容从块设备中读取到内核特定地址管理存放的。
为什么要使用close函数关闭文件?
当我们close动态文件时,close内部内核将内存中的动态文件的内容去更新块设备中的静态文件。如果没有使用close函数关闭文件,会导致文件发生破损。
为什么这么设计,不直接对块设备直接操作?
块设备本身读写非常不灵活,是按块读写的,而内存是按字节单位操作,而且可以随机操作,很灵活。
一、打开文件
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
头文件
#include
#include
#include
参数
pathname:要打开的文件名(含路径,缺省为当前路径)
flags:O_RDONLY 只读打开 O_WRONLY 只写打开 O_RDWR 可读可写打开
以上三种常数只能指定一个。下列常数是可选择的:
常数 | 功能 |
---|---|
O_APPEND | 以追加的方式打开文件 |
O_CREAT | 创建一个文件 |
O_EXCL | 如果使用了O_CREAT而且文件已经存在,就会发生一个错误 |
O_TRUNC | 如果文件已经存在,则删除文件的内容 |
(ps: ls -l 指令可查看所在目录所有文件的权限)
mode:权限设置
Linux总共用5个数字来表示文件的各种权限:第一位表示设置用户ID;第二位表示设置组ID;第三位表示用户自己的权限位;第四位表示组的权限;最后一位表示其他人的权限。每个数字可以取1(执行权限)、2(写权限)、4(读权限)、0(无)或者是这些值的和。例如,要创建一个用户可读、可写、可执行,但是组没有权限,其他人可以读、可以执行的文件,并设置用户ID位。那么,我们应该使用的模式是0(不设置用户ID)、0(不设置组ID)、6(2+4,读、写、不可执行)、0(没有权限)、0(没有权限)即00600:
返回
文件描述符
二、关闭文件
int close(int fd);
头文件
#include
参数
文件标识符
返回
成功的话,返回0;失败的话,返回-1。
三、写操作
ssize_t write(int fd, const void *buf, size_t count);
头文件
#include
参数
fd:文件标识符
buf:写入缓冲指针
count:写入字节大小
返回
成功的话,返回已经写入字节大小;失败的话,返回-1。
四、读操作
ssize_t read(int fd, void *buf, size_t count);
头文件
#include
参数
fd:文件标识符
buf:读出缓冲指针
count:读出字节大小
返回:成功的话,返回已经读出字节大小;失败的话,返回-1。
五、光标定位
off_t lseek(int fd, off_t offset, int whence);
头文件
#include
#include
参数
fd:文件标识符
offset:相对于whence的偏移值
正数往文件尾位置走,负数往文件头位置走。
whence:当前光标位置
参数 | 功能 |
---|---|
SEEK_SET | 文件头位置 |
SEEK_CUR | 文件当前位置 |
SEEK_END | 文件尾位置 |
返回
当前位置相对于文件头位置的第几个字节数
例程1:编写一个程序,在当前目录下打开用户可读写文件“test",如果不存在该文件,创建文件。在其中写入“hello linux!”,关闭该文件。再次打开该文件,读取其中的内容并输出在屏幕上。
#include
#include
#include
#include
#include
#include
#include
int main(){
int fd;
fd=open("test",O_RDWR);
char *write_buf="hello linux!";
if(fd==-1)
{
printf("no file\n");
fd=open("test",O_RDWR|O_CREAT,0600);
printf("file creat success\n");
}
int n_write=write(fd, write_buf, strlen(write_buf));
char *read_buf=(char*)malloc(sizeof(char)*n_write+1);
if(n_write==-1)
printf("write fail!\n");
close(fd);
fd=open("test",O_RDWR);
int n_read=read(fd,read_buf,n_write);
if(n_read==-1)
printf("read fail");
printf("fd=%d\n",fd);
printf("read_count:%d context:%s\n",n_read,read_buf);
close(fd);
return 0;
}
例程2:编写一个程序,在当前目录下打开用户可读写文件“test",如果不存在该文件,创建文件。在其中写入“hello linux!”,移动光标到文件头位置,读取其中的内容并输出在屏幕上。
#include
#include
#include
#include
#include
#include
#include
int main(){
int fd;
fd=open("test",O_RDWR);
char *write_buf="hello linux!";
if(fd==-1)
{
printf("no file\n");
fd=open("test",O_RDWR|O_CREAT,0600);
printf("file creat success\n");
}
int n_write=write(fd, write_buf, strlen(write_buf));
char *read_buf=(char*)malloc(sizeof(char)*n_write+1);
if(n_write==-1)
printf("write fail!\n");
lseek(fd,0,SEEK_SET);
int n_read=read(fd,read_buf,n_write);
if(n_read==-1)
printf("read fail");
printf("fd=%d\n",fd);
printf("read_count:%d context:%s\n",n_read,read_buf);
close(fd);
return 0;
}
例程3:编写一个程序,通过lseek函数,可以巧妙地获取文件大小,即字节数大小,并输出在屏幕上。
#include
#include
#include
#include
#include
#include
#include
int main(){
int fd;
fd=open("test",O_RDWR);
char *write_buf="hello linux!";
if(fd==-1)
{
printf("no file\n");
fd=open("test",O_RDWR|O_CREAT,0600);
printf("file creat success\n");
}
printf("fd=%d\n",fd);
int size=lseek(fd,0,SEEK_END);
printf("file size=%d\n",size);
close(fd);
return 0;
}
open函数补充
对于打开文件open函数,flag参数我们只使用了O_RDWR 和O_CREAT,下面我们对其他常数进行验证。
常数 | 功能 |
---|---|
O_APPEND | 以追加的方式打开文件 |
O_CREAT | 创建一个文件 |
O_EXCL | 如果使用了O_CREAT而且文件已经存在,就会发生一个错误 |
O_TRUNC | 如果文件已经存在,则删除文件的内容 |
例程4:使用O_APPEND常数在文件尾部位置添加数据。
#include
#include
#include
#include
#include
#include
#include
int main(){
int fd;
fd=open("test",O_RDWR|O_APPEND);
char *write_buf="hello linux!\n";
if(fd==-1)
{
printf("no file\n");
fd=open("test",O_RDWR|O_CREAT|O_APPEND,0600);
printf("file creat success\n");
}
printf("fd=%d\n",fd);
int size=lseek(fd,0,SEEK_END);
printf("file size=%d\n",size);
int n_write=write(fd, write_buf, strlen(write_buf));
if(n_write==-1)
printf("write fail!\n");
close(fd);
return 0;
}
例程5:使用O_EXCL常数判断文件是否存在。
#include
#include
#include
#include
#include
#include
#include
int main(){
int fd;
fd=open("test",O_RDWR|O_CREAT|O_EXCL,0600);
if(fd==-1)
{
printf("file already exist\n");
return -1;
}
else
{
printf("file creat success\n");
}
close(fd);
return 0;
}
例程6:使用O_TRUNC常数覆盖原文件。
#include
#include
#include
#include
#include
#include
#include
int main(){
int fd;
fd=open("test",O_RDWR|O_TRUNC);
char *write_buf="hello linux!\n";
if(fd==-1)
{
printf("no file\n");
fd=open("test",O_RDWR|O_CREAT,0600);
printf("file creat success\n");
}
printf("fd=%d\n",fd);
int size=lseek(fd,0,SEEK_END);
printf("file size=%d\n",size);
int n_write=write(fd, write_buf, strlen(write_buf));
if(n_write==-1)
printf("write fail!\n");
close(fd);
return 0;
}
例程7:实现复制文件cp指令。
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char** argv){
int src_fd,des_fd;
if(argc!=3)
{
printf("arguments errors!\n");
return -1;
}
src_fd=open(argv[1],O_RDWR);
if(src_fd==-1)
{
printf("src file don't exist\n");
return -1;
}
int size=lseek(src_fd,0,SEEK_END);
lseek(src_fd,0,SEEK_SET);
des_fd=open(argv[2],O_RDWR|O_CREAT,0600);
char *read_buf=(char*)malloc(sizeof(char)*size+1);
int n_read=read(src_fd,read_buf,size);
if(n_read==-1)
printf("read fail\n");
printf("read_count:%d context:%s\n",n_read,read_buf);
int n_write=write(des_fd, read_buf, strlen(read_buf));
if(n_write==-1)
printf("write fail!\n");
close(src_fd);
close(des_fd);
return 0;
}
例程8:实现配置文件的配置。
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char** argv){
int fd;
char* find_str=malloc(128);
char* value=malloc(128);
if(argc!=3)
{
printf("arguments errors!\n");
return -1;
}
strcpy(find_str,argv[1]);
strcpy(value,argv[2]);
fd=open("config",O_RDWR);
if(fd==-1)
{
printf("no config file\n");
return -1;
}
int size=lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);
char *read_buf=(char*)malloc(sizeof(char)*size+1);
int n_read=read(fd,read_buf,size);
if(n_read==-1)
printf("read fail");
char* str_start=strstr(read_buf,find_str);
if(str_start==NULL)
{
printf("no designative argument!\n");
return -1;
}
str_start+=strlen(find_str)+1;
while(1)
{
if(*str_start=='\n')
break;
*str_start=*value;
str_start++;
value++;
}
printf("read_count:%d context:\n%s\n",n_read,read_buf);
lseek(fd,0,SEEK_SET);
int n_write=write(fd, read_buf, strlen(read_buf));
if(n_write==-1)
printf("write fail!\n");
close(fd);
return 0;
}
例程9:写一个整数到文件。
#include
#include
#include
#include
#include
#include
#include
int main(){
int fd;
int data1=0;
int data2=75;
fd=open("test",O_RDWR);
if(fd==-1)
{
printf("no file\n");
fd=open("test",O_RDWR|O_CREAT,0600);
printf("file creat success\n");
}
int n_write=write(fd, &data2,sizeof(data2));
if(n_write==-1)
printf("write fail!\n");
lseek(fd,0,SEEK_SET);
int n_read=read(fd,&data1,sizeof(data1));
if(n_read==-1)
printf("read fail");
printf("fd=%d\n",fd);
printf("read_count:%d context:%d\n",n_read,data1);
close(fd);
return 0;
}
例程10:写一个结构体到文件。
#include
#include
#include
#include
#include
#include
#include
typedef struct Stu{
int age;
char* name;
}stu,*pstu;
int main(){
int fd;
pstu stu1=(pstu)malloc(sizeof(stu));
stu1->age=21;
stu1->name="xiaoming";
pstu stu2=(pstu)malloc(sizeof(stu));
fd=open("test",O_RDWR);
if(fd==-1)
{
printf("no file\n");
fd=open("test",O_RDWR|O_CREAT,0600);
printf("file creat success\n");
}
int n_write=write(fd, stu1,sizeof(stu));
if(n_write==-1)
printf("write fail!\n");
lseek(fd,0,SEEK_SET);
int n_read=read(fd,stu2,sizeof(stu));
if(n_read==-1)
printf("read fail");
printf("fd=%d\n",fd);
printf("read_count:%d context:%d %s\n",n_read,stu1->age,stu1->name);
close(fd);
return 0;
}
Linux提供的虚拟文件系统为多种文件系统提供了统一的接口,Linux的文件编程有两种途径:基于Linux系统调用;基于C库函数。这两种编程所涉及到文件操作有新建、打开、读写和关闭,对随机文件还可以定位。本章对基于Linux系统调用方法给出了非常具体的实例。