Копирование одного файла в другой (Unix/C)?

Я написал следующий код для копирования одного файла в другой. Хотя код работает, он по-прежнему выводит оба сообщения об ошибках. Почему это ? Я новичок в программировании на Unix и C (хотя раньше я работал с C++), поэтому любая помощь в максимально подробной информации была бы отличной. Спасибо !

int main(int argc, char *argv[])
{
    int n;
    char buf[4096];
    while ((n=read( open(argv[1], O_RDONLY) , buf, 4096))>0)
    {
        if (write(creat(argv[2], S_IREAD | S_IWRITE ), buf, n)!=n)
            printf("Error writing to file.\n");
    }
    if (n<0)
        printf("Error reading from file.\n");
    exit(0);
}

person Jenna Maiz    schedule 31.01.2016    source источник
comment
Вы повторно открываете оба файла при каждой итерации цикла.   -  person Weather Vane    schedule 01.02.2016
comment
Код работает, но действительно ли вы проверяли, что конечный файл имеет то же содержимое, что и исходный файл? Пожалуйста, проверьте размер файла › 4096.   -  person Weather Vane    schedule 01.02.2016
comment
Как вы думаете, с чего начинается чтение вновь открытого файла? И что делает функция create, если файл уже существует?   -  person too honest for this site    schedule 01.02.2016
comment
read() и write() возвращают ssize_t, а не int. Это не одно и то же.   -  person Andrew Henle    schedule 01.02.2016
comment
@WeatherVane Да, после запуска кода место назначения имеет то же содержимое, что и исходный файл.   -  person Jenna Maiz    schedule 01.02.2016
comment
@bayesianStudent этого не может быть, если размер файла › 4096. Если ваше второе сообщение об ошибке было напечатано, read не удалось, а write никогда не происходит.   -  person Weather Vane    schedule 01.02.2016


Ответы (2)


Вы открываете файл в каждой итерации и пытаетесь creat файл в каждой итерации.

Таким образом, за исключением самой первой итерации, все последующие записи завершатся ошибкой. Это, вероятно, «кажется, работает», потому что ваш входной файл содержит менее 4096 байт. Итак, первым призывом к написанию было сделать так, чтобы все выглядело так, как будто все скопировано. Если вы используете ввод, который имеет более 4096 байт, вы увидите только первые 4096 байт (при условии, что и read(), и write() не завершатся ошибкой).

Если бы write() все время выполнялось успешно (например, у вас был creat() вне цикла), тогда вызов open() постоянно открывает один и тот же файл и потенциально является бесконечным циклом, или ваша система исчерпала бы файловый дескриптор и вернула недопустимый файловый дескриптор и read() потерпит неудачу в этом.

Короче говоря: не пишите такой код :)

Переместите оба вызова open() и creat() за пределы цикла:

int fd = open(argv[1], O_RDONLY);
if (fd == -1) { 
   perror("open");
   exit(1);
}

int fd2 = creat(argv[2], S_IREAD | S_IWRITE );
if (fd2 == -1) { 
   perror("write");
   exit(1);
}

while ( (n=read( fd , buf, 4096)) > 0 )
{
    if ( write(fd2 , buf, n) != n )
        printf("Error writing to file.\n");
}
person P.P    schedule 31.01.2016
comment
Кроме того, добавьте проверку ошибок. Убедитесь, что fd (файловые дескрипторы) не являются отрицательными. Пути к файлам через командную строку могут быть недействительными. - person BryanT; 01.02.2016

В приведенном выше ответе указано, однако, что следует воздерживаться от использования creat(), поскольку create() является устаревшей функцией. создать (имя файла, режим); эквивалентно open(имя файла, O_WRONLY | O_CREAT | O_TRUNC, режим);

http://www.gnu.org/software/libc/manual/html_node/Opening-and-Closing-Files.html

Код можно было бы лучше написать так:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define BUFSIZE 4096

int main(int argc, char **argv)
{
    int infd, outfd;
    int n;
    char *infile = NULL;
    char *outfile = NULL;
    int src_flags, dest_flags;
    mode_t dest_perms;
    char buf[BUFSIZE];

    if (argc < 3) {
        fprintf(stderr, "At least src and dest files must be specified\n"); /*Never rely on users' inputs*/
        /*Print usage information if possible*/
        exit(EXIT_FAILURE); 
    }

    infile = argv[1];
    outfile = argv[2];  /*Presuming the order*/            

    src_flags = O_RDONLY;
    dest_flags = O_CREAT | O_WRONLY | O_TRUNC;  
    /*creat() is equivalent to open(fname, O_CREAT | O_WRONLY | O_TRUNC, mode)*/
    dest_perms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; /*rw-rw-rw-*/

    infd = open(infile, src_flags);
    if (infd == -1) {
        perror("cannot open src ");
        exit(EXIT_FAILURE);
    }

    outfd = open(outfile, dest_flags, dest_perms);
    if (outfd == -1) {
        perror("cannot open dest ");
        exit(EXIT_FAILURE);
    }

    while ((n = read(infd, buf, BUFSIZE)) > 0) {
        if (write(outfd, buf, n) != n) {
            fprintf(stderr, "failed to write buf\n");
            goto exit_failure;
        }
    }

    if (n == -1) {
        fprintf(stderr, "read() failed\n");
        goto exit_failure;
    }

exit_failure:
     if (infd) {
        close(infd);
     }

    if (outfd) {
        close(outfd);
    }

    printf("Copy successful\n");

    exit(EXIT_SUCCESS);
}
person nachiketkulk    schedule 01.02.2016