IO进程(学习)2024.8.14

今天学习标准IO的概念,特点,缓存区,文件IO函数的相关知识。

目录

标准IO

一、概念

二、特点

1.有缓存区(缓冲机制)

2.围绕流进行操作

3.默认打开了三个流

三、缓存区

1.行缓存:和终端操作相关

刷新行缓存的条件:

判断缓存区大小的两种方式:

强制刷新:

2.全缓存:和文件操作相关

刷新全缓存的条件:

3.不缓存:标准错误 stderr

四、函数

1.打开文件

2.关闭文件

3.读写文件

(1)每次一个字符的读写

fgetc

fputc

(2)每次一个字符串的读写

fgets

fputs

(3)二进制读写文件

fread

fwrite

4.文件定位操作

rewind

fseek

ftell

五、小练习

1.编程实现cat命令功能。

2.编程实现wc -l命令的功能

3.编程实现cp命令功能。

标准IO

文件类型:

b   c   d   -(普通文件)   l    s   p

一、概念

        标准IO就是C库中定义的一组用于输出输出的函数

二、特点

1.有缓存区(缓冲机制)

        通过缓冲机制减少系统调用(内核向上提供的一组接口)的次数,提高效率

2.围绕进行操作

        流用FILE*来描述,FILE代表的是结构体,描述所操作文件的信息

3.默认打开了三个流

        stdin(标准输入)、stdout(标准输出)、stderr(标准错误)

sudo ctags -R的使用        (追代码)
vi -t  FILE(typedef定义数据类型、宏定义、结构体等)

将光标定位在目标位置,ctrl+]  :向下追代码
ctrl+t:回退
q:退出

三、缓存区

1.行缓存:和终端操作相关

刷新行缓存的条件:

1.程序正常退出
2.\n刷新

3.缓存区满

4.强制刷新

判断缓存区大小的两种方式:

1.利用for循环判断缓存区大小

for(int i=0;i<300;i++)
{
    printf("%4d",i);//打印0-255,说明缓存区大小为256*4=1024
}
while(1);

2.利用stdout

// 前提要启动缓存区,先向缓存区中写入一些数据
printf("缓存区空间大小为:");

// 通过stdout访问结构体中的成员,缓存区的结束地址和起始地址
printf("%ld\n", stdout->_IO_buf_end - stdout->_IO_buf_base); // 1024
强制刷新:
int main(int argc, char const *argv[])
{
    printf("hello");   
    fflush(NULL);     // 强制刷新 可以通过man fflush查看,int fflush(FILE *stream);
    while (1);
    return 0;
}

2.全缓存:和文件操作相关

刷新全缓存的条件:

1.程序正常退出

2.缓存区满

3.强制刷新        fflush

3.不缓存:标准错误 stderr

四、函数

1.打开文件

#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
参数:
        path:打开文件
        mode:打开方式
                r:只读,流被定位到文件开头
                r+:可读可写,流被定位到文件开头
                w:只写,文件不存在创建,文件存在清空,流被定位到文件开头
                w+:可读可写,文件不存在创建,文件存在清空,流被定位到文件开头
                a:追加,文件不存在创建存在追加,流被定位到文件末尾
                a+:可读可写,文件不存在创建,存在追加,开始进行读时从头读,进行写时流被定位到文件末尾
返回值: 成功:文件流
               失败:NULL,并且设置errno(错误码)

2.关闭文件

#include<stdio.h>
int fclose(FILE* stream);
功能:关闭文件
参数:stream:文件流

打开关闭文件案例:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    // 打开文件
    FILE *fp = fopen("./test.txt", "r");
    // 打开失败
    if (NULL == fp)
    {
        perror("文件打开失败");
        return -1;
    }
    printf("文件打开成功\n");
    
    // 关闭文件
    fclose(fp);
    return 0;
}

3.读写文件

(1)每次一个字符的读写
fgetc

#include <stdio.h>
int fgetc(FILE *stream);
功能:从文件中读一个字符
参数:stream:文件流
返回值:成功:读到字符
              失败或读到文件末尾:EOF(-1)

补充:

#include <stdio.h>
int ferror(FILE *stream);
功能:判断读文件时是否出错
返回值:非0表示出错

int feof(FILE *stream);
功能:判断读文件时是否到文件末尾
返回值:非0表示读到文件末尾

fgetc的案例:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    // 打开文件
    FILE *fp = fopen("./test.txt", "r");
    // 打开失败
    if (NULL == fp)
    {
        perror("文件打开失败");
        return -1;
    }
    printf("文件打开成功\n");

    int ch = fgetc(fp); // 调用一次读一个字符,多次调用继续向后读取字符

    if (ch == EOF)
    {
        if (ferror(fp))
        {
            perror("读文件失败");
            return -1;
        }
        if (feof(fp))
        {
            perror("已经读到了文件的末尾");
        }
    }
    else
    {
        printf("%c\n", ch);
    }
    
    // 关闭文件
    fclose(fp);
    return 0;
}
fputc

#include <stdio.h>
int fputc(int c, FILE * stream)
功能:向文件中写入一个字符
参数:c:要写的字符
           stream:文件流
返回值:成功:写的字符的ASCII
               失败:EOF

fputc的案例:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    // 打开文件
    FILE *fp = fopen("./test.txt", "w+");
    // 打开失败
    if (NULL == fp)
    {
        perror("文件打开失败");
        return -1;
    }
    printf("文件打开成功\n");

    fputc('h', fp);
    fputc(65, fp);

    rewind(fp);

    int ch = fgetc(fp);
    printf("%c\n", ch);
    ch = fgetc(fp);
    printf("%c\n", ch);

    // 关闭文件
    fclose(fp);
    return 0;
}
(2)每次一个字符串的读写
fgets

#include <stdio.h>
char *fgets(char *s, int size, FILE *stream);
功能:从文件中读取一串字符
参数:s:存放读取的字符串的首地址
           size:读取的大小
           stream:文件流
返回值:成功:读取的字符串的首地址
              失败或读到文件末尾:NULL
特性:1.一次调用最多读取一行数据
           2.实际读到个数为size-1个,末尾自动添加\0

 fgets案例:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    // 打开文件
    FILE *fp = fopen("./test.txt", "r");
    char buf[32];

    // 打开失败
    if (NULL == fp)
    {
        perror("文件打开失败");
        return -1;
    }
    printf("文件打开成功\n");

    fgets(buf, 6, fp);
    printf("%s\n", buf);
    fgets(buf, 2, fp);
    printf("%s\n", buf);

    for (int i = 0; i < 6; i++)
    {
        printf("%c ", buf[i]);
    }
    printf("\n");

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

#include <stdio.h>
int  fputs(const char *s,  FILE *stream);
功能:向文件中写字符串
参数:s:要写的内容
           stream:文件流
返回值:成功:非负整数
               失败:EOF

fputs案例:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    // 打开文件
    FILE *fp = fopen("./test.txt", "r+");
    char buf[32];
    // 打开失败
    if (NULL == fp)
    {
        perror("文件打开失败");
        return -1;
    }
    printf("文件打开成功\n");

    fputs("hello", fp);
    rewind(fp);
    fgets(buf, 6, fp);
    printf("%s\n", buf);
    // 关闭文件
    fclose(fp);
    return 0;
}
(3)二进制读写文件

可以读写任意类型的数据,以二进制的方式进行读写

fread

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从文件流读取多个元素
参数: ptr :用来存放读取元素 (可以用来读取任意类型的数据)
            size :元素大小  sizeof(数据类型)
            nmemb :读取对象的个数
            stream :要读取的文件
返回值:成功:读取对象的个数
              失败或读到文件尾:0

fwrite

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:按对象写
参数:同上    
返回值:成功:写的元素个数
              失败 :0

二进制读写文件案例:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    // 打开文件
    FILE *fp = fopen("./test.txt", "w+");
    int arr[3] = {1, 2, 3};
    int arr1[3] = {0};
    // 打开失败
    if (NULL == fp)
    {
        perror("文件打开失败");
        return -1;
    }
    printf("文件打开成功\n");

    // 四个参数分别为:要写的数据地址,一个数据的大小,数据的个数,文件流
    fwrite(arr, sizeof(int), 3, fp);
    rewind(fp); // 将文件的位置指针定位到开头位置
    fread(arr1, sizeof(int), 3, fp);

    for (int i = 0; i < 3; i++)
    {
        printf("%d ", arr1[i]);
    }
    printf("\n");
    // 关闭文件
    fclose(fp);
    return 0;
}

4.文件定位操作

rewind

void rewind(FILE *stream);
功能:将文件位置指针定位到起始位置

fseek

int fseek(FILE *stream, long offset, int whence);
功能:文件的定位操作
参数:stream:文件流
           offset:偏移量:正数表示向后文件尾部偏移,负数表示向文件开头偏移
           whence:相对位置:
                   SEEK_SET:相对于文件开头
                   SEEK_CUR:相对于文件当前位置
                   SEEK_END:相对于文件末尾
返回值:成功:0
              失败:-1

fseek案例:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    // 打开文件
    FILE *fp = fopen("./test.txt", "w+");

    // 打开失败
    if (NULL == fp)
    {
        perror("文件打开失败");
        return -1;
    }
    printf("文件打开成功\n");

    fseek(fp, 5, SEEK_SET);
    fputc('A', fp);

    fseek(fp, -4, SEEK_CUR);
    fputc('B', fp);

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

long ftell(FILE *stream);
功能:获取位置指针当前的文件位置
参数:要检测的文件流
返回值:成功:当前的文件位置

              失败:-1

 ftell案例

#include <stdio.h>

int main(int argc, char const *argv[])
{
    // 打开文件
    FILE *fp = fopen("./test.txt", "w+");

    // 打开失败
    if (NULL == fp)
    {
        perror("文件打开失败");
        return -1;
    }
    printf("文件打开成功\n");

    fseek(fp, 5, SEEK_SET);
    fputc('A', fp);

    fseek(fp, -4, SEEK_CUR);
    fputc('B', fp);

    long l = ftell(fp);
    printf("%ld\n", l);

    //计算文件中字符的个数
    fseek(fp, 0, SEEK_END);
    l = ftell(fp);
    printf("%ld\n", l);
    // 关闭文件
    fclose(fp);
    return 0;
}

 补充:
        1.rewind(fp)和fseek(fp, 0, SEEK_SET)等价
        2.可以通过此函数计算文件中字符个数
        3.当打开文件的方式为a或a+时,fseek不起作用

五、小练习

1.编程实现cat命令功能。

思路:打开文件,循环读文件,当读到文件末尾时循环结束,打印读到的数据,关闭文件

示例:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    // 打开文件
    FILE *fp = fopen(argv[1], "r+");
    // 打开失败
    if (NULL == fp)
    {
        perror("文件打开失败");
        return -1;
    }
    printf("文件打开成功\n");
    for (int i = 0;; i++)
    {
        int ch = fgetc(fp);
        if (ch == EOF)
        {
            if (ferror(fp))
            {
                perror("读文件失败");
                return -1;
            }
            if (feof(fp))
            {
                break;
            }
        }
        printf("%c", ch);
    }

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

2.编程实现wc -l命令的功能

思路:打开文件,循环读文件,当读到文件末尾时循环结束,在循环中判断是否是一行,如果是则对整型变量进行自加,关闭文件。

示例:

#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    // 打开文件
    FILE *fp = fopen(argv[1], "r+");
    char buf[100];
    // 打开失败
    if (NULL == fp)
    {
        perror("文件打开失败");
        return -1;
    }
    printf("文件打开成功\n");
    int len = 0;
    while (fgets(buf, sizeof(buf), fp) != NULL)
    {
        if (buf[strlen(buf) - 1] == '\n')
        {
            len++;
        }
    }
    printf("%d\n", len);
    // 关闭文件
    fclose(fp);
    return 0;
}

3.编程实现cp命令功能。

cp 源文件 新文件名

要求:运行代码时在./a.out 后指定源文件和新文件

思路:先判断命令行参数是不是三个,分别打开两个文件,循环将源文件的内容读出来写到新文件中,循环的结束条件读到文件末尾节结束,关闭文件

示例:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    if (argc != 3)
    {
        printf("命令行参数不是三个,请重新运行\n");
        return -1;
    }

    FILE *fp = fopen(argv[1], "r+");
    if (NULL == fp)
    {
        perror("原文件打开失败");
        return -1;
    }
    printf("原文件打开成功\n");

    FILE *fp1 = fopen(argv[2], "w+");
    if (NULL == fp1)
    {
        perror("新文件打开失败");
        return -1;
    }
    printf("新文件打开成功\n");

    char buf[100];
    int n;
    while ((n = fread(buf, sizeof(char), sizeof(buf), fp)) != 0)
    {
        fwrite(buf, sizeof(char), n, fp1);
    }

    // 关闭文件

    fclose(fp);
    fclose(fp1);

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值