目录
一、文件打开及创建
1、int open(const char *pathname,int flags);
包含3个头文件:#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>参数说明:pathname:要打开的文件名(含路径,缺省为当前路径)
flags:O_RDONLY 只读打开 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);
printf("fd = %d\n",fd);
return 0;
}
显示结果为:fd = 3
2、int open(const char *pathname,int flags,mode_t mode);
参数说明:
flags:
O_CREAT 若文件不存在则创建它。使用此选项时,需要同时说明第三个参数mode,用其说明该新文件的存取许可权限。
O_EXCL 如果同时指定了OCREAT,而文件已经存在,则出错返回值为-1。
O_APPEND 每次写时都加到文件的尾端。(写入文件时,不会覆盖原文件内容,加在原文件结尾。如果没有O_APPEND,则从头开始覆盖和新内容相同字节的原始内容。)
O_TRUNC 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0。(原内容全部删除,只有新写入的内容)
Mode:一定是在flags中使用了O_CREAT标志,mode记录待创建的文件的访问权限
例2:打开一个不存在的文件,获得一个返回值,并创建这个文件
如果不存在file1,则例1结果为:fd = -1
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;
fd = open("./file1",O_RDWR);
if(fd == -1){
printf("open file failed\n");
fd = open("./file1",O_RDWR|O_CREAT,0600);
if(fd > 0){
printf("create file1 success\n");
}
}
return 0;
}
//此时不存在file1,显示结果为open file failed,之后新建了file1,显示create file1 success
关于“0600”的设置:(给文件所有者的权限)
可读:r 对应数字为4
可写:w 对应数字为2
可执行: x 对应数字为1
0600即4+2,可读可写
创建creat的使用
1、int creat(const char *filename,mode_t mode)
参数说明:filename:要创建的文件名(包含路径,缺省为当前路径)
mode:创建模式
常见模式:
宏表示 数字 释义 S_IRUSR 4 可读 S-IWUSR 2 可写 S_IXUSR 1 可执行 S_IRWXU 7 可读可写可执行
二:写入文件
1、ssize_t write(int fd,const void *buf,size_t count);
参数说明:fd:哪个文件(文件描述符)
buf:缓冲区数据
count:数据字节数
返回值:写入数据的字节数,错误返回-1
例3: 打开一个文件,在文件中输入”WY is handsome!“
//打开文件所需的3个头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//打印所需要的头文件
#include <stdio.h>
//写和关闭文件所需头文件
#include <unistd.h>
//strlen所需头文件
#include <string.h>
int main()
{
int fd;
char *buf = "WY is handsome!"; //数据
fd = open("./file1",O_RDWR);
if(fd == -1){
printf("open file failed\n");
fd = open("./file1",O_RDWR|O_CREAT,0600);
if(fd > 0){
printf("create file1 success\n");
}
}
printf("open success:fd=%d\n",fd);
//写文件操作,将buf内的内容写入fd
//注意:此处不用sizeof,sizeof是buf指针的长度,strlen是内容字符串长度
write(fd,buf,strlen(buf));
//写完文件要关闭
close(fd);
return 0;
}
三:文件读取
1、ssize_t read(int fd,void *buf,size_t count);
参数说明:从fd中读取count个数据放入buf
返回值:读了多少个就返回字节数;如果什么都没有读到,则返回0;错误返回-1;
例4:将例3写入的内容读取出来
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
//malloc所需的头文件
#include <stdlib.h>
int main()
{
int fd;
char *buf = "WY is handsome!";
//--------打开文件
fd = open("./file1",O_RDWR);
if(fd == -1){
printf("open file failed\n");
fd = open("./file1",O_RDWR|O_CREAT,0600);
if(fd > 0){
printf("create file1 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 file1\n",n_write);
}
//--------读取文件
char *readBuf;
//给readBuf开辟空间,malloc返回的是void *,需要强转为char *
readBuf =(char *)malloc(sizeof(char)*n_write + 1);
//read函数返回值
int n_read = read(fd,readBuf,n_write);
//打印读取的字节数以及内容
printf("read %d,context:%s\n",n_read,readBuf);
close(fd);
return 0;
}
例4结果如下图:
出现问题:读取了0,内容也是空的
原因: 写入内容后,光标在内容后面,read的时候从光标处开始读取,所以什么都读取不到
解决:
①写入内容后,先关闭文件,再打开文件,此时读取就是从头开始读取,如下例5
例5:
#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;
char *buf = "WY is handsome!";
fd = open("./file1",O_RDWR);
if(fd == -1){
printf("open file failed\n");
fd = open("./file1",O_RDWR|O_CREAT,0600);
if(fd > 0){
printf("create file1 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 file1\n",n_write);
}
//写入之后先关闭文件,再打开文件
close(fd);
fd = open("./file1",O_RDWR);
//读取文件
char *readBuf;
readBuf =(char *)malloc(sizeof(char)*n_write + 1);
int n_read = read(fd,readBuf,n_write);
printf("read %d,context:%s\n",n_read,readBuf);
close(fd);
return 0;
}
例5结果如下图:
②重新定位光标,移动光标至头部,如下例6
1、off_t lseek(int fd,off_t offset,int whence);
参数说明:fd:文件描述符
offset:偏移值
whence:固定点位置
将文件读写指针相对whence移动offset个字节
offset:负数往前偏移,正数往后偏移
whence:SEEK_SET:头部位置;SEEK_END:尾部位置;SEEK_CUR:当前位置
例6:
#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;
char *buf = "WY is handsome!";
fd = open("./file1",O_RDWR);
if(fd == -1){
printf("open file failed\n");
fd = open("./file1",O_RDWR|O_CREAT,0600);
if(fd > 0){
printf("create file1 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 file1\n",n_write);
}
//例5的做法注释掉
//close(fd);
//fd = open("./file1",O_RDWR);
char *readBuf;
readBuf =(char *)malloc(sizeof(char)*n_write + 1);
//例6做法
lseek(fd,0,SEEK_SET);//头部偏移0
int n_read = read(fd,readBuf,n_write);
printf("read %d,context:%s\n",n_read,readBuf);
close(fd);
return 0;
}
基于lseek,可以计算文件大小,如下例7
例7:计算文件大小
#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;
char *buf = "WY is handsome!";
//打开文件
fd = open("./file1",O_RDWR);
//lseek返回值是“针对文件头偏移的字节数”
int filesize = lseek(fd,0,SEEK_END);
printf("file's size is %d\n",filesize);
close(fd);
return 0;
}
四、基于上述文件编程,编写实现cp(复制)功能的代码
1、实现步骤
①打开源文件(src.c)
②读src到buf
③打开/创建目标文件(des.c)
④将buf写入到des
⑤close两个文件
2、编程实现
#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 fdSrc;//原文件
int fdDes;//目标文件
char *readBuf = NULL;//存放数据的指针,指向空,防止野指针
//判断原文件是否正确,不正确直接中止程序
if(argc != 3){
printf("pararm error\n");
exit(-1);
}
//打开原文件
fdSrc = open(argv[1],O_RDWR);
//通过lseek读取文件内数据大小,读取完此时光标在末尾
int sizeSrc = lseek(fdSrc,0,SEEK_END);
//把光标移回到最前面
lseek(fdSrc,0,SEEK_SET);
//给数据保存区动态开辟空间
readBuf = (char*)malloc(sizeof(char)*sizeSrc + 8);
//将原文件内的内容读到数据保存区
read(fdSrc,readBuf,sizeSrc);
//打开/创建目标文件
fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);
//将数据保存区的数据写入到目标文件中
write(fdDes,readBuf,strlen(readBuf));
//关闭两个文件
close(fdSrc);
close(fdDes);
return 0;
}
五、基于上述文件编程,编写“修改程序的配置文件”的代码
1、实验说明
有一个file1文件,里面有如下内容:
SPEED=3
LENG=3
SCORE=9
LEVEL=5
现要修改LENG后面的3为5
2、编程实现
#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 fdSrc;
char *readBuf = NULL;
if(argc != 2){
printf("pararm error\n");
exit(-1);
}
fdSrc = open(argv[1],O_RDWR);
int sizeSrc = lseek(fdSrc,0,SEEK_END);
lseek(fdSrc,0,SEEK_SET);
readBuf = (char *)malloc(sizeof(char)*sizeSrc + 8);
read(fdSrc,readBuf,sizeSrc);
//将指针p指向LENG的开头
char *p = strstr(readBuf,"LENG=");
if(p==NULL){
printf("not found\n");
exit(-1);
}
//指针偏移到=后面
p = p+strlen("LENG=");
//指针取内容后修改为5
*p = '5';
//光标移动到开头
lseek(fdSrc,0,SEEK_SET);
write(fdSrc,readBuf,strlen(readBuf));
close(fdSrc);
return 0;
}
六、写一个整数到文件
直接整代码
#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;
//两个数据
int data1 = 100;
int data2 = 0;
//打开file1
fd = open("./file1",O_RDWR);
//将data1写入fd
write(fd,&data1,sizeof(int));
//光标移到头部
lseek(fd,0,SEEK_SET);
//读取fd,将数据保存在data2中
read(fd,&data2,sizeof(int));
printf("read:%d\n",data2);
close(fd);
return 0;
}
结果:
read:100
七、写一个结构体到文件
直接整代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
//结构体
struct Test
{
int a;
char b;
};
int main()
{
int fd;
struct Test data1 = {100,'w'};
struct Test data2;
fd = open("./file1",O_RDWR);
//结构体长度
write(fd,&data1,sizeof(struct Test));
lseek(fd,0,SEEK_SET);
read(fd,&data2,sizeof(struct Test));
printf("read:%d,%c\n",data2.a,data2.b);
close(fd);
return 0;
}
结果:
read:100,w
八、写一个结构体数组到文件
直接上代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
struct Test
{
int a;
char b;
};
int main()
{
int fd;
struct Test data1[2] = {{100,'w'},{101,'y'}};
struct Test data2[2];
fd = open("./file1",O_RDWR);
write(fd,&data1,sizeof(struct Test)*2);
lseek(fd,0,SEEK_SET);
read(fd,&data2,sizeof(struct Test)*2);
printf("read:%d,%c\n",data2[0].a,data2[0].b);
printf("read:%d,%c\n",data2[1].a,data2[1].b);
close(fd);
return 0;
}
结果:
read:100,w
read:101,y
九、标准C语言库的文件操作(open与fopen的区别)
1、来源不同
- open是UNIX系统调用函数(包括LINUX等),返回的是文件描述符(File Descriptor),它是文件在文件描述符表里的索引。
fopen
是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api。返回的是一个指向文件结构的指针。
2、移植性
fopen是标准C库函数,具有良好的可移植性,open函数是UNIX系统调用,移植性有限
3、适用范围
open
返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作普通正规文件(Regular File)。- fopen是用来操纵普通正规文件(Regular File)的。
4、文件IO层次
如果从文件IO的角度来看,前者属于低级IO函数,后者属于高级IO函数。低级和高级的简单区分标准是:谁离系统内核更近。低级文件IO运行在内核态,高级文件IO运行在用户态。
5、缓冲
①缓冲文件系统
缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用;当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓冲区”依此读出需要的数据。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind
等。
②非缓冲文件系统
缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。open, close, read, write, getc, getchar, putc, putchar
等。
十、标准C库打开创建文件读写文件以及光标移动
1、打开文件
FILE *fopen(const char *path,const char *mode);
参数说明:
path:路径
mode:打开模式
模式 说明 r 只读方式打开一个文本文件 rb 只读方式打开一个二进制文件 w 只写方式打开一个文本文件 wb 只写方式打开一个二进制文件 a 追加方式打开一个文本文件
ab 追加方式打开一个二进制文件 r+ 可读可写方式打开一个文本文件 rb+ 可读可写方式打开一个二进制文件 w+ 可读可写方式创建一个文本文件 wb+ 可读可写方式生成一个二进制文件 a+ 可读可写追加方式打开一个文本文件 ab+ 可读可写方式追加一个二进制文件
2、写入文件
size_t fwrite(const void *ptr,size_t size,size_t nmemb,FILE *stream);
参数说明:
ptr:缓冲区
size:一个字符的大小
nmemb:个数
stream:文件
返回值:第三个参数(个数)
3、读取文件
size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream);
参数说明:
ptr:缓冲区
size:一个字符的大小
nmemb:个数
stream:文件
返回值:第三个参数(个数)
4、光标
int fseek(FILE *stream, long offset, int whence);
与lseek参数说明相同
5、 关闭文件
fclose
6、实验:打开一个文件并写入数据,读取数据
代码实现:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;//文件
char *str = "wy is handsome";//数据
char readbuf[128] = {0};//缓冲区
fp = fopen("./wy.txt","w+");//打开文件
fwrite(str,sizeof(char),strlen(str),fp);//写入文件,一次写一个,写n次
// fwrite(str,sizeof(char)*strlen(str),1,fp);//另一种写法,一次写n个,写1次
fseek(fp,0,SEEK_SET);//光标重定位
fread(readbuf,sizeof(char),strlen(str),fp);//读文件到缓冲区
printf("data:%s\n",readbuf);
return 0;
}
十一、标准C库其他函数
1、fputc
int fputc(int c,FILE *stream);
将w写入文件
#include <stdio.h>
int main()
{
FILE *fp;
fp = fopen("./test.txt","w+");
fputc('w',fp);
fclose(fp);
return 0;
}
写入字符串
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
int i;
char *str = "wy is handsome!";
int len = strlen(str);
fp = fopen("./w.txt","w+");
for(i=0;i<len;i++){
fputc(*str,fp);
str++;
}
fclose(fp);
return 0;
}
2、feof(判断是否到文件尾部)
int feof(FILE *stream);
如果没有到达尾部,则返回0;反之则返回非0;
3、fgetc
int fgetc(FILE *stream);