IO进程day01(标准IO 函数接口)

目录

标准IO 函数接口

1》打开文件fopen

2》关闭文件fclose 

 3》文件读写操作

1> 每次读写一个字符:fgetc(),fputc()

 针对文件读写

 针对终端读写

 练习:实现 cat 命令功能    格式:cat 文件名

 2> 每次一个字符串的读写 fgets() 和 fputs()

 针对终端读写

 针对文件读写

练习:通过fgets实现"wc -l 文件名"命令功能(计算文件行数)

3>二进制读写fread() 和 fwrite()

针对终端读写

针对文件读写

4》其他操作

1> 重定向流到文件中

 2> 文件定位操作

总结:


标准IO 函数接口

1》打开文件fopen

man 3 fopen

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

功能:打开文件

参数:

path:打开的文件路径

mode:打开的方式

r:只读,当文件不存在时报错,文件流定位到文件开头

r+可读可写,当文件不存在时报错,文件流定位到文件开头

w:只写,文件不存在创建,存在则清空

w+可读可写,文件不存在创建,存在则清空

a:追加(在末尾写),文件不存在创建,存在追加,文件流定位到文件末尾

a+读和追加,文件不存在创建,存在追加,读文件流定位到文件开头,写文件流定位到文件末尾

注:当a+的方式打开文件时,写只能在末尾进行追加,定位操作是无法改变写的位置,但是可以改变读的位置

返回值:

成功:文件流

失败:NULL,并且会设置错误码

#include <stdio.h>

int main(int argc, char const *argv[])
{
FILE *fp;
    fp = fopen("test.txt", "r");//只读方式打开文件
    if (NULL == fp)//文件不存在,返回-1
    {
        perror("fopen err");
          return -1;
    }
    printf("fopen success\n");//文件存在,返回成功

return 0;
}
#include <stdio.h>

int main(int argc, char const *argv[])
{
FILE *fp;
    fp = fopen("test.txt", "w");//只写方式打开文件
    if (NULL == fp)//文件不存在,创建,存在则清空
    {
        perror("fopen err");
          return -1;
    }
    printf("fopen success\n");//文件存在,返回成功

return 0;
}
#include <stdio.h>

int main(int argc, char const *argv[])
{
FILE *fp;
    fp = fopen("test.txt", "a");//追加方式打开文件,文件不存在,创建,读定位到开头,写定位到末尾
    if (NULL == fp)
    {
        perror("fopen err");
          return -1;
    }
    printf("fopen success\n");//文件存在,返回成功

return 0;
}

补充:

perror( )用来将上一个函数发生错误的原因输出到标准设备 (stderr) 。参数 s 所指的字符串会先打印出, 后面再加上错误原因字符串。此错误原因依照全局变量errno 的值来决定要输出的字符串。在库函数中有个errno变量,每个errno值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了errno的值。perror函数只是将你设置的一些信息和现在的errno所对应的错误一起输出。

2》关闭文件fclose 

int fclose(FILE* stream);

功能:关闭文件

参数:stream:文件流

#include <stdio.h>

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

{

FILE *fp;

//1.打开文件

//fp = fopen("test.txt", "r"); //如果不存在会错误,因为只读r模式

fp = fopen("test.txt", "w");

if (NULL == fp)

{

perror("fopen err");

// while(1); //标准错误不缓存,错误信息会打印

return -1;

}

printf("fopen success\n");

//2.关闭文件

fclose(fp);

return 0;

}

 3》文件读写操作

1> 每次读写一个字符:fgetc(),fputc()

每次读一个字符fgetc()

int fgetc(FILE * stream);

功能:从文件中读取一个字符,并将当前文件指针位置向后移动一个字符。

参数:stream:文件流

返回值:成功:读到的字符

失败或读到文件末尾EOF(-1)

每次写一个字符fputc()

int fputc(int c, FILE * stream);

功能:向文件中写入一个字符, 成功写入后文件指针会自动向后移动一个字节位置。

参数:c:要写的字符

stream:文件流

返回值:成功:写的字符的ASCII

失败EOF(-1)

 针对文件读写
#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *fp;
    //1.打开文件
    fp = fopen("test.txt", "r+");//可读可写方式打开
    if (NULL == fp)
    {
        perror("fopen err");
        return -1;
    }
    printf("fopen success\n");

    char ch = fgetc(fp);//定义一个char类型变量接收读取的字符    每读取一次光标都会向后移
    printf("%d %c\n", ch, ch); //104 h

    ch = fgetc(fp);
    printf("%d %c\n", ch, ch); //101 e

//写的时候会先把光标移到末尾
    fputc('a', fp); //向文件中写个a
    fputc('b', fp); //向文件中写个b

//因为光标移动到末尾了,所以打印是EOF
    ch = fgetc(fp);
    printf("%d %c\n", ch, ch); //-1 EOF 因为以及到末尾了

    //2.关闭文件
    fclose(fp);
    return 0;
}

 针对终端读写

#include <stdio.h>

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

{

char ch;

ch = fgetc(stdin); //相当于getchar()

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

fputc(ch, stdout); //相当于putchar()

fputc(10, stdout);

fputc('b', stdout);

return 0;

}

 补充:feof 和 ferror

int feof(FILE * stream);

功能:判断文件有没有到结尾,也就是当前所在位置后面还有没有字符。

返回:如果到达文件末尾,返回非零值。如果后面还有字符则返回0

#include <stdio.h>
int main()
{
    FILE *fp;
    fp = fopen(argv[1], "r");//打开命令行中输入的文件,
    if (NULL == fp)
    {
        perror("fopen error\n");
        return -1;
    }
    printf("fopen success\n");

    char ch = fgetc(fp);//定义一个字符变量接收读取的内容
    printf("%d %c\n", ch, ch);//打印

    if (feof(fp))//判断此时光标是否在末尾
    {
        printf("end\n");
        return -1;
    }
//文件的末尾默认还有一个\0 EOF,读到最后一个有效数据时,不算末尾,需要再读一个才算光标到达末尾
    ch = fgetc(fp);
    printf("%d %c\n", ch, ch);

    if (feof(fp))//判断此时光标是否在末尾
    {
        printf("end\n");
        return -1;
    }
return 0;
}

 

int ferror(FILE * stream);

功能:检测文件有没有出错

返回:文件出错,返回非零值。如果没有出错,返回0

#include <stdio.h>
int main()
{    
    FILE *fp;
    fp = fopen(argv[1], "w");//w 只写,不可读
    if (NULL == fp)
    {
        perror("fopen error\n");
        return -1;
    }
    printf("fopen success\n");

    char ch = fgetc(fp);//w 只写,不可读,这个操作在读文件,属于操作错误,这时用ferror函数去判断就会返回非零值
    printf("%d %c\n", ch, ch);

    if (ferror(fp))//ferror进行判断之前的操作是否有误
    {
        printf("error\n");
        return -1;
    }
return 0;
}
 练习:实现 cat 命令功能    格式:cat 文件名
#include <stdio.h>
/* cat 文件名:查看文件内容,显示到终端。
   步骤:
        1.打开文件 fopen
        2.循环用fgetc获取文件内容
        3.当读到文件末尾标志EOF时结束
        4.将读取文件内容用fputc打印到终端
        5.关闭文件
*/
int main(int argc, char const *argv[])
{
    if (argc != 2)//命令行文件名个数是否等于 2 
    {
        printf("err: %s <filename>\n", argv[0]); //提示一下正确的格式
        return -1;
    }

    //1.打开文件
    FILE *fp = fopen(argv[1], "r");//打开命令行中输入的文件名
    if (NULL == fp)
    {
        perror("fopen err");
        return -1;
    }

    char ch = fgetc(fp);//读取文件中的字符
       while (!feof(fp))//当读取的光标处不是EOF时,说明没到末尾
     {
         fputc(ch, stdout);//输出一个字符
         ch = fgetc(fp);//读取字符,光标继续向后移动
     }
  
    //3. 关闭文件
    fclose(fp);

    return 0;
}
 2> 每次一个字符串的读写 fgets() 和 fputs()

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

功能:从文件中每次读取一行字符串

参数: s:存放字符串的地址

size:期望一次读取的字符个数

stream:文件流

返回值:成功:s的地址

失败或读到文件末尾:NULL

特性: 每次实际读取的字符个数为size-1个,会在末尾自动添加\0

每次读一行,遇到\n或者到达文件末尾后不再继续读下一行

并把它存储在s所指向的字符串内。

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

功能:向文件中写字符串

参数:s:要写的内容

stream:文件流

返回值:成功:非负整数

失败:EOF

 针对终端读写
#include <stdio.h>

int main(int argc, char const *argv[])
{
    char buf[32] = "";
    //输入操作
    fgets(buf, 32, stdin); //输入hello\n,  此时buf中存入内容: hello\n\0
    printf("buf: %s\n", buf);

    //每次输入都是从头开始写,,写完会自动补 0,会覆盖掉之前的内容,但\0 后的内容仍然存在
    fgets(buf, 32, stdin); //输入66\n,  此时buf中内容: 66\n\0o\n\0,
    printf("buf: %s\n", buf);

    //输出操作
    fputs("world", stdout);//把字符串输入到标准输出里
    fputs(buf, stdout);//把buf里的内容输入到标准输出里

    return 0;
}
 针对文件读写
#include <stdio.h>
int main(int argc, char const *argv[])
{
    FILE *fp;
    char buf[32] = "";

    fp = fopen("test.txt", "r+");//test.txt 文件中内容:hello\n  world\n  66\n\0
    if (NULL == fp)
    {
        perror("fopen err");
        return -1;
    }
    printf("fopen success\n");
    //读写操作
    fgets(buf, 32, fp); //遇到\n或到达末尾后不再继续读  buf:hello\n\0
    fputs(buf, stdout);

    fgets(buf, 32, fp); //  继续读下一行  buf:world\n\0
    fputs(buf, stdout);

    fgets(buf, 32, fp); //buf: 66\0ld\n\0
    fputs(buf, stdout);

//关闭文件
    fclose(fp);
    return 0;
}
练习:通过fgets实现"wc -l 文件名"命令功能(计算文件行数)
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    FILE *fp;
    char buf[32] = "";

    if (argc != 2)//判断命令行指针数组的元素个数
    {
        printf("err: %s <filenme>\n",argv[0]);
        return -1;
    }

    fp = fopen(argv[1], "r");//打开该文件
    if (NULL == fp)
    {
        perror("fopen err");
        return -1;
    }

    //循环fgets读文件, 只要读到就判断是否有\n, 如果有就累加行数
    int len = 0;
    while (fgets(buf, 32, fp) != NULL)
    {
        if (buf[strlen(buf) - 1] == '\n')
            len++;
    }
    printf("%d %s\n", len, argv[1]);  //wc -l会少一行,因为最后一行没有换行

    fclose(fp);
    return 0;
}
3>二进制读写fread() 和 fwrite()

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

功能:从文件流读取多个元素(将二进制数据从文件读出)

参数: ptr :是一个指针,是存放数据的存储空间的起始地址,用来存放读取元素

            size :元素大小 sizeof(元素数据类型)

            nmemb :读取元素的个数

            stream :要读取的文件流

返回值:成功:读取的元素的个数

读到文件尾或失败: 0

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

功能:将二进制数据写入文件

参数: ptr :是一个指针,保存要输出数据的空间的地址。

            size :要写入的字节数 sizeof(数据类型)

            nmemb : 要进行写入元素的个数

            stream: 目标文件流指针

返回值:成功:写的元素个数

失败 :-1

针对终端读写
    //针对终端读写
    char buf[32]= "";
    fread(buf,sizeof(char),10,stdin);//把终端输入 10 个 char 类型的数据读取到 buf 数组中
    printf("buf:  %s\n",buf);//打印 buf 的内容
    fwrite(buf,1,10,stdout);//在终端输出 10 个buf中的char类型数据

针对文件读写
    //针对文件读写
    FILE *fp;
    float arr[3] = {1.23,4.56,6.78};
    float data[3]= {0};
    fp= fopen(argv[1],"r+");//打开命令行中输入的文件
    if(NULL == fp)
    {
        printf("fopen error\n");
        return -1;
    }
    fwrite(arr,sizeof(float),3,fp);//把arr 数组中的3 个float 类型的数据写到fp 文件流中
    rewind(fp);//将文件流光标定位到文件头
    fread(data,4,3,fp);//将fp文件流中的3 个float 类型数据读取到data 数组中
    printf("%f %f %f\n",data[0],data[1],data[2]);//1.230000 4.560000 6.780000

4》其他操作

1> 重定向流到文件中

FILE * freopen(const char *pathname, const char *mode, FILE* fp);

功能:将指定的文件流重定向到打开的文件中

参数:path:文件路径

           mode:打开文件的方式(同fopen)

           fp:文件流指针

返回值:成功:返回打开的文件流指针

失败:NULL

#include <stdio.h>

int main(int argc, char const *argv[])
{
    printf("hello\n");
    freopen(argv[1],"w+",stdout);//将标准输出流重定向到命令行中的文件中
    printf("world\n");

    freopen("/dev/tty","w+",stdout);//将标准输出重定向到终端文件
    printf("66666666\n");

    return 0;
}

 

 2> 文件定位操作

void rewind(FILE *stream);

功能:将文件位置指针定位到起始位置

int fseek(FILE *stream, long offset, int whence);

功能:文件的定位操作

参数:stream:文件流

           offset:偏移量:正数表示向后文件尾部偏移,负数表示向文件开头偏移

           whence:相对位置:

                         SEEK_SET:相对于文件开头

                         SEEK_CUR:相对于文件当前位置

                         SEEK_END:相对于文件末尾

返回值:成功:0

失败:-1

注:当打开文件的方式为a或a+时,fseek不起作用

补充:其中SEEK_SET,SEEK_CURSEEK_END和依次为012.

简言之:

fseek(fp,100,0);把fp指针移动到离文件开头100字节处.

fseek(fp,100,1);把fp指针移动到离文件当前位置100字节处;

fseek(fp,-100,2);把fp指针退回到离文件结尾100字节处。

long ftell(FILE *stream);

功能:获取当前的文件位置

参数:要检测的文件流

返回值:成功:当前的文件位置,出错:-

#include <stdio.h>
int main(int argc, char const *argv[])
{
   FILE *fp;
    fp =fopen(argv[1],"w+");
    if(NULL == fp)
    {
        printf("open err\n");
        return -1;
    }
    printf("open success\n");

    //相当于开头位置,往后10个
    fseek(fp,10,0);
    fputc('a',fp);//在该位置往fp文件流中写个 a 

    //相对于当前位置,往后5个
    fseek(fp,5,1);
    fputs("hello",fp);//在该位置往fp 文件流中写个 hello

    //相对于最后位置,往前1个
    fseek(fp,-1,2);
    fputc('b',fp);//在该位置往fp 文件流中写个 b

    //计算文件位置
    long l= ftell(fp);//定义一个 l 变量保存fp 的文件长度
    printf("%ld",l);//打印

    return 0;
}

总结:

为什么用标准IO?

  1. 因为读写文件通常是大量的数据(相对于底层驱动的系统调用所实现的数据操作单位),这时,使用库函数可以大大减少系统调用的次数。
  2. 为了保证可移植性

关于缓存区: 库函数的缓冲区对于库函数,如果标准输出连到终端设备(直接输出到屏幕),则它是行缓冲的(遇到回车换行符或者是缓冲区满了才输出);否则(输出到文件)是全缓冲的(缓冲区填满或者是程序运行结束了才输出)。程序运行结束时,会刷新所有的缓冲区。


 今天的分享就到这里结束啦,如果有哪里写的不好的地方,请指正。
如果觉得不错并且对你有帮助的话请给个三连支持一下吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值