【问题标题】:Unix: Copy file from current to another directory in CUnix:将文件从当前复制到C中的另一个目录
【发布时间】:2017-09-25 09:33:29
【问题描述】:

我正在尝试制作一个允许我将文件从当前目录复制到另一个目录的复制程序。 到目前为止,我正在使用 open()、creat()、read()、write()。

例如: 到目前为止,我只能将文件复制到我的当前目录。

我有一个文件夹名 A_folder 和一个文件名 file_1,我想将 file_1 从当前目录复制到 A_folder

有人可以帮帮我吗?

代码和图片如下所示

我现在可以做什么: ./copy file1 copy_file

我想要的是: ./copy file1 ./folder copy_file

【问题讨论】:

  • 请问av 是如何定义和初始化/设置的?
  • 好的,我已经更新了,
  • 你想把对perror()的调用放在对fprintf()的调用之前,以避免误导输出形式perror()。请提供您遇到的错误以及您用来引发错误的输入。
  • 我没有任何错误,我只是不知道如何将文件复制到另一个目录
  • 我又更新了

标签: c linux unix directory copy


【解决方案1】:
  1. 当给定A_folderfile_1 时,您需要一个帮助函数来构造您需要的路径A_folder/file_1

    这种函数的一个典型例子是

    char *combine_path(const char *dir, const char *name)
    {
        /* Calculate the lengths of the path components.
           If the respective parameter is NULL, the length is zero .*/
        const size_t  dirlen = (dir) ? strlen(dir) : 0;
        const size_t  namelen = (name) ? strlen(name) : 0;
    
        char         *path, *p;
    
        /* We allocate <dir> + '/' + <name> + '\0'. */
        path = malloc(dirlen + namelen + 2);
        if (!path) {
            errno = ENOMEM;
            return NULL;
        }
    
        /* Let p point to the current position in the
           resulting path. */
        p = path;
    
        /* If there is a directory part,
           copy it, and append a '/' after it. */
        if (dirlen > 0) {
            memcpy(p, dir, dirlen);
            p += dirlen;
            *p = '/';
            p += 1;
        }
    
        /* If there is a name part, copy it. */
        if (namelen > 0) {
            memcpy(p, name, namelen);
            p += namelen;
        }
    
        /* Append a NUL char, '\0', to terminate the
           dynamically allocated buffer.
           This turns it into a C string. */
        *p = '\0';
    
        /* Return the pointer to the dynamically-allocated
           memory, containing the concatenated paths
           as a single string. */
        return path;
    }
    

    请注意,上述函数返回一个动态分配的副本,因此当您不再需要该结果时,您应该free()
     

  2. 我更喜欢更明确的错误检查。考虑:

    int copy_file(const char *frompath, const char *topath)
    {
        struct stat frominfo, toinfo;
        char        data[BUFFERSIZE];
        ssize_t     n;
        int         src, dst, cause;
    
        if (!frompath || !*frompath ||
            !*topath || !*topath) {
            fprintf(stderr, "copy_file(): NULL or empty file name!\n");
            return errno = EINVAL;
        }
    
        src = open(frompath, O_RDONLY | O_NOCTTY);
        if (src == -1) {
            cause = errno;
            fprintf(stderr, "%s: Cannot open file: %s.\n", frompath, strerror(cause));
            return errno = cause;
        }
        if (fstat(src, &frominfo) == -1) {
            cause = errno;
            fprintf(stderr, "%s: Cannot get file statistics: %s.\n", frompath, strerror(cause));
            return errno = cause;
        }
    
        dst = open(topath, O_WRONLY | O_CREAT | O_EXCL, frominfo.st_mode & 0777);
        if (dst == -1) {
            cause = errno;
            fprintf(stderr, "%s: Cannot create file: %s.\n", topath, strerror(saved_errno));
            errno = cause;
        }
    
        while (1) {
            char *p, *q;
    
            n = read(src, buffer, sizeof buffer);
            if (n == 0) {
                /* End of input. */
                cause = 0;
                break;
            } else
            if (n < 0) {
                /* Error (or interrupt, EINTR). */
                if (n == -1)
                    cause = errno;
                else
                    cause = EIO; /* n < -1 is a bug. */
                fprintf(stderr, "%s: Read error: %s.\ņ", frompath, strerror(cause));
                break;
            }
    
            p = buffer;
            q = n;
            cause = 0;
            while (p < q) {
                n = write(dst, p, (size_t)(q - p));
                if (n > 0)
                    p += n;
                else
                if (n == -1) {
                    cause = errno;
                    break;
                else {
                    /* Bug; should never occur. */
                    cause = EIO;
                    break;
                }
            }
            if (cause) {
                fprintf(stderr, "%s: Write error: %s.\n", topath, strerror(cause));
                break;
            }
        }
    
        /* Failed? */
        if (cause) {
            unlink(topath);
            return errno = cause;
        }
    
        if (fstat(dst, &toinfo) == -1) {
            cause = errno;
            fprintf(stderr, "%s: Cannot get file information: %s.\n", topath, strerror(cause));
            unlink(topath);
            return errno = cause;
        }
    
        /* from may be a device; if so, its size
           will be zero. */
        if (frominfo.st_size > 0 &&
            frominfo.st_size != toinfo.st_size) {
            cause = EIO;
            fprintf(stderr, "%s: File size mismatch!\n", topath);
            unlink(topath);
            return errno = cause;
        }
    
        /* Careful closing. */
        if (close(src) == -1) {
            cause = errno;
            fprintf(stderr, "%s: Error closing file: %s.\n", frompath, strerror(cause));
            unlink(topath);
            return errno = cause;
        }
    
        if (close(dst) == -1) {
            cause = errno;
            fprintf(stderr, "%s: Error closing file: %s.\n", topath, strerror(cause));
            unlink(topath);
            return errno = cause;
        }
    
        /* Success. */
        return errno = 0;
    }
    

    请注意我如何使用pq 指针将读取缓冲区内容写入可能不止一个部分的模式。如果源文件是本地文件,而目标文件位于某个不稳定的文件系统上,则可能会发生这种情况。 要求write() 应该写入整个缓冲区或返回错误代码;短写(仅写入给定缓冲区中的一些初始数据)完全可以,并且在某些情况下确实会发生。以上是我首选的处理方式。

    许多人认为这种级别的错误检查 - 尤其是检查 close() 的结果值,因为此时许多操作系统(包括 Linux)从不返回错误 - 愚蠢或至少偏执。

    我个人认为这种错误检查“稳健”,因为我希望我的代码告诉我,作为用户,如果发生了任何不愉快的事情;我绝对不希望它只是假设一切都很好,我希望它对此感到偏执。 (我并不是说 OP 的代码不检查错误代码;我只是说这个版本更加谨慎和直言不讳。)

【讨论】:

  • 感谢您的帮助,我会试一试。
  • 您介意更详细地解释解决方案 1 吗?有些功能超出了我的理解。 X (
  • @mmm:我重新评论了combine_path() 函数。你现在明白了吗?您可以在man pages 找到malloc()strlen()memcpy() 的文档,即在命令行中运行man 3 mallocman 3 strlenman 3 memcpy
  • ?非常感谢。最后一件事,对用 C 语言进行 Linux 编程有什么建议吗?我希望我能成为解决问题的人而不是问它。???
  • @mmm:不幸的是,没有——但我喜欢你的态度:)。网络上的大多数教程和指南都很差。不过,您可以在教程中寻找两件事。当逐行阅读输入时,一个好的教程应该展示如何使用 POSIX.1-2008 getline() 来做到这一点。在处理网络连接时,教程应该使用getaddrinfo()。任何涉及这些主题但使用其他内容的教程都不值得阅读。
猜你喜欢
  • 2020-06-22
  • 1970-01-01
  • 2021-02-15
  • 1970-01-01
  • 2017-11-18
  • 1970-01-01
  • 2012-02-15
  • 2014-07-09
相关资源
最近更新 更多