目录
标准C库函数(fopen、fwrite、fread、fseek、fclose)
实现cp指令
文件名通过参数传入,打开文件 —>读取内容到缓冲区—>缓冲区内容写入目标文件。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
int fdSrc;
int fdDes;
int f_size;
int n_read;
int n_write;
char *readbuff = NULL;
if(argc != 3){
printf("too few arguments\n");
return 0;
}
printf("instruction:");
for(int i=0;i<argc;i++){
printf("%s ",argv[i]);
}
putchar('\n');
//打开被复制文件
fdSrc = open(argv[1],O_RDONLY);
if(fdSrc == -1){
perror("open src file fault:");
return 0;
}
f_size = lseek(fdSrc,0,SEEK_END);//计算文件大小
lseek(fdSrc,0,SEEK_SET);
readbuff = (char *)malloc(f_size+1);//初始化缓冲区
memset(readbuff,'\0',f_size+1);
n_read = read(fdSrc,readbuff,f_size);//将源文件内容读到缓冲区
if(n_read == -1){
perror("read fault");
exit(-1);
}
printf("read %d bytes from %s\n",n_read,argv[1]);
close(fdSrc);//操作完成,关闭文件
//打开目标的文件
fdDes = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0600);
if(fdDes == -1){
perror("open des file fault");
return 0;
}
n_write = write(fdDes,readbuff,strlen(readbuff));//将缓冲区内容写入到目标>文件中
if(n_write == -1){
perror("write fault");
exit(-1);
}
printf("write %d bytes to %s\n",n_write,argv[2]);
close(fdDes);
return 0;
}
修改文件某字段内容
打开文件 —> read读取文件内容到程序缓冲区—> 调用“strstr”得到要修改的位置,进行修改—> 缓冲区内容write写回原文件。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
int fd;
int f_size;
int n_read;
int n_write;
char *readbuff = NULL;
if(argc != 2){
printf("too few arguments\n");
return 0;
}
printf("instruction:");
for(int i=0;i<argc;i++){
printf("%s ",argv[i]);
}
putchar('\n');
//打开配置文件
fd = open(argv[1],O_RDWR);
if(fd == -1){
perror("open src file fault:");
return 0;
}
f_size = lseek(fd,0,SEEK_END);//计算文件大小
lseek(fd,0,SEEK_SET);
readbuff = (char *)malloc(f_size+1);//初始化缓冲区
memset(readbuff,'\0',f_size+1);
n_read = read(fd,readbuff,f_size);//将源文件内容读到缓冲区
if(n_read == -1){
perror("read fault");
exit(-1);
}
printf("read %d bytes from \"%s\"\n",n_read,argv[1]);
close(fd);
/*找到修改的位置*/
char *tmp = strstr(readbuff,"score=");
if(tmp==NULL){
printf("no such string\n");
}
tmp = tmp + strlen("score=");
*tmp = '9';
*(tmp+1) = '6';
//重新写入配置文件
fd = open(argv[1],O_RDWR|O_TRUNC);
if(fd == -1){
perror("open file fault");
exit(-1);
}
n_write = write(fd,readbuff,strlen(readbuff));//将缓冲区内容写入到目标文件
中
if(n_write == -1){
perror("write fault");
exit(-1);
}
printf("write %d bytes to \"%s\"\n",n_write,argv[1]);
close(fd);
return 0;
}
写一个整数到文件
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
int data = 100;
int data2 = 0;
fd = open("./file1",O_RDWR);//打开文件
write(fd,&data,sizeof(int));//将整数写到文件
lseek(fd,0,SEEK_SET);//光标回到头部
read(fd,&data2,sizeof(int));//读取文件内容
printf("content is: %d\n",data2);
close(fd);//关闭文件
return 0;
}
写结构体数组到文件
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
struct Test
{
int a;
char b;
};
int main()
{
int fd;
struct Test data1[2] = {{10,'a'},{20,'b'}};
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("content is: %d,%c\n",data2[0].a,data2[0].b);
printf("content is: %d,%c\n",data2[1].a,data2[1].b);
close(fd);//关闭文件
return 0;
}
标准C库文件I/O函数
open是UNIX系统调用函数(包括LINUX等),fopen是标准C语言库函数,
因此:
-
open移植性有限。但基于内核的开发驱动开发,用open。也可操作普通正规文件(Regular File)。open与read,write配合使用。
-
fopen移植性好。fopen是用来操作普通正规文件(Regular File)。fopen与fread,fwrite配合使用。
1.缓冲文件系统
缓冲文件系统的特点是:在内存开辟一个“缓冲区",给程序中的文件使用; 当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区",装满后再从内存“缓冲区”依此读出需要的数据。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区"越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器而定。API有:fopen, fclose, fread, fwrite,fgetc,fgets, fputc, fputs, freopen, fseek, ftell, rewind等。
2.非缓冲文件系统
缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快。API有:open, close, read, write, getc, getchar, putc, putchar等。
总结,就是open无缓冲,fopen有缓冲。 前者与read, write等配合使用,后者与fread,fwrite等配合使用。使用fopen函数,由于在用户态下就有了缓冲,因此进行文件读写操作的时候就减少了用户态和内核态的切换(切换到内核态调用是需要调用系统调用API);而使用open函数,在文件读写时则每次都需要进行内核态和用户态的切换;表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列的函数快; 如果随机访问文件则相反。
标准C库函数(fopen、fwrite、fread、fseek、fclose)
FILE *fopen(const char *path, const char *mode);
参数:
mode:
r 打开文本文件,用于读。流被定位于文件的开始。
r+ 打开文本文件,用于读写。流被定位于文件的开始。
w 将文件长度截断为零,或者创建文本文件,用于写。流被定位于文件的开始。
w+ 打开文件,用于读写。如果文件不存在就创建它,否则将截断它。流被定位于文件的开始。
a 打开文件,用于追加 (在文件尾写)。如果文件不存在就创建它。流被定位于文件的末尾。
a+ 打开文件,用于追加 (在文件尾写)。如果文件不存在就创建它。读文件的初始位置是文件的开始,但是输出总是被追加到文件的末尾。
用fopen写字符串到文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *fs = NULL;
char writebuff[] = "12345";
char *readbuff = NULL;
//打开文件
fs = fopen("./file1","r+");//可读可写方式打开文件
if(fs == NULL){
perror("open file fail");
}
//写入文件
int n_write = fwrite(writebuff,1,strlen(writebuff),fs);
printf("write %d bytes\n",n_write);
//计算文件大小
int f_size = ftell(fs);//返回当前位置值
readbuff = (char *)malloc(f_size+1);
memset(readbuff,'\0',f_size+1);
//读取文件
fseek(fs,0,SEEK_SET);
int n_read = fread(readbuff,1,f_size,fs);
if(ferror(fs)){
printf("read file fail\n");
}
printf("read %d bytes,%s\n",n_read,readbuff);
fclose(fs);
return 0;
}
用fopen写结构体数组到文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Test
{
int a;
char b;
}TEST;
int main()
{
FILE *fs = NULL;
TEST arr[] = {{11,'a'},{22,'c'}};
TEST *arr2;
//打开文件
fs = fopen("./file1","r+");
if(fs == NULL){
perror("open file fail");
}
//写入文件
int n_write = fwrite(arr,sizeof(arr),1,fs);
printf("write %d memb\n",n_write);
//计算文件大小
int f_size = ftell(fs);//返回当前位置值
arr2 = (TEST *)malloc(f_size);
//读取文件
fseek(fs,0,SEEK_SET);
int n_read = fread(arr2,f_size,1,fs);
if(ferror(fs)){
printf("read file fail\n");
}
printf("read %d members,%d,%c,%d,%c\n",n_read,arr2[0].a,arr2[0].b,arr2[1].a,arr2[1].b);
fclose(fs);
return 0;
}
其他C库函数:
除了用fwrite、fread,还可以用fputc和fgetc逐个字符写入和读取。
fgetc():
C 库函数 int fgetc(FILE *stream) 从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。
返回值:该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。
fputc():
C 库函数 int fputc(int char, FILE *stream) 把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。
feof():
C 库函数 int feof(FILE *stream) 测试给定流 stream 的文件结束标识符。返回值:到文件尾巴时返回非0,其它返回0。
ferror():
C 库函数 int ferror(FILE *stream),在调用各种输入输出函数(如 putc.getc.fread.fwrite等)时,如果出现错误,调用ferror会返回非0值,返回0表示未出错。
demo:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *fs = NULL;
char *writebuff = "12345";
char *readbuff = NULL;
//打开文件
fs = fopen("./file1","r+");
if(fs == NULL){
perror("open file fail");
}
//写入文件
while(*writebuff){
fputc(*writebuff,fs);
writebuff++;
}
if(ferror(fs)){
printf("write file fail\n");
}
//计算文件大小
int f_size = ftell(fs);//返回当前位置值
readbuff = (char *)malloc(f_size+1);
memset(readbuff,'\0',f_size+1);
//读取文件
fseek(fs,0,SEEK_SET);
int i = 0;
char a;
a = fgetc(fs);
while(feof(fs) == 0){//检查文件结束符,如果文件结束返回非0,否则返回0
readbuff[i] = a;
a = fgetc(fs);
i++;
}
if(ferror(fs)){
printf("read file fail\n");
}
printf("read,%s\n",readbuff);
fclose(fs);
return 0;
}