简体   繁体   中英

Unix: Copy file from current to another directory in C

I am trying to make a copy program that allows me to copy file from current directory to another directory. I am using open(), creat(), read(), write() so far.

For example: So far i can only copy the file to my current directory.

I have a folder name A_folder and a file name file_1 and i want to copy file_1 from my current directory to A_folder .

Can someone please help me?

Code and image are shown below

What I can do now: ./copy file1 copy_file

What I want is: ./copy file1 ./folder copy_file

  1. You need a helper function that constructs the path you need, A_folder/file_1 , when given A_folder and file_1 .

    A typical example of such a function is

     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; } 

    Note that the above function returns a dynamically allocated copy, so you should free() the result when you no longer need it.

  2. I prefer much more explicit error checking. Consider:

     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; } 

    Note the pattern how I use p and q pointers to write the read buffer contents in possibly more than one part. This can occur, if the source file is local, and the target file is on some wonky filesystem. There is no requirement that write() should either write the entire buffer or return with an error code; short writes -- where only some of the initial data in the given buffer was written -- are perfectly okay, and do occur in some situations. The above is my preferred way to handle those.

    Many consider this level of error checking -- especially checking the result value of close() , since at this point in time many operating systems (including Linux) never return an error there -- foolish or at least paranoid.

    I personally consider this kind of error checking "robust" , because I want my code to tell me, as the user, if anything untoward happened; I definitely do not want it to just assume everything went fine, I want it to be paranoid about it. (I am not saying that OP's code does not check error codes; I'm only saying this version is more careful and vocal about it.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM