您的位置:首页 > 运维架构

15:文件操作(C标准库函数)fopen/fclose/fread/fwrite/fseek/fprintf/fscanf

2017-01-14 20:33 621 查看
【文件操作】

所有的文件都是"采用二进制的方式记录"数据

如果文件里所有二进制数据都有对应的字符(ASCII码),就把这种文件叫做"文本文件"

除了文本文件之外的所有文件都叫做"二进制文件"

文本文件和二进制文件各自采用不同的方法操作("可以把文本文件当作二进制文件来操作",能够操作二进制文件就也同时可以操作文本文件,但反过来不行)

文件操作基本步骤:

1. 打开文件:"fopen()"

2. 操作文件:读取"fread()",写入"fwrite()"

3. 关闭文件:"fclose()"

/*文件操作代码框架(2种写法)*/

#include <stdio.h>

int main() {

    FILE *p_file = fopen("a.txt", "w"); //结构体指针,FILE结构体类型

    if(p_file) { //有可能打开失败(返回值为NULL),所以需要分支检查

        //使用文件

        fclose(p_file); //文件使用完毕需要关闭文件

        p_file = NULL;

    }   

    return 0;

}

//另外一种写法

int main() {

    FILE *p_file = fopen("a.txt", "w");

    if(!p_file) {

        return 0;

    }   

    //使用文件

    fclose(p_file);

    p_file = NULL;

    return 0;

}

文件操作代码框架详解:

"fopen函数的返回值应该记录在文件指针"里,只有文件指针,才能在程序中代表打开的文件

    FILE *p_file = fopen("a.txt", "w"); //记录在指针p_file中

fopen函数有可能失败,如果失败则返回值是 NULL 空地址(nil)

完成对文件的所有操作之后,必须使用 "fclose"函数关闭文件

fclose函数需要文件指针作为参数

    fclose(p_file);

文件关闭之后,文件指针成为野指针,必须恢复成空指针

    p_file = NULL;

"fopen" 函数需要两个参数:

    fopen("a.txt", "w"); //a.txt相对路径表示当前目录

1. 代表打开文件的路径

2. 代表打开的方式(决定程序中可以对文件做什么操作)

文件打开方式有如下选择:

"r" 只能查看文件内容,只能从文件头开始查看

    如果文件不存在会打开失败

"r+"包含 r 的功能,比 r 多了修改功能

"w" 只能修改文件内容不能查看,只能从文件头开始修改

    如果文件不存在就创建新文件;如果文件存在就删除文件的所有内容

"w+"包含 w 的功能,比 w 多了查看功能

"a" 只能修改文件内容不能查看,只能在文件末尾追加新的内容

    如果文件不存在就创建新文件;如果文件存在不会修改原有内容

"a+"包含 a 的功能,比 a 多了查看功能

"b" 也是一种文件打开方式,这个打开方式"可以和上面任何一个混用",如wb

    这个打开方式表示程序中要"采用二进制方式操作文件"

文件操作主要分两种:

1. 把内存中一组连续存储区的内容拷贝到文件里(写文件)

2. 把文件里一组连续存储区的内容拷贝到内存里(读文件)

"fread()"函数可以采用二进制的方式"读文件"内容

"fwrite()"函数可以采用二进制的方式"写文件"内容

这两个函数都是有【返回值】的,返回值表示实际操作的存储区个数

这两个函数都需要以下 4 个参数:

1. 内存里第一个存储区的地址

2. 单个存储区的大小

3. 希望操作的存储区个数

4. 文件指针

<示例>/*写文件*/

#include <stdio.h>

int main() {

    int arr[] = {1, 2, 3, 4, 5}, size = 0;

    FILE *p_file = fopen("a.bin", "wb"); //a.bin

    if(p_file) {

        size = fwrite(arr, sizeof(int), 5, p_file);

        printf("实际写入%d个整数类型存储区\n", size); //5

        fclose(p_file);

        p_file = NULL;

    }   

    return 0;

}

->$: ls -l b.bin

//查看当前文件的详细属性信息,主要是存储区大小

<示例>/*读文件*/

#include <stdio.h>

int main() {

    int arr[5] = {0}, size = 0, num = 0;

    FILE *p_file = fopen("a.bin", "rb"); //已有文件a.bin

    if(p_file) {

        size = fread(arr, sizeof(int), 5, p_file);

        printf("一共得到%d个整数\n", size); //5 

        for(num = 0; num < 5; num++) {

            printf("%d ", arr[num]); //1 2 3 4 5

        }   

        printf("\n");

        fclose(p_file);

        p_file = NULL;

    }   

    return 0;

}

"fprintf"函数可以按照格式把数据记录到"文本文件"里

这个函数的第一个参数就是文件指针,后面的参数和printf函数的参数一样

    fprintf(p_file, "%d ", arr[num]); //从数组获取数据写入文件里

<示例>/*文本文件写入*/

#include <stdio.h>

//#include <string.h>   fpirntf函数可以省略string.h

int main() {

    //char buf[10] = {0};

    int arr[] = {1, 2, 3, 4, 5}, num = 0;

    FILE *p_file = fopen("a.txt", "w"); //文本文件不需要加b

    if(p_file) {

        for(num = 0; num < 5; num++) {

            //sprintf(buf, "%d ", arr[num]);

            //fwrite(buf, sizeof(char), strlen(buf), p_file);

            fprintf(p_file, "%d ", arr[num]);//此句等同以上两句

        }

        fclose(p_file);

        p_file = NULL;

    }

    return 0;

}

"fscanf"函数可以按照格式从文本文件里获得数字并记录到变量存储区里

这个函数的第一个参数是文件指针,后面的参数和scanf函数的参数一样

    fscanf(p_file, "%d", &num); //从文件获得一个数字记录在num变量里

<示例>/*文本文件读取*/

#include <stdio.h>

int main() {

    int num = 0, i = 0;

    FILE *p_file = fopen("a.txt", "r");

    if(p_file) {

        for(i = 0; i < 5; i++) {

            fscanf(p_file, "%d", &num);

            printf("%d ", num);

        }   

        printf("\n");

        fclose(p_file);

        p_file = NULL;

    }   

    return 0;

}

【练习】

11111

22222

33333

44444

55555

编写程序,把上面这个二维数组中所有数字记录到二进制文件里面

再编写程序,从二进制文件中得到二维数组的所有数字,记录到二维数组里,并输出效果如下

55555

44444

33333

22222

11111

<思想>

文件写入/读取函数

/*代码*/ (写入文件)

#include <stdio.h>

int main() {

    int arr[][5] = {1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5};

    FILE *p_file = fopen("06b.bin", "wb");

    if(p_file) {

        fwrite(arr, sizeof(int), 25, p_file);

        fclose(p_file); 

        p_file = NULL;

    }       

    return 0;

}

/*代码*/ (读取文件)

#include <stdio.h>

int main() {

    int arr[5][5] = {0}, num = 0, i = 0, j = 0;

    FILE *p_file = fopen("06b.bin", "rb");

    if(p_file) {

        for(num = 4; num >= 0; num--) {

            fread(arr[num], sizeof(int), 5, p_file);

        }   

        fclose(p_file);

        p_file = NULL;

    }   

    for(i = 0; i < 5; i++) {

        for(j = 0; j < 5; j++) {

            printf("%d", arr[i][j]);

        }   

        printf("\n");

    }   

    return 0;

}

【练习】

模拟"人员信息管理系统"

程序从键盘得到多个人员信息,然后把他们都记录到二进制文件里

每个人员信息包含整数类型的id,整数类型的年龄,和单精度浮点类型的工资

人员个数不缺定

文件内容应该可以追加

<思想>

结构体/fwrite

/*代码*/

#include <stdio.h>

typedef struct {

    int id; 

    int age;

    float wages;

} Person;

int main() {

    Person p = {0};

    int num = 0;

    FILE *p_file = fopen("pinfo.bin", "a+b");

    if(p_file) {

        while(1) {

            printf("请输入ID:");

            scanf("%d", &p.id);

            printf("请输入年龄:");

            scanf("%d", &p.age);

            printf("请输入工资:");

            scanf("%g", &p.wages);

            fwrite(&p, sizeof(Person), 1, p_file); 

            //fwrite每次写入一个结构体

            printf("是否需要继续输入是(1)/否(0):");

            scanf("%d", &num);

            if(!num){

                break; //跳出循环分支在fwrite下面保证最后1次能够写入

            }   

        }   

        fclose(p_file);

        p_file = NULL;

    }   

    return 0;

}

【练习】

"人员信息管理系统" 文件 pinfo.bin

将其信息读取并打印到屏幕上

<思想>

结构体/fread

/*代码*/

#include <stdio.h>

typedef struct {

    int id; 

    int age;

    float wages;

} Person;

int main() {

    Person p = {0};

    int size = 0;

    FILE *p_file = fopen("pinfo.bin", "rb");

    if(p_file) {

        while(1) {

            size = fread(&p, sizeof(Person), 1, p_file); 

            if(!size) { //size赋值返回值,操作0个存储区的时候代表结束

                break; 

            }

            printf("ID:%d\n", p.id);

            printf("年龄:%d\n", p.age);

            printf("工资:%g\n", p.wages);

        }

        fclose(p_file);

        p_file = NULL;

    }   

    return 0;

}

计算机里为每个打开的文件保留一个整数,这个整数表示下一次文件读写操作的开始位置

这个位置一定在两个相邻字节之间

这个整数的数值就是文件头到这个位置之间包含的字节个数

这个整数叫做"文件的位置指针"

每当从文件中得到 n 个字节或向文件里写入 n 个字节后位置指针都会增加 n

"ftell"函数可以获得当前位置指针的数值

"rewind"函数可以把位置指针的数值设置成 0

<示例>

#include <stdio.h>

int main() {

    char ch = 0;

    FILE *p_file = fopen("08file.txt", "rb");//文件里:abcdefghijk

    if(p_file) {

        printf("%ld\n", ftell(p_file)); //0 

        fread(&ch, sizeof(char), 1, p_file);

        printf("%c\n", ch);//a

        printf("%ld\n", ftell(p_file)); //1 

        fread(&ch, sizeof(char), 1, p_file);

        printf("%c\n", ch);//b

        printf("%ld\n", ftell(p_file)); //2 

        fread(&ch, sizeof(char), 1, p_file);

        printf("%c\n", ch);//c

        rewind(p_file); //将位置指针的数值设置成 0

        printf("%ld\n", ftell(p_file)); //0 

        fread(&ch, sizeof(char), 1, p_file);

        printf("%c\n", ch);//a

        fclose(p_file);

        p_file = NULL;

    }   

    return 0;

}

"fseek"函数可以把位置指针设置到任意位置

该函数调用语句里需要指定一个基准位置,以及目标位置到基准位置之间的距离

    SEEK_SET 0 把文件头作为基准位置

    SEEK_CUR 1 把当前位置作为基准位置

    SEEK_END 2 把文件尾作为基准位置

如果目标位置在基准位置后边,则距离用正数表示

如果目标位置在基准位置前边,则距离用负数表示

这个距离的绝对值就是两个位置之间包含的字节个数

<示例>

        //直接读取字符c

        fseek(p_file, 2, SEEK_SET); // 0 1 2 文件头到c距离是2

        fread(&ch, sizeof(char), 1, p_file);

        printf("%c\n", ch);//c

        //直接读取字符h

        fseek(p_file, 4, SEEK_CUR); //当前位置是c到h距离是4

        fread(&ch, sizeof(char), 1, p_file);

        printf("%c\n", ch);//h

        //直接读取字符l

        fseek(p_file, -4, SEEK_END); //从文件末尾到l距离是4,负数

        fread(&ch, sizeof(char), 1, p_file);

        printf("%c\n", ch);//l

【练习】

编写程序从person.bin(id,age,wages)文件中得到所有人的id并显示在屏幕上

<思想>

文件读取/位置指针函数

/*代码*/

#include <stdio.h>

typedef struct {

    int id; 

    int age;

    int wages;

} Person;

int main() {

    Person p = {0};

    int id = 0, size = 0;

    FILE *p_file = fopen("pinfo.bin", "rb");

    if(p_file) {

        while(1) {

            size = fread(&id, sizeof(int), 1, p_file); //记录在id中

            if(!size) {

                break;

            }   

            printf("%d\n", id);

            fseek(p_file, sizeof(Person) - sizeof(int), SEEK_CUR);

            //巧妙的用法,使结构体中的成员位置有规律循环

        }   

        fclose(p_file);

        p_file = NULL;

    }   

    return 0;
}

【练习】/*文件操作*/

编写程序实现cp(文件拷贝)的命令功能



->$: ls 

a.txt

->$: cp a.txt b.txt

->$: ls

a.txt b.txt

<思想>

命令行参数操作两个同时打开的文件

/*代码*/

#include <stdio.h>

int main(int argc, char *argv[]) {

    FILE *p_old = NULL, *p_new = NULL;

    char buf[100] = {0};

    int size = 0;

    if(argc < 3) {

        printf("命令错误!\n");

        return 0;

    }   

    p_old = fopen(argv[1], "rb");

    if(!p_old) {

        printf("原始文件打开失败!\n");

        return 0;

    }   

    p_new = fopen(argv[2], "wb");

    if(!p_new) {

        printf("原始文件打开失败!\n");

        fclose(p_old);

        p_old = NULL;

        return 0;

    }   

    while(1) {

        size = fread(buf, sizeof(char), 100, p_old);

        if(!size) {

            break;

        }

        fwrite(buf, sizeof(char), size, p_new);

    }   

    fclose(p_new);

    p_new = NULL;

    fclose(p_old);

    p_old = NULL;

    return 0;

}

->$: ls 

01lianxi 01lianxi.c

->$: 01lianxi 01lianxi.c 01lianxi.bak

->$: ls

01lianxi 01lianxi.c "01lianxi.bak"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  标准C语言
相关文章推荐