文件I/O--Linux下cp功能的实现

Linux下cp功能的实现

  • Linux 下cp命令的使用方法: cp filename1 filename2 //将filename1中的内容复制到filename2中.
  • 学习了Linux下文件文件i/o, 让我们一起通过学习的内容来实现一个cp命令吧!

逻辑分析

  1. 通过调用open()函数来打开filename1文件(已经存在并有内容), 再继续open()创建并打开filename2文件.
  2. 通过调用read()函数读filename1文件中的内容到缓冲区中, 再调用write()函数写进filename2文件中.
  • 注意: 看似思路非常明确并简洁, 过程并不是如此哦. 接下来我们看一看实现的过程, 先让我们展示一下最终代码.

最终代码

程序源码

/*	最终程序源码
*	次代码能实现大文件的拷贝
*	如果拷贝失败, 则调用unlink()函数, 删除filename2文件 */
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>

#define BUFSIZE 100

int main(int argc, char **argv)
{
        int     		fd1 = -1;
        int     		fd2 = -1;
        int     		rv = -1;
        char    		buf[BUFSIZE];

        if( argc!=3 )
        {
                printf("Input format: ./mycp filename1 filename2\n");
                return -1;
        }

        if( (fd1=open(argv[1], O_RDONLY)) <0 )
        {
                perror("Open file1 failure");
                return -2;
        }

        if( (fd2=open(argv[2], O_RDWR|O_CREAT, 0666)) < 0 )
        {
                perror("Open file2 failure");
                return -3;
        }

        memset(buf, 0, sizeof(buf));
        lseek(fd1, 0, SEEK_SET); 

    	while( (rv=read(fd1, buf, sizeof(buf))) > 0)
        {
                if( (rv=write(fd2, buf, rv)) <0 )
                {
                        perror("Write beter into file failure");
                        goto cleanup;
                }
        }
    	if( rv < 0 )
    	{
        		perror("Read data from file failuer");
        		goto cleanup;
    	}

cleanup:
    	if( rv < 0 )
    	{
        	unlink(argv[2]);
    	}
    
    	close(fd1);
    	close(fd2);
    	return 0;
}

运行结果

在这里插入图片描述

代码版本_一代

程序源码

// mycp_1.c
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>

#define BUFSIZE 100


int main(int argc, char **argv)
{
        int     fd1 = -1;
        int     fd2 = -1;
        int     rv1 = -1;
        int     rv2 = -1;
        char    buf[BUFSIZE];

        if( argc!=3 )
        {
                printf("Input format: ./mycp filename1 filename2\n");
                return -1;
        }

        if( (fd1=open(argv[1], O_RDONLY)) <0 )
        {
                perror("Open file1 failure");
                return -2;
        }

        if( (fd2=open(argv[2], O_RDWR|O_CREAT, 0666)) < 0 )
        {
                perror("Open file2 failure");
                return -3;
        }

        memset(buf, 0, sizeof(buf));
        lseek(fd1, 0, SEEK_SET); 

    	while( (rv1=read(fd1, buf, sizeof(buf))) > 0)
        {
                if( (rv2=write(fd2, buf, sizeof(buf))) <0 )
                {
                        perror("Write beter into file failure");
            unlink(argv[2]);
                        goto cleanup;
                }

        }
    	if( rv1 < 0 )
    	{
        	perror("Read data from file failuer");
        	unlink(argv[2]);
        	goto cleanup;
    	}
    
        close(fd1);
        close(fd2);

cleanup:
        close(fd1);
        close(fd2);

        return 0;
}

运行结果

在这里我们发现拷贝后的文件变大, 在代码中我们设置的缓冲区buf大小为100.
文件恰好是buf的整数倍, 也就是说我们最后一次写文件写了一个buf大小.
我们如何让最后一次只读到剩余文件的大小, 并将实际大小写进去呢.
让我们看代码_二代如何实现
在这里插入图片描述

代码版本_二代

程序源码

// mycp_2.c
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>

#define BUFSIZE 100


int main(int argc, char **argv)
{
        int     	fd1 = -1;
        int     	fd2 = -1;
        int        	rv1 = -1;
        int     	rv2 = -1;
        char    	buf[BUFSIZE];
        struct stat buf1;
        static int  a = 0;

        if( argc!=3 )
        {
                printf("Input format: ./mycp filename1 filename2\n");
                return -1;
        }

        if( (fd1=open(argv[1], O_RDONLY)) <0 )
        {
                perror("Open file1 failure");
                return -2;
        }

        if( (fd2=open(argv[2], O_RDWR|O_CREAT, 0666)) < 0 )
        {
                perror("Open file2 failure");
                return -3;
        }

        memset(buf, 0, sizeof(buf));
        lseek(fd1, 0, SEEK_SET); 

        static int b = 0;
        stat(argv[1], &buf1);
        printf("file size: %ld\n", buf1.st_size);
        a = (buf1.st_size/sizeof(buf));  //a为多少个sizeof(buf).

        while( b < a+1 )
        {
                b++;
                if( b < a+1 )
                {
                        if( (rv1=read(fd1, buf, sizeof(buf))) <0 )
                        {
                                perror("Read data from file failuer");
                                goto cleanup;
                        }

                        if( (rv2=write(fd2, buf, sizeof(buf))) <0 )
                        {
                                perror("Write beter into file failure");
                                goto cleanup;
                        }
                }
                else if( (buf1.st_size-(a)*sizeof(buf)) != 0 ) 
                {
                        if( (rv1=read(fd1, buf, buf1.st_size-(a)*sizeof(buf))) <0 )
                        {
                                perror("Read data from file failuer");
                                goto cleanup;
                        }

                        if( (rv2=write(fd2, buf, buf1.st_size-(a)*sizeof(buf))) <0 )
                        {
                                perror("Write beter into file failure");
                                goto cleanup;

                        }
                return 0;
                }
                else  //文件大小恰好是buf的整数倍
                {
                        return 0;
                }

        }
        close(fd1);
        close(fd2);

cleanup:
        close(fd1);
        close(fd2);

        return 0;
}

运行结果

在一代代码中, 最后一次总是写进去整个sizeof(buf)大小
那我们先计算文件大小, 在计算一下需要a个完整的sizeof(buf)
我们就复制a次, 每次都是sizeof(buf)大小
还有剩余, 那么我们将剩余(buf1.st_size-(a)*sizeof(buf))的写进filename2文件中即可
如果文件大小恰好和buf设置的大小为整数倍怎么办呢?
我们在代码83行中, 已经考虑到了哦! 最后读取文件数为0 也就是else 的条件哦!
我们完成了cp命令的拷贝, 学习到了获取文件大小的方法.
当然了, 这种是逻辑复杂, 并不是最优方法.
在这里插入图片描述

总结

特别注意使用if() 判断时, "()"中有既有加减运算和比较时, 一定要注意优先级的问题.
学到了如何获取文件大小: int stat(const char * file_name,struct stat *buf);
stat()用来将参数file_name所指的文件状态, 复制到参数buf所指的结构中.
在代码二代中, 我们的思路其实是没问题的, 但是这样太过于复杂.
我们可以在代码一代中进行改进, read()函数调用之后的返回值就是实际读到的大小.
在我们进行write()时, 第三个参数应该为 read()函数调用的返回值即可.
这样进行修改之后就变成我们最终代码.


经过这个cp命令的实现, 面对出现的问题, 产生自己的想法以及解决问题的方法, 这才是最重要的.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值