C语言 | 文件操作(一)

一、文件概述

1.磁盘文件

指一组相关数据的有序集合,通常存储在外部介质(如磁盘)上,使用时才调入内存。从用户或者操作系统使用的角度(逻辑上)把文件分为文本文件和二进制文件。

a.文本文件

1.基于字符编码的文件,常见编码有ASCII、UNICODE等;

2.一般可以使用文本编辑器直接打开;

3.数5678,以ASCII存储形式为:00110101 00110110 00110111 00111000。

b.二进制文件

1基于值编码的文件,自己根据具体应用,指定某个值是什么意思;

2.把内存中的数据按其在内存中的存储形式原样输出到磁盘上;

3.数5678,以二进制存储形式为:00010110 00101110。

2.设备文件

在操作系统中把每一个与主机相连的输入、输出设备看作是一个文件,把它们的输入、输出等同于对磁盘文件的读和写。

二、对文本文件的操作

1.打开文件

(1)函数

#include<stdio.h>

FILE* fopen(const char* filename,const char* mode);

参数:filename:需要打开的文件名(包括路径)

           mode:打开文件的模式设置  

返回值:成功:文件指针;失败:NULL

(2)打开文件的模式

打开模式含义备注
r或rb以只读的方式打开一个文本文件(文件不存在则报错)

1.b是二进制的意思,只在windows中有效,在Linux用r和rb的结果一样。

2.Unix和Linux下所有的文本文件行都是\n结尾,而Windows所有的文本文件行都是\r\n结尾。

3.Unix和Linux下,“文本”与“二进制”模式没有区别,"\r\n"作为两个字符原样输入输出

4.Windows下,以“文本”方式打开文件,即不加b时:

  a.读取文件时,系统会将所有的\r\n转换为\n

  b.写入文件时,系统会将\n转换为\r\n

5.Windows下,以“二进制”方式打开文件时,不会进行\r\n与\n的互相转换

 

 

 

w或wb以写的方式打开文件(文件存在则清空,文件不存在则创建)
a或ab以追加的方式打开文件,在末尾添加内容(文件不存在则创建)
r+或rb+以可读、可写的方式打开文件(若文件不存在则报错)
w+或wb+以可读、可写的方式打开文件(文件存在则清空,文件不存在则创建)
a+或ab+以追加的方式打开文件,在末尾添加内容(文件不存在则创建)

2.关闭文件

(1)关闭文件的意义

1.打开的文件会占用内存资源,如果总是打开不关闭,会消耗很多内存。

2.一个进程同时打开的文件数是有限制的,超过最大同时打开文件数,再次调用 fopen 打开文件会失败。

3.如果没有明确的调用 fclose 关闭打开的文件,那么程序在退出的时候,操作系统会统一关闭。

(2)函数

#include<stdio.h>

int fclose(FILE* stream);

参数:stream:文件指针

返回值:成功:0;失败:-1

3.按照字符读写文件

(1)写文件

#include<stdio.h>

int fputc(int ch,FILE* stream);

参数:ch:需要写入文件的字符

           stream:文件指针

返回值:成功:成功写入文件的字符;失败:-1

(2)读文件

#include<stdio.h>

int fgetc(FILE* stream);

参数:stream:文件指针

返回值:成功:成功读取到的字符;失败:-1

(3)检测文件结尾

1.EOF:#define EOF (-1)

在 C 语言中 , EOF 表示文件结束符 ( end of file )。在 while 循环中以 EOF 作为文件结束标志,这种以 EOF 作为文件结束标志的文件,必须是文本文件。在文本文件中 , 数据都是以字符的 ASCII 代码值的形式存放,ASCII 代码值的范围是 0 ~ 127 , 不可能出现 -1 , 因此可以用 EOF 作为文件结束标志。

2.feof():判断的是最后一次“读操作的内容”,不是当前位置内容(上一个内容)

当把数据以二进制形式存放到文件中时,就会有 -1 值的出现,因此不能采用EOF作为二进制文件的结束标志 . 为解决这一个问题,ANSI C 提供一个 feof函数,用来判断文件是否结束。feof 函数既可用以判断二进制文件又可用以判断文本文件。

#include<stdio.h>

int feof(FILE* stream);

参数:stream:文件指针

返回值:非0:已经到文件结尾;0:没有到文件结尾

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void main()
{
    //以写的模式打开文件
    FILE* fp1 = fopen("D:/c.txt", "w");
    int ch = 'h';
    //以字符的形式写入文件
    fputc(ch, fp1);
    //关闭文件
    fclose(fp1);
    

    //以读的模式打开文件
    FILE* fp2 = fopen("D:/c.txt", "r");
    if (!fp2)
    {
        return;
    }
    //feof:判断是否到了文件结尾
    while (!feof(fp2))
    {
        //以字符的形式读文件,文件在读取时光标流会自动向下移动
        char c = fgetc(fp2);
        printf("%c", c);//h
    }
    //关闭文件
    fclose(fp2);
}

4.按照行读写文件

(1)写文件

#include<stdio.h>

int fputs(const char* str,FILE* stream);

参数:str:字符串

           stream:文件指针

返回值:成功:0;失败:-1

(2)读文件

#include<stdio.h>

int fgets(char* str,int size,FILE* stream);

参数:str:字符串

          size:指定最大读取字符串的长度

           stream:文件指针

返回值:成功:成功读取到的字符串;读到文件尾或者出错:NULL

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string>
void main()
{
    FILE* fp1 = fopen("D:/c.txt", "w");
    //const char* ch = "hello world\n !";
    char ch[] = "hello world\n !";
    fputs(ch, fp1);//一共两行,即fputs不会自动在结尾加一个\n,字符串结束符\0不会写入文件
    fclose(fp1);

    FILE* fp2 = fopen("D:/c.txt", "r");
    if (!fp2)
    {
        return;
    }
    char* data=(char*)malloc(sizeof(char)*20);
    while (!feof(fp2))
    {
        fgets(data, 20, fp2);//会自动加上\0作为字符串结束
        printf("%s", data);
    }
    fclose(fp2);
    free(data);
}
//输出结果:
//hello world 
// !
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string>
#include <time.h>

void main()
{
    srand((size_t)time(NULL));
    int a, b, c;
    char* p = (char*)malloc(sizeof(char) * 20);
    FILE* fp = fopen("D:/加减乘除.txt", "w");
    for (size_t i = 0; i < 10; i++)
    {
        a = rand() % 10 + 1;//1~10的数
        b = rand() % 10 + 1;
        c = rand() % 4;//0~3的数
        memset(p, 0, 20);
        switch (c)
        {
        case 0:
            sprintf(p, "%d+%d=\n", a, b);//按格式化将数据写入字符串
            break;
        case 1:
            sprintf(p, "%d-%d=\n", a, b);
            break;
        case 2:
            sprintf(p, "%d*%d=\n", a, b);
            break;
        case 3:
            sprintf(p, "%d/%d=\n", a, b);
            break;
        default:
            break;
        }
        fputs(p, fp);
    }
    fclose(fp);
    free(p);
}

//加减乘除.txt文件内容:(11行)
8*10=
9*6=
2+7=
7+10=
10/2=
9/5=
7/6=
10*6=
6*8=
9/6=
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string>
#include <time.h>

void main()
{
    FILE* fp1 = fopen("D:/加减乘除.txt", "r");
    if (!fp1)
    {
        return;
    }
    FILE* fp2 = fopen("D:/加减乘除结果.txt", "w");
    char* p = (char*)malloc(sizeof(char) * 20);
    int a, b, value;
    char c;
    while (!feof(fp1))
    {
        memset(p, 0, 20);
        a = 0; b = 0; c = ' ';
        fgets(p, 20, fp1);
        
        sscanf(p, "%d%c%d=", &a, &c, &b);//按格式化读字符串中的数据 
        if (a == 0)//除掉最后一行 
        {
            break;
        }
        switch (c)
        {
        case '+':value = a + b;
            break;
        case '-':value = a - b;
            break;
        case '*':value = a * b;
            break;
        case '/':value = a / b;
            break;
        default:
            break;
        }
        sprintf(p, "%d%c%d=%d\n", a, c, b, value);
        fputs(p, fp2);
    }
    free(p);
    fclose(fp1);
    fclose(fp2);
}

//加减乘除结果.txt文本内容:(11行)
8*10=80
9*6=54
2+7=9
7+10=17
10/2=5
9/5=1
7/6=1
10*6=60
6*8=48
9/6=1

5.按照格式化读写文件

类似于上面例子中的sscanf与sprintf.

(1)写文件

#include<stdio.h>

int fprintf(FILE* stream,const char* format,...);

根据参数format字符串来转化并格式化数据,然后将结果输出到stream指定的文件中

参数:stream:文件指针

           format:字符串格式,格式和printf()一样

返回值:成功:实际写入文件的字符个数;失败:-1

(2)读文件

#include<stdio.h>

int fscanf(FILE* stream,const char* format,...);

从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据,遇到空格,换行结束

参数:stream:文件指针

           format:字符串格式,格式和scanf()一样

返回值:成功:成功转换的值的个数;失败:-1

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

void main()
{
    FILE* fp1 = fopen("D:/info.txt", "w");
    char name[] = "Lisa";
    int age = 25;
    fprintf(fp1, "%s's age is %d,\0 she is a girl", name, age);
    fclose(fp1);
}

//info.txt文本内容:
Lisa's age is 25,
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

void main()
{
    FILE* fp1 = fopen("D:/info.txt", "w");
    char name[] = "Lisa";
    int age = 25;
    fprintf(fp1, "%s's age is %d, she is a\ngirl", name, age);
    fclose(fp1);
}

//info.txt文本内容:
Lisa's age is 25, she is a
girl
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

void main()
{
    //info.txt文本内容:2020 hello world
    FILE* fp = fopen("D:/info.txt", "r");
    if (!fp)
    {
        return;
    }
    
    int a = 0;
    char* info = (char*)malloc(sizeof(char) * 50);
    memset(info, 0, 50);

    fscanf(fp, "%d%s", &a, info); 
    printf("%d,%s",a, info);//2020,hello

    fscanf(fp, "%s", info);
    printf("%s", info);//world
    fclose(fp);
    free(info);
}

6.按照块读写二进制文件

(1)写文件

#include<stdio.h>

int fwrite(const void* ptr,size_t size,size_t nmemb,FILE* stream);

参数:ptr:准备写入文件数据的地址

          size:写入文件内容的块数据大小

          nmemb:写入文件的块数

          stream:文件指针

           (写入文件的数据总大小:size*nmemb)

返回值:成功:实际写入文件的块个数,即nmemb;失败:0

(2)读文件

#include<stdio.h>

int fread( void* ptr,size_t _ElementSize,size_t _ElementCount,FILE* _stream);

参数:ptr:存储读到的文件数据的地址

          _ElementSize:块数据大小

          _ElementCount:读取的块个数

          _stream:文件指针

返回值:成功:实际成功读取到的内容块数,如果此值比_ElementCount小并且大于0,说明读到文件的结尾;失败:0

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

void main()
{
    int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    FILE* fp = fopen("D:/块数据.txt", "w");
    fwrite(arr, sizeof(int), 10, fp);
   // fwrite(arr, 20, 2, fp);//正确,只要数据大小是40即可
    fclose(fp);
}

结果:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string>

void main()
{
    FILE* fp = fopen("D:/块数据.txt", "r");
    if (!fp)
    {
        return;
    }
    int arr[10] = { 0 };
    fread(&arr, 4, 10, fp);
    for (size_t i = 0; i < 10; i++)
    {
        printf("%d", arr[i]);//12345678910
    }
    fclose(fp);
}

存储结构体:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct student {
    std::string name;
    int age;
    std::string address;
};
void main()
{
    struct student stu[3] = {
                {"张三",20,"北京昌平"},
                {"李四",22,"北京朝阳"},
                {"王五",19,"北京海淀"}
            };
    FILE* fp = fopen("D:/存储结构体.txt", "w");
    for (size_t i = 0; i < 3; i++)
    {
        fwrite(&stu[i], sizeof(struct student), 1, fp);
    }
    fclose(fp);
}

读取结构体:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct student {
    char name[21];
    int age;
    char address[51];
};
void main()
{
    FILE* fp = fopen("D:/存储结构体.txt", "r");
    if (!fp)
    {
        return;
    }
    struct student* stu=(struct student*)malloc(sizeof(struct student)*3);
    for (size_t i = 0; i < 3; i++)
    {
        fread(&stu[i], sizeof(struct student), 1, fp);
        printf("%s\n", stu[i].name);
        printf("%d\n", stu[i].age);
        printf("%s\n", stu[i].address);

    }
    fclose(fp);
    free(stu);
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烫青菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值