zoukankan      html  css  js  c++  java
  • 关于cp命令的编写

    关于cp命令的编写

    娄老师在课上详细的讲了命令who的编写过程~对此,我很有启发!于是想亲自动手试试~ 有什么不足的地方请大家提出来!

    Learning by doing ~ 做中学,真的只有自己动手去实践一遍,才能体会到其中的精髓!我跟着娄老师讲who命令时的思路来做了一遍cp,收获颇多~很爽!

    参考资料——别出心材的Linux系统调用

    在编写cp命令之前,同样有三个问题:

    • cp命令能做什么
    • cp命令是如何实现的?
    • 能不能自己编写一个cp命令?

    问题1. cp命令能做什么?

    cp能够复制文件,典型的用法是:

    cp source-file target-file
    

    如果target-file所指定的文件不存在,cp就创建这个文件,如果已经存在就覆盖,target-file的内容与source-file相同。

    问题2. cp命令是如何实现的?

    一个Linux命令的功能我们可以通过whatisman -f来查看,当然最好的方法是自己通过使用来体验一下:

    要进一步了解cp的用法,需要借助联机帮助manpages。我们输入man -k cp,再输入man 1 cp。

    要学会在帮助文档中寻找有用的信息!

    到这,即使以前没有用过cp命令,也大概知道它的功能了。

    了解cp的功能后,写出其伪代码:

    • 打开source-file
    • 创建target-file
    • 从source-file读出一段数据
    • 把这段数据写入target-file
    • 关闭source-file
    • 关闭target-file

    现在的问题是如何创建文件?如何打开文件?如何读文件,如何写文件?

    如何创建文件:

    如何读文件:

    我们用man -k read | grep file | grep 2搜一下,再man 2 read

    如何打开文件:

    图片中红线内部是需要用到的库。

    然后使用grep -nr XXX /usr/include查找相关宏。

    如何写文件:

    问题3.能不能自己编写一个cp命令

    看代码的时候我最先不理解的就是main函数的定义:

    int main(int argc, char *argv[]){}
    

    经查阅得知,argc是用来表示在命令行下输入命令时的参数个数,包括指令本身;argv[]是用来取得你输入的参数。针对具体指令分析如下(每一步解释由注释形式给出)。

    首先先先看一下涉及到的头文件的用处:

    • stdio.h 标准输入输出
    • stdlib.h C标准函数库
    • unistd.h Unix类系统定义符号常量
    • fcntl.h 定义了很多宏和open,fcntl函数原型
    • sys/types.h 基本系统数据类型
    • dirent.h unix类目录操作的头文件,包含了许多UNIX系统服务的函数原型,例如opendir函数、readdir函数。
    • termios.h 在Posix规范中定义的标准接口

    代码如下:

     #include        <stdio.h>//标准输入输出
     #include        <stdlib.h>//C标准函数库
     #include        <unistd.h>//Unix类系统定义符号常量
     #include        <fcntl.h>//定义了很多宏和open,fcntl函数原型
    
       #define BUFFERSIZE      4096//定义存储器容量
       #define COPYMODE        0644//定义复制的长度
    
     void oops(char *, char *);
    
     int main(int argc, char *argv[])
     {
    int in_fd, out_fd, n_chars;//三个描述符值
    char buf[BUFFERSIZE];//存储器位置
    
    /*cp的参数有两个,分别是要复制的文件,和目的目录,这样一共应该是有三个操作数
    所以要先检查argc的值是否为三,如果不是,返回标准错误*/
    if (argc != 3) {
        fprintf(stderr, "usage: %s source destination
    ", *argv);
        exit(1);
    }
    /*检查cp的第一个参数,要复制的文件,用open打开,in_fd为open返回的描述符
    如果返回-1,代表打开失败,提示错误*/
    if ((in_fd = open(argv[1], O_RDONLY)) == -1)
        oops("Cannot open ", argv[1]);
    
    /*检查cp的第二个参数,复制的目的地址,用create在目的地址创建新文件,out_fd为open返回的描述符
    如果返回-1,代表创建失败,提示错误*/
    if ((out_fd = creat(argv[2], COPYMODE)) == -1)
        oops("Cannot creat", argv[2]);
    
    /*cp指令的动作就是读取一个文件的内容到存储器,在新的地址创建空白文件,再从存储器将内容写入新文件。
    这里判断复制是否成功:
    如果能读取顺利,而读取的位数和写的位数不同,是写错误;
    如果读取失败,是读错误。*/
    while ((n_chars = read(in_fd, buf, BUFFERSIZE)) > 0)
        if (write(out_fd, buf, n_chars) != n_chars)
            oops("Write error to ", argv[2]);
    if (n_chars == -1)
        oops("Read error from ", argv[1]);
    
    /*这里执行的是关闭文件的动作,in_fd和out_fd两个文件描述符
    所指向的文件只要有一个关闭错误,就提示关闭错误。*/
    if (close(in_fd) == -1 || close(out_fd) == -1)
        oops("Error closing files", "");
    }
    
    /*这个是用来输出错误信息的函数*/
    void oops(char *s1, char *s2)
    {
    fprintf(stderr, "Error: %s ", s1);
    perror(s2);//用来将上一个函数发生错误的原因输出到标准设备(stderr)
    exit(1);
     }
    

    这里要注意main函数的两个参数:

    • argc记录了用户在运行程序的命令行中输入的参数的个数。
    • arg[]指向的数组中至少有一个字符指针,即arg[0].它通常指向程序中的可执行文件的文件名。

    代码验证:

    首先新建两个txt文件,我这里为1.txt和2.txt。

    1.txt里面的内容是111111;2.txt的内容为222222.

    经过cp命令后,1.txt的内容拷贝到了2.txt里面。

    将2.txt里面的内容复原后,用编写的cp命令来试一下,

    果然经过编写的cp命令后,1.txt的内容拷贝到了2.txt里面。

    说明编写的cp代码正确!

    总结

    通过上面的例子,我们学习了Linux中学习Linxu系统编程的方法:

    • 仔细研究manpages
    • 问题驱动,使用man -k key1|grep key2|...在manpages中搜索你要的内容
    • 阅读.h文件: 可以通过grep -nr XXXX /usr/incldue查找相关的宏定义,结构体定义,类型定义等
    • 解决一个问题要多个系统调用,可以参考manpages的SEE ALSO部分来得到相关系统调用的信息
  • 相关阅读:
    软件测试:Homework 3
    软件测试:Lab 1
    软件测试:Homework 2
    软件测试:Homework 1
    JAVA的回忆
    Java 操作符
    Java 笔录
    经典C#编程理解,概要,经典
    网络精灵
    签到计时
  • 原文地址:https://www.cnblogs.com/cxy1616/p/6063463.html
Copyright © 2011-2022 走看看