C语言基础13文件操作

概述

  • 什么是文件

        文件是保存在外存储器上(一般代指磁盘,也可以是U盘、移动硬盘等)的数据的集合。

  • 文件操作体现在那几个方面

        1.文件内容的读取

        2.文件内容的写入

        数据的读取和写入可被视为针对文件进行输入和输出的操作,此时数据就像水流一样从外存储器流向内存,或者从内存流向外存储器,所以系统形象的称文件操作为文件流

        C语言程序对文件的操作采用“文件缓冲机制”。就是说,在程序中对文件的数据读写并不是直接操作文件中的数据,而是系统会为文件在内存中创建“文件缓冲区”,程序对文件的操作,其实是在缓冲区进行的。

  • 文件的分类

        根据数据的存储方式划分:

        1. 文本文件(ASCII文件)

        2. 二进制文件
  • 文件标识
        1. 文件系统中:路径 + 文件名,举例: d:/aaa/bbb.txt
        2. C语言程序中:文件指针(文件类型指针),语法: FILE * 指针变量名
  • 文件操作的步骤
        1. 打开文件
        2. 文件处理(读写文件)
        3. 关闭文件

文件的操作

文件的打开与关闭

打开文件(fopen),让系统为文件创建文件缓冲区;

  • 函数名:fopen
  • 头文件: #include <stdio.h>
  • 函数原型: FILE* fopen(const char *path,const char *mode);
  • 函数功能:打开文件,并为文件创建缓冲区
  • 函数参数:
    • path:目标文件的路径
    • mode:文件打开的方式(读-r、写-w、读写-rw
  • 返回值:
    • 成功:返回文件指针 File* (缓冲区首地址)
    • 失败:返回NULL

文件关闭(fclose),文件使用完毕,一定要记得释放

  • 函数名:fclose
  • 头文件: #include <stdio.h>
  • 函数原型: int fclose(FILE* fp);
  • 函数功能:关闭文件,释放缓冲区
  • 函数参数:
    • fp:已经打开的文件指针
  • 返回值:
    • 成功:返回0
    • 失败:返回EOF-1

案例:

/**
* 文件的打开与关闭 
*/ 
#include <stdio.h> 
int main(int argc,char** argv) 
{ 
// 在命令行执行./a.out的时候,传递一个需要打开的目标文件的地址 
if(argc < 2) 
{ 
printf("输入有误,请按照<%s 文件路径>格式输入\n",argv[0]); 
return -1; 
}
// 根据提供的文件路径,打开文件,mode(r,w,rw) 
FILE* fp = fopen(argv[1],"r"); 
// 校验文件是否读取成功 
if(!fp) 
{ 
perror("文件打开失败!"); 
return -1; 
}
puts("文件打开成功!"); 
// 关闭打开的文件 
int ret = fclose(fp); 
// 校验文件是否关闭成功(很多时候这一步会省略掉) 
if(ret == -1) 
{ 
perror("文件关闭失败!"); 
return -1; 
}
puts("文件关闭成功!"); 
return 0; 
} 

文件的读写

单字符读写(fgetc)

  • 函数名:fgetc
  • 头文件:#include <stdio.h>
  • 函数原型:int fgetc(FILE *fp);
  • 函数功能:从fp代表的文件中获取一个字符
  • 函数参数:
    • fp:我们需要操作的文件的描述
  • 返回值:
    • 成功:返回读取到的字符
    • 失败:返回EOF(-1)

方式一:

/**
 * 单字符的读取
 */
#include <stdio.h>

int main(int argc,char **argv)
{
    if(argc < 2)
    {
        printf("输入有误,请按照<%s 文件路径>格式输入\n",argv[0]);
        return -1;
    }

    // 打开文件
    FILE* fp = fopen(argv[1],"r");
    // 非空校验
    if(!fp)
    {
        perror("文件打开失败!");
        return -1;
    }

    // 单字符读取文件
    int re = 0;
	
    while(re != -1 && re != '\n')
    {
        re = fgetc(fp);
		printf("%c",re);
    }
	
	printf("\n");


    // 关闭文件
    fclose(fp);

    return 0;
    
}

方式二:

/**
* 单字符读取 
*/ 
#include <stdio.h> 
int main(int argc,char **argv) 
{ 
// 获取外部输入 
if(argc < 2) 
{ 
printf("输入有误,请按照<%s 文件路径>格式输入\n",argv[0]); 
return -1; 
}
// 打开文件 
FILE* fp = fopen(argv[1],"r"); 
if(!fp) 
{ 
perror("文件打开失败!"); 
return -1; 
}
// 读取文件 
char ch; 
while((ch = fgetc(fp)) != EOF) 
{ 
printf("%c",ch); 
}
printf("\n"); 
// 关闭文件 
fclose(fp); 
return 0; 
} 

多字符读写(fgets)

  • 函数名:fgets()
  • 头文件:#include <stdio.h>
  • 函数原型:char *fgets(char *buf,int size,FILE *stream);
  • 函数功能:从fp代表的文件中获取size个字符,放置在buf代表的内存中
  • 函数参数:
    • buf:内存空间首地址用于存放读取的字节
    • size:待读取的字符,实际读取size-1
    • fp:已经打开的文件指针
  • 返回值:
    • 成功:返回buf
    • 失败:文件末尾,返回NULL
/**
* 多字符读取 
*/ 
#include <stdio.h> 
#include <string.h> 
int main(int argc,char **argv) 
{ 
if(argc < 2) 
{ 
printf("输入有误,请按照<%s 文件路径>格式输入\n",argv[0]); 
return -1; 
}
FILE* fp = fopen(argv[1],"rw"); 
if(!fp) 
{ 
perror("文件打开失败!"); 
return -1; 
}
// 多字符读取 
// 创建缓冲区大小 
char buf[64] = {0}; 
while(fgets(buf,64,fp)!=NULL) 
{ 
printf("%s",buf); 
// 给buf赋初始值 
memset(buf,0,sizeof(buf)); 
}
printf("\n"); 
fclose(fp); 
return 0; 
} 

单字符写入(fputc)

  • 函数名:fputc
  • 头文件:#include <stdio.h>
  • 函数原型:int fputc(int c,FILE *fp)
  • 函数功能:向fp代表的文件中写入一个字符c
  • 函数参数:
    • c:待写入的字符
    • fp:已打开的文件指针
  • 返回值:
    • 成功:返回字符c
    • 失败:返回EOF(-1)
/**
* 单字符写入 
*/ 
#include <stdio.h> 
int main(int argc,char **argv) 
{ 
if(argc < 3) 
{ 
printf("输入有误,请按照<%s 文件路径 文本数据>格式输入\n",argv[0]); 
return -1; 
}
FILE* fp = fopen(argv[1],"w"); 
if(!fp) 
{ 
perror("文件打开失败!"); 
return -1; 
}
// 单字符写入 
while(*argv[2] != '\0') 
{ 
// ./a.out file1.txt I_Love_Your 
fputc(*argv[2],fp); 
argv[2]++;// 指针偏移1位 
}
fclose(fp); 
return 0; 
}

多字符写入(fputs)

  • 函数名:fputs
  • 头文件:#include <stdio.h>
  • 函数原型:int fputs(const char *s,FILE *fp);
  • 函数参数:
    • s:待写入的字符数组(写入缓冲区)
    • fp:已打开的文件指针
  • 返回值:
    • 成功:返回非负整数(>0)
    • 失败:返回EOF(-1)
/**
* 多字符写入 
*/ 
#include <stdio.h> 
int main(int argc,char **argv) 
{ 
if(argc < 3) 
{ 
printf("输入有误,请按照<%s 文件路径 文本数据>格式输入\n",argv[0]); 
return -1; 
}
FILE* fp = fopen(argv[1],"w"); 
if(!fp) 
{ 
perror("文件打开失败!"); 
return -1; 
}
// 单字符写入 
// ./a.out file1.txt I_Love_Your 
fputs(argv[2],fp); 
fclose(fp); 
return 0; 
} 

判文件结束(feof)

  • 函数名: feof
  • 头文件: #include <stdio.h>
  • 函数原型: int feof(fp)
  • 函数功能:在读fp指向的文件时判断是否遇到文件结束。
  • 函数参数:
    • fp:已打开的文件指针
  • 返回值:
    • 文件未读取完毕:返回0
    • 失败:文件读取完毕:返回非0
/**
* feof案例:将一个磁盘文件中的信息复制到另一个磁盘文件中。 
*/ 
#include <stdio.h> 
#include <string.h> 
int main(int argc,char** argv) 
{ 
// main函数输入判断 
if(argc < 3) 
{ 
printf("输入有误,请按照<%s 源文件路径 目标文件路径>格式输入\n",argv[0]); 
return -1; 
}
// 打开文件 
FILE* in = fopen(argv[1],"r"); 
FILE* out = fopen(argv[2],"w"); 
// 校验 
if(!in || !out) 
{ 
perror("文件打开失败!"); 
return -1; 
}
// 单个字符读写 
// while(!feof(in)) 
// { 
// 读写操作 
// fputc(fgetc(in),out); 
//} 
// 多个字符读写 
// 创建一个缓冲区,用来存放读写的数据 
char buf[64] = {0}; 
// 使用循环读写文件 
while(fgets(buf,64,in)!=NULL) 
{ 
// 写入数据 
fputs(buf,out); 
// 重置缓冲区 
memset(buf,0,sizeof(buf)); 
} 
printf("\n"); 
// 关闭文件 
fclose(in); 
fclose(out); 
} 

数据块的读写(二进制)

fread

  • 头文件: #include <stdio.h>
  • 函数原型: size_t fread(void *ptr,size_t size,size_t count,FILE* fp)
  • 函数功能:从fp代表的文件中以size为单位(一个数据块)读取count个数据块存放在ptr内存
  • 中。
  • 函数参数:
    • ptr:内存空间首地址,用于存放读取到数据(缓冲区)
    • size:数据块大小,以byte为单位
    • count:待读取的数据块的个数
    • fp:已打开的文件指针
  • 返回值:
    • 成功:返回实际写入的字节数??
    • 失败:返回 < 0

案例:

/**
* 数据库读写案例:将二进制文件stu-list中的学生信息读出来。 
*/ 
#include <stdio.h> 
#define SIZE 4 
// 创建学生结构体 
struct Student 
{ 
char name[20]; 
int num; 
int age; 
char addr[50];// 住址 
} stud[SIZE]; 
void main() 
{ 
int i; 
FILE* fp; 
if((fp = fopen("stu-list","rb")) == NULL) 
{ 
perror("文件打开失败!"); 
return; 
}
// 循环读取二进制文件 
for(i = 0; i < SIZE; i++) 
{ 
fread(&stud[i],sizeof(struct Student),1,fp); 
// 将读到的内容输出到控制台 
printf("%-10s%4d%4d%-20s\n",stud[i].name,stud[i].num,stud[i].age,stud[i].addr); 
}
fclose(fp); 
} 

fwrite

  • 头文件: #include <stdio.h>
  • 函数原型: size_t fwrite(const void* ptr,size_t size,size_t count,FILE* fp)
  • 函数功能:向fp代表的文件中以size为一个数据块,写入count个数据块到fp
  • 函数参数:
    • ptr:内存空间首地址,用于存放待写入的数据,(写入缓冲区)
    • size:数据块大小,以byte为单位
    • count:待写入的数据块个数
    • fp:已打开的文件指针
  • 返回值:
    • 成功:返回实际写入字节数??
    • 失败:写入完毕,返回 < 0

案例:

/**
* 数据库读写案例:从键盘输入4个学生的有关数据,然后把它们转存到磁盘文件上去。 
*/ 
#include <stdio.h> 
#define SIZE 4 // 学生数量 
// 创建学生结构体 
struct Student 
{ 
char name[20]; 
int num; 
int age; 
char addr[50];// 住址 
} stud[SIZE]; 
// 保存学生信息到文件 
void save() 
{ 
FILE* fp; 
int i; 
入,默认是文本写入 
{ 
perror("文件打开失败!"); 
return; 
}
// 写入操作 
for(i = 0; i < SIZE; i++) 
{ 
fwrite(&stud[i],sizeof(struct Student),1,fp); 
}
// 关闭文件 
fclose(fp); 
}
void main() 
{ 
int i; 
printf("请输入学生的信息:姓名,学号,年龄,住址\n"); 
for(i = 0; i < SIZE;i++) 
{ 
scanf("%s%d%d%s",stud[i].name,&stud[i].num,&stud[i].age,stud[i].addr); 
// 录入一个学生,就保存一个学生到文件中 
save(); 
} 
} 

文件的随机读写

  • 说明:C语言允许程序员在读写文件内容时,可在指定的位置上读写数据
  • 文件随机读写的核心操作: 文件位置指针的定位

文件位置指针的移动方法:

rewind

  • 头文件: #include <stdio.h>
  • 函数原型: void rewind(FILE* fp);
  • 函数功能: 将文件位置指针定位到文件开头
  • 函数参数:
    • fp: 已经打开的文件指针
  • 返回值: 无

fseek

  • 头文件: #include <stdio.h>
  • 函数原型: int fseek(FILE *fp, long offset, int whence);
  • 函数功能: 将文件位置指针定位到指定位置
  • 函数参数:
    • fp: 已经打开的文件指针
    • offset: 相对于参考位置的偏移位置
    • whence: 参考位置
      • SEEK_SET 0  表示文件头
      • SEEK_CUR 1  表示当前读写的位置
      • SEEK_END 2  表示文件尾
  • 返回值:
    • 成功 :0
    • 失败 : -1

ftell

  • 头文件: #include <stdio.h>
  • 函数原型: long ftell(FILE *fp);
  • 函数功能: 获取文件位置指针当前位置
  • 函数参数:
    • fp: 已经打开的文件指针
  • 返回值:
    • 成功 :文件位置指针当前位置
    • 失败 : -1

案例1:

/**
* 有一个磁盘文件,第一次将它的内容显示在屏幕上,第二次把它复制到另一文件上。 
*/ 
#include <stdio.h> 
void main() 
{ 
FILE *fp1, *fp2; 
fp1 = fopen("file1.c", "r"); 
fp2 = fopen("file2.c", "w"); 
while (!feof(fp1)) 
putchar(getc(fp1)); /*输出到屏幕*/ 
rewind(fp1); /*位置指针返回到文件头*/ 
while (!feof(fp1)) 
putc(getc(fp1), fp2); /*从文件file1的头读起,输出到文件file2中*/ 
fclose(fp1); 
fclose(fp2); /*关闭文件*/ 
} 

案例2:

/**
* 在磁盘文件上存有10个学生的数据。要求将第1、3、5、7、9个学生数据输入计算机,并在屏幕上显示出来。 
*/ 
#include <stdlib.h> 
#include <stdio.h> 
struct student_type 
{ 
char name[10]; 
int num; 
int age; 
char sex; 
} stud[10]; 
void main() 
{ 
int i; 
FILE *fp; 
if ((fp = fopen("stud-dat", "rb")) == NULL) 
{ 
printf("can not open file\n"); 
return; 
}
for (i = 0; i < 10; i += 2) 
{ 
fseek(fp, i * sizeof(struct student_type), 0); 
fread(&stud[i], sizeof(struct student_type), 1, fp); 
printf("%s %d %d %c\n", stud[i].name, stud[i].num, stud[i].age, stud[i].sex); 
}
fclose(fp); 
} 

案例3:

/**
* 下列C程序的功能是,用“追加”的形式打开文件gg.txt,查看文件读写指针的位置,然后向文件写入“data”, 
再查看
文件读写指针的位置。 
*/ 
#include "stdio.h" 
main() 
{ 
long p; 
FILE *fp; 
if ((fp = fopen("gg.txt","a")) == NULL) 
{ 
printf("cannot open this file!\n"); 
return; 
} 
p = ftell(fp); 
printf("p=%ld\n",p); 
fputs("data", fp); 
p = ftell(fp); 
printf("p=%ld\n",p); 
fclose(fp); 
} 

  • 16
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值