首页 > 其他分享 >利用标准I/O函数,实现两个文件的复制功能

利用标准I/O函数,实现两个文件的复制功能

时间:2024-05-08 21:00:26浏览次数:13  
标签:fp 文件 函数 stream src int 复制 FILE size

目录

主要使用函数原型:

1.每次读写一个字符:

int fgetc(FILE *stream);
int fputc(int c, FILE *stream);

2.每次读写一行字符:

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

3.每次读写一个块字符:

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

4.另外,每个函数也使用了一些辅助函数,主要列举如下:

int feof(FILE *stream);
int ferror(FILE *stream);
long ftell(FILE *stream); //获取当前的位置偏移量

实现过程中几个易错细节小结

  • 几个读取函数的文件指针偏移

    int fgetc(FILE *stream),char *fgets(char *s , int size , FILE *stream),与size_t fread(void *ptr,size_t size,xize_t nmemb,FILE*stream)的每次读取,都是从文件的开始位置,向后读取;在下一次循环到来之前,文件内的当前位置,已经是已读取的字符之后。

    笔者一开始图方便,将读取函数fgetc()的返回值直接作为写入函数fputc()的参数,写了下面这行代码,就导致了一个比较低级的错误:

        while (!feof(fp_src)) // 每次读写一个字符的第19~33行简易实现
        {
            fputc(fgetc(fp_src), fp_dst);
        }
    

    导致复制出来的文件末尾都有一个乱码:

        fclose(fp_dst); // 关闭并释放文件指针堆空间
        fclose(fp_src);
        return 0;
    }�
    

    因此,此处的循环结束条件必须加上fgetc(fp_src)==EOF。

  • 行与块的区别

    行与块的区别,影响到设计的函数结构。

    行:即数据至多包含一个换行符“\n”,遇到换行符就进行下一次循环;因此,可以以fgets()是否为NULL为循环结束条件,即文件stream到达文件末尾即可。

    块:即一个固定的缓存空间,当数据块中出现换行符或字符串结束标记符等都不会受影响。因此将一个文件分为若干块,将不满一块时的判断条件作为循环结束条件,即:
    *size_t fread(void ptr,size_t size,xize_t nmemb,FILE*stream)< NMEMB

    并将剩下的字符继续输入。

  • 函数返回值

    如同第二点,返回值非常重要,可以以此为切入口设计程序架构。

    单字符 单行
    读取函数 int fgetc(FILE *stream); char *fgets(char *s , int size , FILE *stream); size_t fread(void *ptr,size_t size,xize_t nmemb,FILE*stream);
    成功/失败 读取到的字符/EOF(-1) 指针s/NULL nmemb/<nmemb
    写入函数 int fputc(int c, FILE *stream); char *fputs(const char *s ,FILE *stream); size_t fwrite(const void *ptr,size_t size,xize_t nmemb,FILE*stream);
    成功/失败 读取到的字符/EOF(-1) true/NULL nmemb/<nmemb

函数:每次读写一个字符


#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
    if (3 != argc) // 判断用户输入的参数是否有效。
    {
        perror("argument is invalid.\n");
        exit(1);
    }
    // 分别打开待拷贝和目标拷贝文件
    FILE *fp_src = fopen(argv[1], "rb"); // 以二进制形式读取第一个文件
    FILE *fp_dst = fopen(argv[2], "wb"); // 以二进制形式追加写入第二个文件
    if (!fp_dst || !fp_src)              // 如果打开错误,则直接打印错误信息并退出.
    {
        perror("fopen()");
        exit(1);
    }
    int data = fgetc(fp_src); // 设置变量,存放fgetc得到的字符
    while (1)
    {
        if (feof(fp_src) && data == EOF) // 如果当前光标已经到文件尾,则退出循环
        {
            printf("Copy completed.\n");
            break;
        }
        else if (ferror(fp_src)) // 如果出现未知错误,则退出
        {
            perror("fgetc()");
            exit(1);
        }
        fputc(data, fp_dst);
        data = fgetc(fp_src); // 继续存放fgetc得到的字符
    }
    fclose(fp_dst); // 关闭并释放打开文件申请的堆空间
    fclose(fp_src);
    return 0;
}

函数:每次读写一行字符


#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#define BUFSIZE 100 // 设置每一个缓冲区,即每一行能复制的最大字节数
int main(int argc, const char *argv[])
{
    if (3 != argc) // 判断用户输入的参数是否有效。
    {
        perror("argument is invalid.\n");
        exit(1);
    }
    // 分别打开待拷贝和目标拷贝文件
    FILE *fp_src = fopen(argv[1], "rb"); // 以二进制形式读取第一个文件
    FILE *fp_dst = fopen(argv[2], "wb"); // 以二进制形式追加写入第二个文件
    if (!fp_dst || !fp_src)              // 如果打开错误,则直接打印错误信息并退出.
    {
        perror("fopen()");
        exit(1);
    }
    char buf[BUFSIZE] = {0}; // 定义缓冲区变量,利用数组实现
    while (1)
    {
        bzero(buf, BUFSIZE);              // 每次操作前,进行清空缓冲区操作,以免内容泄露
        if (!fgets(buf, BUFSIZE, fp_src)) // 获取源文件数据,并判断是否为NULL,如果为NULL有两种情况判断
        {
            if (feof(fp_src)) // 如果当前光标已经到文件尾,则表示复制完成并退出循环
            {
                printf("Copy completed.\n");
                break;
            }
            else if (ferror(fp_src)) // 如果出现未知错误,则退出
            {
                perror("fgetc()");
                exit(1);
            }
        }
        fputs(buf, fp_dst); // 复制完成后,进行粘贴操作
    }
    fclose(fp_dst); // 关闭并释放打开文件申请的堆空间
    fclose(fp_src);
    return 0;
}

函数:每次读写一个块字符


#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#define SIZE 100 // 设置每一块能容纳的最大字节数
#define NMEMB 5  // 设置块数
int main(int argc, const char *argv[])
{
    if (3 != argc) // 判断用户输入的参数是否有效。
    {
        perror("argument is invalid.\n");
        exit(1);
    }
    // 分别打开待拷贝和目标拷贝文件
    FILE *fp_src = fopen(argv[1], "rb"); // 以二进制形式读取第一个文件
    FILE *fp_dst = fopen(argv[2], "wb"); // 以二进制形式追加写入第二个文件
    if (!fp_dst || !fp_src)              // 如果打开错误,则直接打印错误信息并退出.
    {
        perror("fopen()");
        exit(1);
    }
    char buf[SIZE * NMEMB] = {0}; // 定义缓冲区变量,利用数组实现
    long pre, cur;
    while (1)
    {
        bzero(buf, SIZE * NMEMB);                    // 每次操作前,进行清空缓冲区操作,以免内容泄露
        pre = ftell(fp_src);                         // 记录当前的偏移量;
        if (fread(buf, SIZE, NMEMB, fp_src) < NMEMB) // 获取源文件数据,并判断异常情况,并进行异常情况判断
        {
            if (feof(fp_src)) // 如果当前光标已经到文件尾,则需要把剩余的内容进行复制,这里利用pre,cur实现
            {
                fread(buf, cur - pre, 1, fp_src);
                fwrite(buf, cur - pre, 1, fp_dst);
                printf("Copy completed.\n");
                break;
            }
            else if (ferror(fp_src)) // 如果出现未知错误,则退出
            {
                perror("fgetc()");
                exit(1);
            }
        }
        fwrite(buf, SIZE, NMEMB, fp_dst); // 复制完成后,进行粘贴操作
    }
    fclose(fp_dst); // 关闭并释放打开文件申请的堆空间
    fclose(fp_src);
    return 0;
}

标签:fp,文件,函数,stream,src,int,复制,FILE,size
From: https://www.cnblogs.com/cino/p/18180861

相关文章

  • 欧拉函数
    1欧拉函数的定义和性质欧拉函数定义:\(\varphi(n)\)定义为不超过\(n\)且与\(n\)互质的正整数的个数。\[\varphi(n)=\sum\limits_{i=1}^n[gcd(n,i)=1]\]例如,\(n=4\)时,有\(1,3\)与\(4\)互质,因此\(\varphi(4)=2\);\(n=9\)时,有\(1,2,4,5,7,8\)与\(9\)互质,因此\(\v......
  • Linux 7修改网卡名称后,配置文件中的默认网关不生效【转载】
    背景 为了系统统一管理在创建了系统后统一将网卡名称修改为eth0,eth1等格式,并在修改完网卡名称重新编译grub配置文件重启后,添加了静态路由,使用route-n查看系统发现路由可以生效,但是配置的默认网关不生效,记录下排查过程。检查网卡配置文件并手动配置默认网关 在检查了网卡配......
  • [Cmake Qt]找不到文件ui_xx.h的问题?有关Qt工程的问题,看这篇文章就行了。
    前言最近在开发一个组件,但是这个东西是以dll的形式发布的界面库,所以在开发的时候就需要上层调用。如果你是很懂CMake的话,ui_xx.h的文件目录在$下然后除了有关这个ui_xx.h,还有一些别的可以简单聊聊的一、父子工程组织,或者说依赖关系在使用CMake进行开发的时候,一般可以有......
  • 08. C语言函数
    【函数基础】函数用于将程序代码分类管理,实现不同功能的代码放在不同函数内,一个函数等于一种功能,其它函数可以调用本函数执行。C语言规定所有的指令数据必须定义在函数内部,比如之前介绍的程序执行流程控制语句,另外修改全局变量的操作也是通过指令进行的,所以全局变量只能在函数内......
  • 文件IO练习题1
    利用标准IO函数接口实现文件拷贝,把本地磁盘的文件A中的数据完整的拷贝到另一个文本B中,如果文本B不存在则创建,要求文本A的名称和文本B的名称通过命令行传递,并进行验证是否正确。/***************************************************filename:Pro_StuInfo.c*author......
  • uniapp 新建文件
    uniapp新建文件支持ios和androidfunctioncreateFile(bases64,item,savedFilePathOne){//请求文件系统plus.io.requestFileSystem(plus.io.PRIVATE_DOC,function(fs){//letstorageAddress=fs.root.toURL();//创建文件fs.root.getFile......
  • 如何从多个文件夹内转移全部文件(忽略文件夹的结构)(进行复制)(再打包)
    首先,需要用到的这个工具:度娘网盘提取码:qwu2蓝奏云提取码:2r1z 04文件夹里面有只有1个名称为"1"的文件夹,“1”里面有“2”,“2”有“3”,“3”有“4”,从“1”开始,都有5个兔兔的图片,这是“1”里面的文件夹结构,现在要做的就是忽略文件夹结构,提取出全部的兔兔图片合并成一个压缩......
  • 如何把多个文件(夹)向下移动1层(在复制前或后进行)
    首先,需要用到的这个工具:度娘网盘提取码:qwu2蓝奏云提取码:2r1z 先看一下文件夹的结构,一共4个文件夹,1-4编号,每个里面都有兔兔的图片,作为操作说明(实际就按自己要处理的文件)打开工具,切换到“文件批量复制”的版块思路:先把4个文件夹拖入到“来源路径”里,整理一下,去掉1......
  • MySQL配置文件
    一.Linux1.MySQL5.7**MySQL5.7配置文件示例(适用于Linux)**[mysql]#设置mysql客户端默认字符集default-character-set=utf8[mysqld]#服务器端口port=3306#MySQL的安装目录basedir=/usr/local/mysql#MySQL的数据目录datadir=/var/lib/mysql#错误日志文件......
  • 把.nuget文件夹从C盘移到其它盘
    C盘是系统盘,考虑到很多程序都会占用系统盘资源,所以500G的固态硬盘究竟,一开始C盘就划了300G的大小。但即便这样,不知不觉中,C盘的空间也快不够用了。分析了一下C盘的空间占用情况,发现.nuget文件夹大概有40多G的大小。这个不能忍,直接上网搜了一下移到其它盘的方法。下面我写一下我的......