10.2 IO流与标准库

本文详细介绍了C语言中的IO流操作,包括文件的打开、关闭,格式化输入输出,字符读写,以及文件位置的管理和随机访问。重点讲解了fopen、fclose、fprintf、fscanf、fputc、fgetc等函数的用法,并提供了多个示例。同时提到了二进制I/O的相关函数fwrite和fread,以及文件位置的设置和检查方法fseek、ftell、feof和ferror。
摘要由CSDN通过智能技术生成

I是输入,O是输出

        都是以文件的形式,以字符流形式输入,以像素点形式输出。

     I/O流的打开 //打开文件

        #include

        FILE* fopen { //其实是一个被typdef修改的结构体

                const char * path, //文件路径,且不可更改

                const char * mode //打开模式,且不可更改

        };

        成功返回I/O流指针,作为后续I/O流函数的参数,失败返回NULL。

        打开模式:

                r - 只读,文件必须存在,从头开始读

                w -只写,文件不存在就创建,存在就清空,从头开始写

                a -追加,文件不存在就创建,存在不请空,从尾开始写

                r+ -读写,文件必须存在,从头开始读写

                w+ -写读,文件不存在就创建,存在就清空,从头开始写读

                a+ -追读,文件不存在就创建,存在不清空,从头开始读,从尾开始写

a  以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。
a+  以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。
上述的形态字符串都可以再加一个b字符,如rb、w+b或ab+等组合,加入b 字符用来告诉函数库打开的文件为二进制文件,而非纯文字文件。不过在POSIX系统,包含Linux都会忽略该字符。由fopen()所建立的新文件会具有S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666)权限,此文件权限也会参考umask值。
原文链接:https://blog.csdn.net/Zhangjay/article/details/6531551

    I/O流的关闭

        int fclose{

                FILE *fp //I/O流指针

        ;}

        成功返回0,失败返回EOF

打开文件示例如下:

//文件操作的标准C库函数
#include <stdio.h>
int main(void) {
    FILE *fp = NULL;
    //打开文件
    //fp = fopen("a.txt", "r"); //以只读方式打开当前目录下的a.txt文件
    fp = fopen("a.txt", "w"); //以只写方式打开当前目录下的a.txt文件,存在则清空,不存在则创建
    if(fp == NULL) {
        printf("打开失败.\n");
        return -1;
    }
    printf("打开成功\n"); //以后访问fp就是在访问文件本身
    //关闭文件
    fclose(fp);
    fp = NULL; //好习惯
    return 0;
}

格式化I/O

        格式化输出 //向文件中保存数据

        int fprintf {

                FILE* stream, // I/O流指针

                const char* format, //格式字符串 整型格式

                ………… // 输出数据

        };

        fprintf(fp,"%d",520); //fp是上文中的文件指针,输入%d格式的整型数进入fp文件中

        fprintf(fp,"%d %d",520,521); //fp是上文中的文件指针,输入%d格式的整型数进入fp文件中

        成功返回输出字符串,失败返回负数

        

        从文件中提取数据

        int fscanf {

                FILE* stream;

                const char* format

                …………

        };

fscanf(fp, "%d", &a) //从文件里按照%d的格式拿到数据给变量a

成功返回实际输入的数据项数,失败或遇到文件尾返回EOF

其主要知识点看代码:

//文件操作的标准C库函数
//当运行程序时,操作系统会帮助咱们的程序默认打开三个文件,这三个文件分别代表:键盘(又称标准输入),显示器(又称标准输出),显示器(又称标准出错),同样fopen打开也会得到三个FILE*指针,分别叫
//stdin,stdout,stderr,也就是:FILE *stdin, *stdout, *stderr
//stdin:代表标准输入,就是键盘
//stdout:代表标准输出,就是显示器
//stderr:代表标准出错,就是显示器
#include <stdio.h>
int main(void) {
    FILE *fp = NULL;
    //打开文件
    fp = fopen("a.txt", "r"); //以只读方式打开当前目录下的a.txt文件
    if(fp == NULL) {
        printf("打开失败.\n");
        return -1;
    }
    printf("打开成功\n"); //以后访问fp就是在访问文件本身
    int i = 0;
    char str[20] = {0};
    double d = 0;
    //按照指定的格式从文件a.txt中获取数据保存到变量i,str,d中
    fscanf(fp, "%d%s%lf", &i, str, &d);
    printf("i = %d, str = %s, d = %lg\n", i, str, d);
    //关闭文件
    fclose(fp);
    fp = NULL; //好习惯
    FILE *fpw = fopen("b.txt", "w+");
    //将变量i,str,d中的数据按照指定的格式保存到文件b.txt中
    fprintf(fpw, "copy:%d,%s,%lg\n", i, str, d);
    fclose(fpw);
    //stdin,stdout,stderr三个默认的文件指针演示
    fscanf(stdin, "%d%s%lf", &i, str, &d);//从键盘上按照指定的格式输入数据保存到变量i,str,d
    printf("i = %d, str = %s, d = %lf\n", i, str, d);
    fprintf(stdout, "i = %d, str = %s, d = %lf\n", i, str, d);//打印变量i,str,d到显示器
    fprintf(stderr, "i = %d, str = %s, d = %lf\n", i, str, d);//打印变量i,str,d到显示器
    return 0;
}

        注意: fscanf("%d%s%lf") 中间不要加空格!!

        //stdout:代表标准输出,就是显示器

        //stderr:代表标准出错,就是显示器

        二者的区别是一个自带缓冲区,一个不带缓冲区,stderr不带缓冲区即输入直接输出,不做缓存

        

输出字符

        int fputc { //向文件里保存一个字符

                int c;

                FILE* stream

        };

        成功返回实际输出的字符,失败返回EOF

        int fgetc { //从文件读取一个字符

                FILE* stream

        };

        成功返回实际输入的字符,失败或遇到文件尾返回EOF 类似NULL

使用这两个文件做拷贝

//fputc和fgetc标准库函数演示
#include <stdio.h>
int main(void) {
    FILE *fpr = fopen("a.txt", "r");
    FILE *fpw = fopen("b.txt", "w+");
    int ch; //暂存从文件中读取的字符
    while(1) {
        ch = fgetc(fpr); //从文件a.txt中读取一个字符保存到ch中
        if(ch == EOF) //判断是否读取失败或者读取到了文件尾部
            break;
        fputc(ch, fpw); //将读取到的字符保存到文件b.txt中
    }
    fclose(fpr);
    fclose(fpw);
    return 0;
}

                

非格式化I/O

输出字符串:

        int fputs{ 向文件里保存一个字符串

                const char *s, //字符串首地址

                FILE* stream // I/O流指针

        };

        fputs("hello", fp)

        成功返回非负数,失败返回EOF,不追加换行符

        char* fgets{ 从文件里取一个字符串

                char* s; //字符串缓冲区首地址

                int size, //字符串缓冲区大小

                FILE* stream

        };

        fgets(str, 10, fp)

        最多读取size -1 个字符,追加结尾空字符读到换行符返回,不把换行符换成空字符。成功返回s,失败或者遇到文件尾返回NULL

字符串文件拷贝示例如下:

//fputs和fgets标准库函数演示
#include <stdio.h>
int main(void) {
    FILE *fpr = fopen("a.txt", "r");
    FILE *fpw = fopen("b.txt", "w+");
    char str[4] = {0}; //暂存读取到的字符串数据
    while(fgets(str, 4, fpr) != NULL) //循环从文件a.txt读取字符串保存到str中,一次读3个字符
        fputs(str, fpw); //将数组中的字符串数据保存到文件b.txt中
    fclose(fpr);
    fclose(fpw);
    return 0;
}

最重要的三个I/O结构体:

        二进制I/O

        1.二进制输出:(写入)

        size_t fwrite { //向文件写入数据

                const void* ptr, //缓冲区地址 你要写入的数据对应的内存首地址

                size_t size, //元素字节数 写入的单个数据的大小

                size_t nmemb, //期望输出元素数

                FILE* stream; //I/O流指针

                };

        返回实际写入元素个数,遇到错误,返回值比nmemb小或为0. 写入的数据是二进制的。

        可以在命令界面利用 hexdump a.txt 把文件内容按照16进制的格式显示出来

        2.二进制输入 (读取)

        size_t fread { //从一个文件中读取数据

                void* ptr, //缓冲区地址,暂存从文件中读取的数据

                size_t size, //元素字节数

                size_t nmemb, //期望读取元素数

                FILE* stream //I/O流指针

        };

        成功返回实际读取到的元素个数,遇到错误或文件尾,返回值比nmemb小或为0

        rewind(fp); //将文件的读写位置重新指定到文件的最开头

        解释读写位置:

        typedef struct file{

                char *filename;

                int mode;

                unsigned long offset; //偏移量:用来记录文件的读写位置

        }

        结构体中的参数,用于记录读写位置

文件位置与随机访问:

设置文件读写位置

        int fseek {

                FILE* stream, // I/O流指针

                long offset, //偏移字节数

                int whence //偏移起点

                        //SEEK_SET: 从文件头

                        // SEEK_CUR: 从当前位置

                        // SEEK_END: 从文件尾

        };

        成功返回0,失败返回-1

        void rewind (FILE* stream); // fseek(stream,0l,SEEK_SET) rewind函数其实就相当于fseek函数,第二个0是从文件头,偏移是0,l 是因为offset默认是long类型,加 l 增加代码可读性

获取文件位置

        long ftell {

                FILE * stream // I/O流指针

        };

        成功返回当前文件位置,失败返回-1

        是否到文件尾

        int feof (FILE* stream); //返回0是没有读到文件尾,返回非0是文件尾

        是否出现错误

        int ferror(FILE* stream); //返回非0,文件错误,返回0,则不是文件出错导致EOF

        这是为了区分文件是读取失败还是到文件尾

     

        if(feof(fp)){

                printf("读到末尾了.\n");

                return 0;

        }

        if(ferror(fp)){

                printf("读失败了.\n");

                return -1;

        }

//fwrite,fread,fseek,rewind,ftell函数演示
#include <stdio.h>
int main(void) {
    FILE *fp = fopen("a.txt", "w+");
    int a[] = {1,2,3,4,5,6,7,8};
    int len = sizeof(a)/sizeof(a[0]);
    int size = 0;
    size = fwrite(a, sizeof(a[0]), len, fp);//向a.txt文件写入8个数据,单个数据大小4字节
    printf("实际写入了%d个数据.\n", size);
    //将文件的读写位置重新指定到文件的最开头
    rewind(fp); //如果不加这个函数,则会在上个写入数据的末尾继续向后读,则读取数据为0
    int b[8] = {0}; //暂存从文件中读取的数据
    size = fread(b, sizeof(int), 10, fp);//从a.txt文件中读取10个数据,单个数据大小4字节
    printf("实际读取了%d个数据.\n", size);
    for(int i = 0; i < size; i++)
        printf("%d ", b[i]);
    printf("\n");
    //fseek函数
    int c[2] = {0}; //暂存读取到的数据
    fseek(fp, 8, SEEK_SET);//从文件开头往后8个字节开始操作文件(读写位置位于3)
    //1 2 3 4 5 6 7 8
    //    ^
    fread(c, sizeof(int), 2, fp);//读取完毕之后,文件读写位置跑到5这个位置
    //1 2 3 4 5 6 7 8
    //        ^
    printf("%d %d\n", c[0], c[1]);
    fseek(fp, 8, SEEK_CUR);//从当前位置(5)往后8个字节开始操作文件(读写位置位于7)
    //1 2 3 4 5 6 7 8
    //            ^
    fread(c, sizeof(int), 2, fp);//读取完毕之后,文件读写位置跑到末尾
    //1 2 3 4 5 6 7 8
    //               ^
    printf("%d %d\n", c[0], c[1]);
    fseek(fp, -12, SEEK_END);//从文件的末尾往前12个字节开始操作文件(读写位置位于6)
    //1 2 3 4 5 6 7 8
    //          ^
    fread(c, sizeof(int), 2, fp);//读取完毕之后,文件读写位置跑到8
    //1 2 3 4 5 6 7 8
    //              ^
    printf("%d %d\n", c[0], c[1]);
    printf("当前文件的读写位置是:%ld\n", ftell(fp));
    fclose(fp);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值