文件编程
Linux操作系统提供一系列的API
打开 open
写 读 write read
光标定位 lseek
关闭 close
1.open 函数
(1).使用包含的头文件
open函数使用需要有三个头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char*pthnane,int flags);
int open(const char*pthname,int flags,mode_t mode)
文件创建函数
int creat(const char *pathname, mode_t mode);
**pthname:**表示要打开的文件名(含文件路径,缺失则为当前路径)
这里我们要使用的绝对路径
比如当前使用的是./ 这个表示的使用的是当前目录
当我们想要打开不是当前目录的文件的时候
我们需要使用它的路径 /home/sp/wenjian/test.c 来打开文件
*
(2)打开方式
flags
这三个只能任选其一
只读打开 O_RDOLNY
只写打开 O_WRONLY
可读可写打开 O_RDWR
1.演示
第一种方法创建方式
include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;//文件标识符
fd=open("./file1",O_RDWR);//open的使用 字符串本身就是指针,后面的参数定义文件打开方式
printf("fd=%d\n",fd);//输出fd
return 0;
}
输出结果 fd为3
如果把file1这个文件删除以后,fd变为了-1
返回值为-1 表示打开失败了
以下的常量是选用的,这些选项是用来和上面的必选项进行按位或起来作为flags参数。
O_APPEND 表示追加,如果原来文件里面有内容,则这次写入会写在文件的最末尾。
O_CREAT 表示如果指定文件不存在,则创建这个文件
O_EXCL 表示如果要创建的文件已存在,则出错,同时返回 -1,并且修改 errno 的值。
O_TRUNC 表示截断,如果文件存在,并且以只写、读写方式打开,则将其长度截断为0。
O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式(nonblocking mode)
以下三个常量同样是选用的,它们用于同步输入输出
O_DSYNC 等待物理 I/O 结束后再 write。在不影响读取新写入的数据的前提下,不等待文件属性更新。
O_RSYNC read 等待所有写入同一区域的写操作完成后再进行
O_SYNC 等待物理 I/O 结束后再 write,包括更新文件属性的 I/O
第二种方法创建方式
读写方式和下面的常量选项一起使用,通过 | 或的方式使用
fd=open("./file1",O_RDWR|O_CREAT,0600);//使用第二种方法创建
使用创建函数只会让创建 不能知道文件是否存在 fd一直为3
通过O_EXCL判断文件是否存在
两个参数一起使用,通过或一起使用
如果该文件存在的话需要在判断语句中重新打开文件
因为创建的O_EXCL 有文件的话返回值是-1 默认打开文件失败 不会执行后面的write或者read
fd=open("./file1",O_RDWR|O_CREAT|O_EXCL,0600);
//需要记得添加权限
if(fd==-1){
printf("已经有了file1这个文件\n");
fd=open("./file1",O_RDWR);
}else{
printf("创建成功\n");
}
O_APPEND 表示追加,
在文件的最后面写入,不会清除文件的内容
不加入这个函数,会在原有的文件内容,的头部位置,改变写入字节数相同的字节数。
如果原来文件里面有内容,则这次写入会写在文件的最末尾。
在文件末尾的地方插入, 在file1的最后面插入 supeng hen shuai
char *buf="supeng hen shuai ";
fd=open("./file1",O_RDWR|O_APPEND,0600);
write(fd,buf ,strlen(buf));
O_TRUNC 表示截断
如果文件存在,并且以只写、读写方式打开,则将其长度截断为0。
把文件里面所有的东西去除,只显示写入的东西
char *buf="supeng hen shuai ";
fd=open("./file1",O_RDWR|O_TRUNC,0600);
write(fd,buf ,strlen(buf));
3、mode:
mode参数表示设置文件访问权限的初始值,和用户掩码umask有关,比如0644表示-rw-r–r–,也可以用S_IRUSR、S_IWUSR等宏定义按位或起来表示,详见open(2)的Man Page。要注意的是,有以下几点
文件权限由open的mode参数和当前进程的umask掩码共同决定。
第三个参数是在第二个参数中有O_CREAT时才作用,如果没有,则第三个参数可以忽略
文件创建
PWD 指令 到绝对路径
S_IRUSR 00400 读
S_IWUSR 00200 写
S_IXUSR 00100 可执行
S_IRWXG 00070 读写可执行
int creat(const char *pathname, mode_t mode);
creat("/home/CLC/file1",S_IRWXG);//在home CLC
//下面创建file1文件 并把该文件作为可读可写可执行
2.write 函数
#include <unistd.h>
ssize_t write(int fd, const void* buf, size_t count);
参数:
fd:需要写的文件描述符;
buf:将buf中的内容写入 fd中,一个缓冲区的字节写入fd
count: 一次写入的字节数
int fd;
char *buf="nihao nianqingren";
fd=open("./file",O_RDWR);
if(fd==-1){
fd=open("./file",O_RDWR|O_CREAT,0600);
}
int cmd;
cmd=write(fd,buf,strlen(buf));
printf("cmd=%d\n",cmd);//会显示写入的字节数
3.read函数
(1)函数使用
读操作
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
使用write函数写入到文件以后,光标会移动到最后的地方
我们需要使用光标移动的指令 但是可以关闭文件重新打开
write(fd,buf,strlen(buf));
char *readBuf;
readBuf=(char *)malloc(sizeof(char) *128);
close(fd);
fd=open("./file",O_RDWR);
read(fd,readBuf,128);
printf("内容:%s\n",readBuf);
4.close 关闭文件函数
close(fd);
5.lseek 光标移动函数
(1)光标的使用
//包含的两个头文件
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
fd 表示操作的文件
offset 是一个偏移值,对whence的偏移值
偏移值为负数,表示向前面偏移
偏移值为正数,表示向后偏移
whence 有三个位置,下面表示光标现在处在的三个位置
SEEK_SET //表示文件的头
The offset is set to offset bytes.
SEEK_CUR //表示当前光标位置
The offset is set to its current location plus offset bytes.
SEEK_END //表示尾巴
The offset is set to the size of the file plus offset bytes.
- 欲将读写位置移到文件开头时:lseek(int fildes, 0, SEEK_SET);
- 欲将读写位置移到文件尾时:lseek(int fildes, 0, SEEK_END);
- 想要取得目前文件位置时:lseek(int fildes, 0, SEEK_CUR);
上面的read函数就可以直接使用sleek函数
sleek(fd,0,SEEK_SET); //把光标移动到文件的头
read(fd,readBuf,128);
//这样就可以直接读取
(2)光标统计文件长度
sleek的返回值是 基于头的偏移地址 基于头偏移了多少字节
int lseekLong = sleek(fd,0,SEEK_END);
printf("lseekLong=%d\n",lseekLong);
这里当前读写位置是尾巴 ,就是说他和文件的开头有多少个字节,通过返回值显示出来,从而达到测出来该文件大小是多少。
6.文件描述符
1、对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一一个非负整数。当打开一个现存文件或者创建一个新文件时,内核向进程返回一个文件
描述符。当读写一个文件时,用open和creat返回的文件描述符标识该文件,将其作为参数传递给read和write。
按照惯例,UNIX shell使用文件描述符0与进程的标准输入相结合,文件描述符1与标准输出相结合,文件描述符2与标准错误输出相结合。STDIN FILENO、STDOUT. FILENO、STDERR FILENO这几个宏代替了0、1、2这几个
系统中有三个默认的文件输入符
fd0 :表示标准输入
fd1: 表示标准输出
fd2:表示标准错误
2、文件描述符,这个数字在一-个进程中表示-一个特定含义,当我们open- -个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回
给应用程序一个数字作为文件描述符,这个数字就和我们内存中维护的这个动态文件的这些数据结构绑定上了,以后我们应用程序如果要操作这个动态文件,只
需要用这个文件描述符区分。
3、文件描述符的作用域就是当前进程,出了这个进程文件描述符就没有意义了。
open函数打开文件,打开成功返回一个文件描述符,打开失败,返回-1。
char *buf;
buf=(char*)malloc(sizeof(char)*128);
read(0,buf,5);//在标准输入里面输入5个字节
write(1,buf,5);//在标准输出里面显示5个字节
printf("\n输入完成\n");
内核在内存申请一段内存就是相当于buf 缓存区 开辟空间
使用open 会打开动态文件
在内核生成一个结构体存放fd buf 文件
使用read write 会把内核中的buf文件使用 操作的都是动态文件
使用close的时候会把buf的内容写到磁盘当中
7.文件操作小练习 cp指令的实现
首先介绍main函数的参数
所以我们见到的main函数的原型多是下面这种 形式:
int main ( int argc, char* argv[]),
参数argc代表了输入参数的个数,
char *argv[]表示传入的参数的字符串,是一个字符串数组。
#include <stdio.h>
int main(int argc,char *argv[])
{
printf("创建参数%d\n",argc);
printf("N.01 %s\n",argv[0]);
printf("N.02 %s\n",argv[1]);
printf("N.03 %s\n",argv[2]);
return 0;
}
输出结果
CLC@Embed_Learn:~$ ./a.out dst crt 显示的输出的这三个
canshugeshu3
N.01 ./a.out
N.02 dst
N.03 crt
创建步骤
首先打开 dst文件
读取dst的buf read
打开或者创建crt文件 open
把dst的buf写入crt文件 write
关闭crt文件和dst文件
int main(int argc,char *argv[] )
{
int fddest;
int fdnode;
char *readBuf=NULL;//创建一个readBuf指针
if(argc!=3){
printf("程序错误,退出\n");
exit(-1);//表示退出程序
}
fddest=open(argv[1],O_RDWR);//打开复制的文件
int lseeklong=lseek(fddest,0,SEEK_END);//通过上面的知识用lseek打印出来文件的大小
lseek(fddest,0,SEEK_SET);//前面通过sleek,把光标弄到了最后,这里还要通过sleek把光标挪到文件头
//给readBuf开辟空间,开辟上面lseeklong+8个空间
//memset赋初值函数
readBuf=(char*)malloc(sizeof(char)*lseeklong+8);
//读取复制文件的信息,到缓存区readBuf
int n_read=read(fddest,readBuf,lseeklong);
//打开去复制的函数
//在这里打开文件 如果没有创建文件,如果有的话,把创建的文件里面的内容清空,然后再进行下面的写操作
fdnode=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);
//把缓存区的内容写到新的文件里面去
write(fdnode,readBuf,strlen(readBuf));
//关闭两个文件
close(fddest);
close(fdnode);
return 0;
}
8.文件编程小应用 修改程序配置
int main()
{
int fd;
char *findBuf;//寻找到的字符串存放
fd = open("./file",O_RDWR);
if(fd>0){
printf("open success\n");
}else{
printf("file cunzai\n");
}
int lseekLong = lseek(fd,0,SEEK_END);//统计文件长度
char *readBuf;
char *p;
lseek(fd,0,SEEK_SET);
readBuf = (char *)malloc(sizeof(char)*lseekLong);//开辟空间
read(fd,readBuf,lseekLong);
findBuf=strstr(readBuf,"long");//寻找long出现的地方 并返回
//hsjdfsd 你的字串是df 则会返回 fdsd
if(findBuf == NULL){
printf("NO find\n");
close(fd);
exit(-1);
}
findBuf=findBuf+strlen("long = ");//让找到的字符偏移long = 个字节
*findBuf='6'; //将改为变成 字符6
findBuf=findBuf+1;
*findBuf='5'; //将改为变成字符5
lseek(fd,0,SEEK_SET);//SEEK_SET //将fd放到文件开头
//把存在缓存区里面的内容写入进去
write(fd,readBuf,strlen(readBuf)); //把缓存区的内容再次写入文件中
close(fd);
return 0;
}
9.把结构体(数组)写入文件当中
write函数的第二个参数是一个void *型的指针 相当于表示的是一个地址
struct test
{
int a;
short b;
};
int main()
{
int fd;
struct test t1={0,2};
struct test t2;
fd=open("./file",O_RDWR);
if(fd<0){
printf("打开文件失败\n");
exit(-1);
}
int n_write;
n_write=write(fd,&t1,sizeof(struct test));
lseek(fd,0,SEEK_SET); //把光标挪到文件的头部
read(fd,&t2,n_write);//读取到t2上面
printf("a=%d b=%d\n",t2.a,t2.b);
close(fd);
return 0;
}
把结构体数组写入文件
//定义两个结构体数组***************
struct test t1[2]={{100,'c'},{101,'d'}};
struct test t2[2];
fddest=open("./file1",O_RDWR);
//把结构体写入文件
int n_write=write(fddest,&t1,sizeof(struct test)*2);
lseek(fddest,0,SEEK_SET);//移动光标到文件前面
int n_read=read(fddest,&t2,sizeof(struct test)*2);
printf(" %d %c\n",t2[0].a,t2[0].c);
printf(" %d %c\n",t2[1].a,t2[1].c);
close(fddest);
标准C语言库的文件操作函数
存放在#include <stdio.h>
1.fopen函数
fopen 函数
r 打开只读文件,该文件必须存在。
r+ 打开可读写的文件,该文件必须存在。
rb 打开一个二进制文件,只读。
rb+ 以读/写方式打开一个二进制文件。
w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
wb 打开一个二进制文件,只写。
wb+ 以读/写方式建立一个新的二进制文件。
a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。
a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。
ab 打开一个二进制文件,进行追加 。
ab+ 以读/写方式打开一个二进制文件进行追加 。
FILE *fd;//创建一个文件描述符
//FILE * fopen(const char * path,const char * mode);
fd=fopen("./su.txt","w+");//第二个在函数原型是一个指针 字符串本身表示的就是一个指针,所以这里要用 " "
2.fwrite函数
char *buf="chuangjain";
//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
//函数原型
//函数使用
fwrite(buf,sizeof(char),strlen(buf),fd);
fwrite(buf,sizeof(char)*strlen(buf),1,fd);
//有两种创建方式
//函数的第一个是字符串,第二个是一个的大小,第三个是执行的次数,最后是文件描述符
fread, fseek fclose ftell
ftell函数是用来获取文件的当前读写位置;
函数原型: long ftell(FILE *fp)
函数功能:得到流式文件的当前读写位置,其返回值是当前读写位置偏离文件头部的字节数.
ban=ftell(fp); 是获取fp指定的文件的当前读写位置,并将其值传给变量ban.
//函数原型
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
//函数的使用
char *readBuf=NULL;//创建读取的内容放置的缓存区
***************************
fseek(fd,0,SEEK_SET);//计算文件的大小
int slong=ftell(fd);//得到偏移多少
分析:可以用fseek函数把位置指针移到文件尾,
再用ftell函数获得这时位置指针距文件头的字节数,这个字节数就是文件的长度.
fseek(fd,0,SEEK_SET);//把光标挪到文件头
readBuf=(char*)malloc(sizeof(char)*fseekLong+8);//开辟空间
fread(readBuf,sizeof(char),strlen(buf),fd);//读取文件
fclose(fd);
fread fwrite
返回值取决于第三个参数
也就是上面说的执行次数 执行多少次,虽然没有那么多的内容,但是还是要执行 fwrite的返回值就是多少
fread的返回值和执行多少次没有关系 只要把缓存区的内容执行完,那么返回值就是多少
重要提示,只有fread或者fwrite这样写才能得到写入或者读取数据个数
只有每次读取一个字节,读取N次才能得到读取数据个数
int ret;
char buf[128]={'\0'};
FILE *fdr=NULL;
ret=fread(buf,1,sizeof(buf),fdr);
fputc
int fputc(int c, FILE *stream);
**char本质也是-128-127的int,因此也可以用int存放char**
int fputs(const char *s, FILE *stream);
int putc(int c, FILE *stream);
FILE *fd;
char *str="nihao xiaohuozi";
fd=fopen("./su.txt","w+");
int cmd = strlen(str);
int i;
for(i=0;i<cmd;i++){
fputc(*str,fd);
str++;
}
close(fd);
fgetc feof
函数原型
int fgetc(FILE *stream);
char *fgets(char *s, int size, FILE *stream);
int getc(FILE *stream);
int feof(FILE *stream);
feof()是检测流上的文件结束符的函数,如果文件结束,则返回非0值,否则返回0
FILE *fd;
fd=fopen("./su.txt","r");
char c;
while(!feof(fd)){
c=fgetc(fd);//通过fgetc函数得到字符
printf("%c",c);//显示出来字符
}
fclose(fd);