c语言(read、write)和(fread、fwrite)和(fgets、fputs)三对函数分别实现文件拷贝功能, 模拟Linux下的cp命令

4 篇文章 0 订阅
2 篇文章 0 订阅

目录

一、read和write(系统IO)

代码

运行格式

二、fread和fwrite(标准IO)

代码

 运行格式

补充:关于每次读多个字节的

1.fwrite的原理

2.ftell

改进代码

三、fgets和fputs

代码

 运行格式

四、注意



一、read和write(系统IO)

代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <error.h>
#include <string.h>

#define ONCE_GET_SIZE 1

int Get_File_Descriptor(const char *pathname, int flags, mode_t mode); // 获取文件描述符
int Read_File_Date(int file_fd, char *buf, size_t size);               // 读数据
int Write_File_Date(int file_fd, char *buf, size_t size);              // 写数据
int Close_File_Descriptor(int file_fd);                                // 关闭文件
int Copy(int fdin, int fdout, char *buf);                              // 文件拷贝功能

/*
    功能:      获取文件描述符
    pathname: 文件路径
    flags:    说明此函数的多个选择项
    mode:     新建文件的访问权限,等于0则表示不需要创建
    返回值:    错误返回-1,正确返回文件描述符
*/
int Get_File_Descriptor(const char *pathname, int flags, mode_t mode)
{
    int fd;
    if (!mode)
    {
        fd = open(pathname, flags);
    }
    else
    {
        umask(0000);
        fd = open(pathname, flags, mode);
    }
    if (fd == -1)
    {
        perror("open error ");
        return -1;
    }
    return fd;
}

/*
    功能:      读取数据
    file_fd:   要读文件的文件描述符
    buf:       存放读取的数据
    size:       读取数据的大小
    返回值:    错误返回-1,正确返回读出的字节数量
*/
int Read_File_Date(int file_fd, char *buf, size_t size)
{
    size_t read_ret = read(file_fd, buf, size);
    if (read_ret == -1)
    {
        perror("write error");
        return -1;
    }
    return read_ret;
}

/*
    功能:      写入数据
    file_fd:   要写文件的文件描述符
    buf:       存放写入的数据
    size:       读取数据的大小
    返回值:    错误返回-1,正确返回写入的字节数量
*/
int Write_File_Date(int file_fd, char *buf, size_t size)
{
    size_t write_ret = write(file_fd, buf, size);
    if (write_ret == -1)
    {
        perror("write error");
        return -1;
    }

    return write_ret;
}

/*
    功能:      文件拷贝
    fdin:      源文件
    fdout:     目标文件
    buf:       数据
    返回值:    错误返回-1,正确返回0
*/

int Copy(int fdin, int fdout, char *buf)
{
    ssize_t read_size, write_size;
    while ((read_size = Read_File_Date(fdin, buf, ONCE_GET_SIZE)) > 0)
    {
        if ((write_size = Write_File_Date(fdout, buf, ONCE_GET_SIZE)) != read_size)
        {
            perror("copy error");
            return -1;
        }
    }
    return 0;
}

/*
    功能:      关闭文件
    返回值:    错误返回-1,正确返回0
*/
int Close_File_Descriptor(int file_fd)
{
    if (close(file_fd) == -1)
    {
        perror("close error");
        return -1;
    }
    return 0;
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        printf("输入参数有误!\n");
        return -1;
    }

    int fdin = Get_File_Descriptor(argv[1], O_RDONLY, 0);
    if (fdin == -1)
    {
        printf("源文件失败!\n");
        return -1;
    }

    char buf[ONCE_GET_SIZE]; // 接受读出的数据
    memset(buf, 0, sizeof(buf));

    int fdout = Get_File_Descriptor(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0777);
    if (fdout == -1)
    {
        printf("目标文件打开失败!\n");
        return -1;
    }

    Copy(fdin, fdout, buf); // 拷贝

    if (Close_File_Descriptor(fdin) == -1)
    {
        printf("源文件关闭失败\n");
        return -1;
    }

    if (Close_File_Descriptor(fdout) == -1)
    {
        printf("目标文件关闭失败\n");
        return -1;
    }
    return 0;
}

运行格式

gcc 文件拷贝.c -o cp

./cp 源文件路径 目的文件路径

二、fread和fwrite(标准IO)

代码

#include <stdio.h>
#include <string.h>

#define SIZE 1
#define NMEMB 1   // 每次读 1*1 个字节,如果需要读别的大小请看下面的
#define ERR -1

int File_Copy(const char *src, char *dest);
int File_Copy(const char *src, char *dest)
{
    FILE *fp_src = fopen(src, "r");
    FILE *fp_dest = fopen(dest, "w");
    if (fp_src == (FILE *)NULL || fp_dest == (FILE *)NULL)
    {
        perror("fropen error");
        return ERR;
    }
    char buf[SIZE * NMEMB + 1];
    while (1)
    {
        memset(buf, 0, sizeof(buf));
        if (fread(buf, SIZE, NMEMB, fp_src) < NMEMB)
        {
            if (feof(fp_src))
            {
                printf("拷贝完成!\n");
                break;
            }
            if (ferror(fp_src))
            {
                perror("拷贝失败!");
                return -1;
            }
        }
        if (fwrite(buf, SIZE, NMEMB, fp_dest) < NMEMB)
        {
            perror("fwrite error");
            return -1;
        }
    }
    if (fclose(fp_src) == ERR || fclose(fp_dest) == ERR)
    {
        perror("fclose error");
        return ERR;
    }
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        printf("参数有误!\n");
        return ERR;
    }
    if (File_Copy(argv[1], argv[2]) == ERR)
    {
        printf("拷贝失败!\n");
        return ERR;
    }
    return 0;
}

 运行格式

gcc 文件拷贝.c -o cp

./cp 源文件路径 目的文件路径

补充:关于每次读多个字节的

注意:前面是每次读 1*1的所以不需要考虑最后一组,但那样太慢了

1.fwrite的原理

所以每次写入的数据是 size * nmemb 的字节数

所以如果循环读写的代码如下时,也就是每次读4个字节。

#define SIZE 2
#define NUM 2

while (1)
    {
        memset(buf, 0, sizeof(buf));
        int read_ret = fread(buf, SIZE, NUM, fdin);
        if (read_ret < NUM)
        {
            if (feof(fdin))
            {
                printf("拷贝完成!\n");
                break;
            }
            if (ferror(fdin))
            {
                return -1;
            }
        }
        if (fwrite(buf, SIZE, NUM, fdout) < NUM)
        {
            printf("不够哦\n");
            return -1;
        }
    }

如果数据不是4的倍数时,则最后一组数据不会正确读入文件,但会读入buf,则这时候就需要ftell函数

注意:光标每次移动的距离就是  size * nmemb,所以最后一组数据feof会成立

2.ftell

ftell()函数主要用来读取,当前光标在文件中的位置。它的参数只有一个,就是需要读取的文件指针,返回值的类型是long,数字的大小代表当前光标距离文件起始处的字节数。

改进如下:

改进代码

    char buf[SIZE * NUM + 1];
    int start = 0, end = 0;
    while (1)
    {
        memset(buf, 0, sizeof(buf));
        start = ftell(fdin);
        int read_ret = fread(buf, SIZE, NUM, fdin);
        if (read_ret < NUM)
        {
            if (feof(fdin))
            {
                end = ftell(fdin);

                if(fwrite(buf, end - start, 1, fdout) < 1)//读最后的一组数据
                {
                        perror("error");
                        return -1;
                }
                
                printf("拷贝完成!\n");
                break;
            }
            if (ferror(fdin))
            {
                return -1;
            }
        }
        if (fwrite(buf, SIZE, NUM, fdout) < NUM)
        {
            printf("不够哦\n");
            return -1;
        }
    }

三、fgets和fputs

代码

#include <stdio.h>
#include <string.h>

#define SIZE 256  //一次性拷贝的量
#define ERR -1

int File_Copy(const char *src, char *dest);
int File_Copy(const char *src, char *dest)
{
    FILE *fp_src = fopen(src, "r");
    FILE *fp_dest = fopen(dest, "w");
    if (fp_src == (FILE *)NULL || fp_dest == (FILE *)NULL)
    {
        perror("fropen error");
        return ERR;
    }
    char buf[SIZE + 1];
    while (1)
    {
        memset(buf, 0, sizeof(buf));
        if (fgets(buf, SIZE, fp_src) == NULL)
        {
            if (feof(fp_src))
            {
                printf("拷贝完成!\n");
                break;
            }
            if (ferror(fp_src))
            {
                perror("拷贝失败!\n");
                return -1;
            }
        }
        if (fputs(buf, fp_dest) == EOF)
        {
            perror("fputs errpr");
            return -1;
        }
    }
    if (fclose(fp_src) == ERR || fclose(fp_dest) == ERR)
    {
        perror("fclose error");
        return ERR;
    }
    return 0;
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        printf("参数有误!\n");
        return ERR;
    }
    if (File_Copy(argv[1], argv[2]) == ERR)
    {
        printf("拷贝失败!\n");
        return ERR;
    }
    return 0;
}

 运行格式

gcc 文件拷贝.c -o cp

./cp 源文件路径 目的文件路径

四、注意

第三种fgets和fputs拷贝除文本以外的文件,可能会出错

原因是fputs到 '\0' 就停止,不会将 '\0' 写进去

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aogu181

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值