概念引入
window ,linux如何修改一个文件,比如写一个word文档:
打开/创建文件 -->编辑文件 -->保存文件 -->关闭文件
我们需要使用代码自动化完成以上操作:
操作系统(linux)给我们提供了一系列的API:
打开: open
读写: read/write
光标定位: lseek
关闭: close
===========================================
文件描述符:
也就是文件的索引, 对于内核而言,所有文件都由文件描述符引用。 文件描述符是一个非负整数。
打开/创建文件-- 返回文件描述符
读写文件需要文件描述符作为参数传递
注意: 文件描述符的作用域是当前进程 ,出了这个进程文件,描述符没有任何意义
linux 系统默认文件描述符:
0 -- >标准输入(也就是键盘) 1-->标准输出 2 -->标准错误, so我们open文件的时候返回的fd从3开始
0 1 2对应的宏分别为: STDIN_FILENO STDOUT_FILENO STDERR_FILENO
------------------
编程应用:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>int main()
{
char readBuf[128];
read(0,readBuf,5);
write(1,readBuf,strlen(readBuf));
puts("");
return 0;
}
--------------------------------
注意: 使用完文件后,要close() 关闭,防止文件损坏
存在磁盘中的文件 -- 静态文件
open 静态文件 后,在linux 内核产生结构体,来存放fd,buf(内存)等数据 -- 这时候就是动态文件
调用close() -- 会把缓冲区buf的所有东西写入磁盘中
// 为什么需要动态文件:磁盘的最小读取单位就是一个块。属于块设备
快设别十分的不灵活,是快读写,而内存是按字节单位操作的,而且可以随机操作,很灵活
打开/创建文件:
打开文件open()
返回值 --文件描述符,起到索引作用
需要头文件:
<sys/types.h><sys/stat.h> <fcntl.h>
函数原型
int open(const char*pathname,int flags);
int open(const char*pathname,int flags,mode_t mode);
pathname --要打开的的文件路径,可省略--当前路径
flags 打开方式:O_RDONLY 只读打开 O_WRONLY 只写打开 O_RDWR 可读可写
以上常数只能指定一个 ,但是以下常数可选择:
flags|后续常数:
O_CREAT -- 若文件不存在就创建他
O_EXCK 如果同时指定了O_CRATE,文件已经存在,则返回值为-1 --> 判断文件是否存在
O_APPEND -- 从文件的末尾写入数据 -- 如果不加 append 的话,原来的内容可能会被覆盖
O_TRUNC 属性去打开文件时,if这个文件是有内容的,而且为只读or只写成功打开。则将其长度截短为0
--意识就是清空文件,然后重写写入内容mode: 文件权限:
常用 权限:
1.可读 r --4
2.可写 w --2
3.执行:x --1
比如6: 4+2 rw_0600 -- 给文件所有者读写权限
-------------------------------------------------------
为了简化表达,我们还可以采取数字表示代替ugo,二进制0~7代表三种权限:
把rwx记为421 : r-4 w-2 x-1
0:无任何权限 000 ---
1: 只有x权限 000 --x
2:只有w权限 010 -w-
3:011 -wx
4:100 r--
5: 101 r-x
6: 110 rw-
7:全部权限:111 rwx
————————————————
文件权限详细理解和操作,建议移步 3 linux入门 -- 用户和权限-CSDN博客
创建文件:create()
需要头文件:
<sys/types.h><sys/stat.h> <fcntl.h>
返回值也是 fd -- 文件描述符
函数原型:
int create(const char *filename,mode_t mode);
filename: 创建文件名,包含路径,省略就是当前路径
mode 创建模式//以什么权限创建
常见mode:
S_IRUSR 4 可读
S_IWUSR 2 可写
S_IXUSR 1 可执行
S_IRWXU 7 可读,写,执行
验证程序:
-------------------------
case1 -- open正常打开返回值
if 文件存在就放回 3,4,5等 非负整数,不存在放回-1
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int fd;
fd=open("./file1",O_RDWR);
printf("fd=%d\n",fd);return 0;
}
--------------------
case2:文件不存在,我们使用O_CREAT创建
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int fd;
fd=open("./file1",O_RDWR);
if(fd==-1){
puts("open fail!!!");
fd=open("./file1",O_RDWR|O_CREAT,0600);
if(fd>0){
printf("create succeed fd=%d\n",fd);
}
}
return 0;
}
----------------------------------
case3: O_EXCL验证文件是否存在
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>int main()
{
int fd;
char *buf="mxdashuaibi";
fd=open("./file1",O_RDWR|O_CREAT|O_EXCL,0600);
if (fd==-1)
{
puts("文件已经存在。");
}
close(fd);
return 0;
}
题外话 -怎么判断-1 ---位运算: ~fd --> -1 取反为0,-1 的补码是 11111111 反码就是 00000000
========================================
文件写入操作 write ()
函数原型:
ssize_t write(int fd,const void *buf,size_t count);
需要头文件: <unistd.h>
返回值: 写入成功返回写入大小 ,失败返回-1
fd--文件操作符
buf -- 缓冲区
count -- 需要向文件写入的大小
意思: buf指针指向的缓冲区拿出count的空间写入数据到fd指向的空间中(目标文件中)
注意:这里不要用sizeof 拿到buf 的大小 -- 因为buf是一个指针只能读取8个字节大小的数据
case: write 基本用法:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
int fd;
char *buf="mxdashuaibi";
fd=open("./file1",O_RDWR);
if((~fd)){
puts("open fail!!!");
fd=open("./file1",O_RDWR|O_CREAT,0600);
if(fd>0){
printf("create success fd=%d\n",fd);
}
}
puts("写操作。");
///write(fd,(void*)buf,sizeof(buf)); //错误示范
write(fd,(void*)buf,strlen(buf));
close(fd);
return 0;
}
=============
关闭文件 -- close
头文件 <unistd.h>
int close(int fd);
返回值: 0 -- 成功 -1 -- 失败
===========================
读取文件 : read()
函数原型:
ssize_t read(int fd,const void *buf,size_t count);
头文件:<unistd.h>
返回值: 读到多少字节返回多少字节 -- 读到文件尾巴--返回0,读取失败 -1
注意:
如果 在read之前进行了 写操作,我们的的光标位置应该在最后一次写的操作,一般就是文件末尾
这时候读取的数据是不准确的,我们需要将光标移动 到头: 两种方式
1.移动光标到头
2.重新打开文件
case: 基本读取操作
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>int main()
{
int fd;
char *buf="mxdashuaibi";
fd=open("./file1",O_RDWR);
if((~fd)){
puts("open fail!!!");
fd=open("./file1",O_RDWR|O_CREAT,0600);
if(fd>0){
printf("create success fd=%d\n",fd);
}
}
puts("写操作。");
///write(fd,(void*)buf,sizeof(buf)); //错误示范
int cnt_w=write(fd,(void*)buf,strlen(buf));
if(cnt_w!=-1){
printf("Have writed %d byte to file1.\n",cnt_w);
}
close(fd);
fd=open("./file1",O_RDWR);
char *readBuf =(char*)malloc(sizeof(char)*(cnt_w+1));
int cnt_r=read(fd,readBuf,cnt_w);
printf("Have read %d byte to file1.\n",cnt_r);
close(fd);
return 0;
}
================================
光标移动操作: lseek
函数原型:
off_t lseek(int fd,off_t offset,int whence) -- 将文件读写指针相对whnece 移动 offset个字节
需要头文件:<sys/types.h> <unistd.h>
whence 包括三个宏:
SEEK_SET -- 文件头
SEEK_END ---文件尾
SEEK_CNT--当前光标位置
offset -- 对whence 的一个偏移值
返回值: 针对文件头 偏移了多少个字节 -- 可以用来计算文件大小
case:怎么计算文件大小:
int FileSize=lseek(fd, 0,SEEK_END);
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>int main()
{
int fd;
char *buf="mxdashuaibi";
fd=open("./file1",O_RDWR);///write(fd,(void*)buf,sizeof(buf)); //错误示范
int cnt_w=write(fd,(void*)buf,strlen(buf));
int fileSize = lseek(fd,0,SEEK_END);
printf("fileSize: %d\n",fileSize);close(fd);
return 0;
}
命令应用实例:
实现linux cp命令的代码:
命令格式;
cp src.c des.c
C语言参数:
int main(char argc, char**argv);
argc -- 参数的总个数
argv -- 包含的参数,每一个参数都是一个数组 ./aout(cp) src des
思路:
1.打开 src.c
2.读取src.c的全部数据到buf
3.创建一个新文件 des.c
4.将buf里面的内容写入des.c
5.关闭两个 文件
gcc demo.c -o mycp // -o指定生成的可执行文件名字
./mycp
写自己的cp命令
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.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)
{
puts("param error!");
exit(-1);
}
fdSrc=open(argv[1],O_RDWR);
int size = lseek(fdSrc,0,SEEK_END);
lseek(fdSrc,0,SEEK_SET);//记把光标位置移动到头,不然下面的read读不到数据
readBuf= (char *)malloc(sizeof(char)*size);
int n_read=read(fdSrc,readBuf,size);
fdDes=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);// 新文件设为读写权限,if文件不存在创建一个,if文件已经存在删除全部内容添加我们拷贝的内容
int n_write=write(fdDes,readBuf,strlen(readBuf));close(fdDes);
close(fdSrc);
return 0;
}==================================
编程实现修改文件里面的某一项:
把文件第二行 length = 3; 的3修改为4
涉及字符串的操作,比如我们的有几个常用API:
strstr() -- 在一个3母串里面去找一个子串,并返回子串的位置,没找到就返回NULL
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>int main(int argc, char **argv)
{
int fdSrc;char *readBuf = NULL;
fdSrc = open(argv[1], O_RDWR);
int size = lseek(fdSrc, 0, SEEK_END);
lseek(fdSrc, 0, SEEK_SET);readBuf = (char *)malloc(sizeof(char) * (size+8));
int n_read = read(fdSrc, readBuf, size);
char *p = strstr(readBuf, "length=");
if (p == NULL)
{
puts("not found");
exit(-1);
}
p = p + strlen("length=");
*p = '5';// close(fdSrc);
// fdSrc = open(argv[1], O_RDWR|O_TRUNC);
lseek(fdSrc,0,SEEK_SET);write(fdSrc,readBuf,strlen(readBuf));
close(fdSrc);return 0;
}
================================
写入一个整数/结构体到文件:
一个整数
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>int main()
{
int fdSrc;
int data={100,'b'};
int data2;
fdSrc = open("./file1", O_RDWR);
int n_write = write(fdSrc,&data,sizeof(int));
lseek(fdSrc, 0, SEEK_SET);
int n_read=read(fdSrc,&data2,sizeof(int));
printf("data2 = %d\n",data2);
close(fdSrc);return 0;
}
一个结构体
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>struct Test
{
int a;
char b;
};int main()
{
int fdSrc;
struct Test data={100,'b'};
struct Test data2;
fdSrc = open("./file1", O_RDWR);
int n_write = write(fdSrc,&data,sizeof(struct Test));
lseek(fdSrc, 0, SEEK_SET);
int n_read=read(fdSrc,&data2,sizeof(struct Test));
printf("data2 = %d,%c\n",data2.a,data2.b);
close(fdSrc);return 0;
}
多个结构体:
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>struct Test
{
int a;
char b;
};
int main()
{
int fdSrc;
struct Test data[2]={{100,'b'},{101,'c'}};
struct Test data2[2];
fdSrc = open("./file1", O_RDWR);
int n_write = write(fdSrc,&data,sizeof(struct Test)*2);
lseek(fdSrc, 0, SEEK_SET);
int n_read=read(fdSrc,&data2,sizeof(struct Test)*2);
printf("data2[0] = %d,%c\n",data2[0].a,data2[0].b);
printf("data2[1] = %d,%c\n",data2[1].a,data2[1].b);
close(fdSrc);return 0;
}