C语言基础⑩①——文件

  • Linux是由文件驱动的系统。

一、文件操作

1、概述

  • 什么是文件

文件是指存储在外存储器(即硬盘、U盘、闪盘、软盘等)上的数据的集合

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

  1. 文件内容的读取;     
  2. 文件内容的写入。

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

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

  • 文件的分类

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

  1. 文本文件(ASCII文件);
  2. 二进制文件。
  • 文件标识

  1. 文件系统中:路径+文件名,举例:d:/aaa/bbb.txt
  2. C语言系统中:文件指针(文件类型指针),语法:FILE  *指针变量名
  • 文件操作的步骤:

  1. 打开文件;
  2. 文件处理(读写文件);
  3. 关闭文件

2、文件的操作

1.文件的打开关闭

  • 打开文件,让系统为文件创建文件缓冲区;

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

int *arr[] --> 指针数组,即数组内的元素为指针;

int (*arr)[] 等价于 int arr[][] --> 数组指针,操作二维数组时使用,举例:char c[] = {"aaaa","bbbb","cccc"}。  

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

    • 函数名: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;
}

perror专用于输出异常提示!

2.文件的读写

1)读

  • 单字符读写
    • 函数名:fgets
    • 头文件: #include <stdio.h>
    • 函数原型:int fgets(FILE*  fp)
    • 函数功能:从fp代表的文件中获取一个字符
    • 函数参数:
      • fp:我们需要操作的文件的描述;
    • 返回值:返回读取到的字符
举例:单字符读取
/**
* 单字符读取
*/
#include <stdio.h>

int main(int argc,char** argv)//参数个数,参数所携带的字符串
{
    if(argc < 2)
    {
        printf("输入有误\n");
        return -1;
    }

    //打开文件
    FILE* fp = fopen(argv[1],"r");//权限:可读

    //非空校验
    if(!fp)
    {
        perror("文件打开失败!");
        return -1;
    }

    //单字符读取文件
    int re = fgetc(fp);
    if(re == -1)//整数不能这样判断
    {
        perror("文件读取失败!");
        return -1;
    }

    printf("%c\n",re);

    //关闭文件
    fclose(fp);

    return 0;
}

  • 举例:单字符读取字符串
/**
* 单字符读取
*/
#include <stdio.h>

int main(int argc,char** argv)//参数个数,参数所携带的字符串
{
    if(argc < 2)
    {
        printf("输入有误\n");
        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;
}

  • 多字符读取        
    • 函数名:fgets[]
    • 头文件:#include <stdio.h>
    • 函数原型:char  *fgets(char  *buf,int  size,FILE  *fp);
    • 函数功能:从fp代表的文件中获取size个字符,放置在buf代表的内存中;
    • 函数参数:
      • buf:内存空间首地址用于存放读取的字节;
      • size:待读取的字符,实际读取size-1;
      • fp:已打开的文件指针;
    • 返回值:
      • 成功:返回buf;
      • 失败:文件末尾,返回NULL;
Linux中查阅函数帮助:man  函数名

举例:多字符读取
/**
* 多字符读取
*/
#include <stdio.h>
#include <string.h>

int main(int argc,char **argv)
{
    if(argc < 2)
    {
        printf("输入有误");
        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;
}

2)写

  • 单字符写入
    • 函数名: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
    • 头文件:#include <stdio.h>
    • 函数原型:int fputs(const  char  *s,FILE  *stream);
    • 函数功能:向fp代表的文件中写入一个字符数组s
    • 函数参数:
      • 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;
}

3)文件结束

  • 判文件结束
    • 函数:feof(fp)
    • 头文件:#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));        
   }
/**
 * 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));        
   }

4)数据块的读写(二进制)

  • 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中的学生信息读出来

/**
 * 数据库读写案例:将二进制文件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个学生的有关数据,然后把它们转存到磁盘文件上去
/**
 * 数据库读写案例:从键盘输入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;
    if((fp = fopen("stu-list","wb")) == NULL)// stu-list对应的目录:./stu-list,wb-二进制写
入,默认是文本写入
   {
        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();
   }
}

5)文件的随机读写

  • 说明: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;
举例:有一个磁盘文件,第一次将它的内容显示在屏幕上,第二次把它复制到另一文件上
/**
 * 有一个磁盘文件,第一次将它的内容显示在屏幕上,第二次把它复制到另一文件上。 
 */
#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); /*关闭文件*/
}

举例:在磁盘文件上存有10个学生的数据。要求将第1、3、5、7、9个学生数据输入计算机,并在屏幕上显示出来
/**
 * 在磁盘文件上存有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);
}

举例:下列C程序的功能是,用“追加”的形式打开文件gg.txt,查看文件读写指针的位置,然后向文件写入“data”, 再查看文件读写指针的位置。
/**
 * 下列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);
}

三、作业

1.编写程序实现文件拷贝(用 fgets函数实现)

代码:

 

运行效果:

2. 从键盘输入一串字符,存放到一个文件中,后打开读取存到内存另一个空间并显示,验证是否正确 键盘接收--> 存放到文件-->读文件-->显示内容

 代码:

 

运行效果:

3. 定义一个表示公交线路的结构体,要求有线路名称,起始站,终点站,里程等成员,定义结构体数 组,用来存储4条公交线路信息,并将数据保存到文件。要求验证是否存储成功。

 代码:

 

运行效果:

4. 自行查找 fscanf 和 fprintf 函数,并尝试用这两个函数进行数据的保存和读取。

scanf("格式控制符",地址列表)  
printf("格式控制符",输出列表)
fscanf(文件指针,"格式控制符",地址列表)  
fprintf(文件指针,"格式控制符",输出列表)

 代码:

 

运行效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值