Копировать байты из одного файла в другой в обратном порядке в C

После проверки ответа здесь и запуска его в моей среде я обнаружил, что код все еще сталкивается с теми же проблемами, что и мой код. Эта проблема заключается в том, что всякий раз, когда у меня есть входной файл, похожий на этот...

 FILE A                 
|---------------------| 
| ABCDE               | 
| abcde               | 
|---------------------| 

Я получаю дополнительный пробел новой строки, сгенерированный в моем файле назначения.

 FILE B                 
|---------------------| 
| edcba               | 
|                     | 
| EDCBA               | 
|---------------------| 

После отладки моего кода я мог видеть, что '\n' копируется в файл назначения дважды, я хотел бы понять, почему lseek делает это.

Прикреплен мой код. Критический раздел, о котором идет речь, находится в цикле do / while. Я почти уверен, что мой мыслительный процесс в порядке, так как код из этого ответа, который я посмотрел, вывел бы те же самые результаты.

#define CHAR_SIZE 2048 
#define BUFF_SIZE 1    
#define PERMS 0666   


int main(int argc, char* argv[]){                                          
    if (argc < 3) {                                                        
        return 1;                                                          
        printf ("ERROR: not enough arguments\n");                          
    }                                                                      
    int src_file = 0; int dest_file = 0;                                   
    int n = -1;                                                            
    if((src_file=open(argv[1],O_RDONLY)) < -1) return 1;                   
    if((dest_file = creat(argv[2], PERMS)) < -1) return 1;                 
    printf ("The filesize is: %d\n", lseek(src_file, (off_t) 0, SEEK_END));
    char buffer[BUFF_SIZE];                                                
    lseek (src_file,n--,SEEK_END);                                         
    do {                                                                   
        read(src_file,buffer,BUFF_SIZE);                                   
        printf ("%s", buffer);                                             
        write(dest_file,buffer,BUFF_SIZE);                                 
    }while (lseek (src_file,n--,SEEK_END) > -1);                           
    printf("\n");                                                          
    return 0;                                                              

}                       

2 ответа

Решение

У вас есть ряд проблем. Ваш дополнительный перевод строки происходит от того факта, что POSIX определяет конец строки как newline (хотя не все файлы соответствуют). Поэтому, чтобы избавиться от лишней новой строки, вам необходимо:

int n = -2;

вместо

int n = -1;

(который явно читает конец строки POSIX и записывает его в ваш выходной файл)

Ваши дополнительные проблемы в том, что вы не будете знать, если ваш файл не открывается, потому что вы проверяете возврат неправильно:

// if ((src_file = open (argv[1],O_RDONLY)) < -1) return 1;
// if ((dest_file = creat (argv[2], PERMS)) < -1) return 1;

Возвращение -1 на провал. Поэтому вам необходимо:

if ((src_file = open (argv[1],O_RDONLY)) == -1) return 1;
if ((dest_file = creat (argv[2], PERMS)) == -1) return 1;

Далее ваш буфер НЕ будет содержать строку. Как минимум вам нужно 2-char массив для хранения 1-char плюс nul-terminating персонаж. Следующее не будет работать:

#define BUFF_SIZE 1
...
char buffer[BUFF_SIZE];
...
    printf ("%s", buffer);

Вы отправили не завершенный символ printf, Который, если вы компилируете с включенными предупреждениями (например, -Wall -Wextra) вы знаете об этом, потому что компилятор предупредит вас (возможно, даже без правильных флагов предупреждений в зависимости от вашего компилятора). Как минимум для того, чтобы вышеуказанное работало, вам нужно:

#define BUFF_SIZE 2

и вы должны застраховать себя buffer перед звонком printf, Вы можете сделать это с помощью:

char buffer[BUFF_SIZE] = "";
...
    read (src_file, buffer, BUFF_SIZE - 1);
    buffer[1] = 0;
    printf ("%s", buffer);
    write (dest_file, buffer, BUFF_SIZE - 1);

(вы должны проверить возврат read а также write чтобы подтвердить, что вы читаете / записываете количество байтов, которое вы считаете...)

Объединяя исправления (и показывая, что вы можете полностью удалить буфер и просто использовать int как buf char) вы можете сделать следующее:

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

#define CHAR_SIZE 2048
#define BUFF_SIZE 2
#define PERMS 0666

int main(int argc, char **argv) {

    if (argc < 3) {
        return 1;
        printf ("ERROR: not enough arguments\n");
    }

    int src_file = 0;
    int dest_file = 0;
    int n = -2;
    int nl = '\n';  /* explicit newline when writing in reverse */

    // if ((src_file = open (argv[1],O_RDONLY)) < -1) return 1;
    // if ((dest_file = creat (argv[2], PERMS)) < -1) return 1;
    if ((src_file = open (argv[1],O_RDONLY)) == -1) return 1;
    if ((dest_file = creat (argv[2], PERMS)) == -1) return 1;

    printf ("The filesize is: %ld\n", lseek(src_file, (off_t) 0, SEEK_END));

    lseek (src_file, n--, SEEK_END);
#ifdef WBUFCHAR
    int bufchar;
    do {    /* validate both read and write */
        if (read (src_file, &bufchar, BUFF_SIZE - 1) == 0) {
            fprintf (stderr, "error: read failure.\n");
            return 1;
        }
        putchar (bufchar);
        if (write (dest_file, &bufchar, BUFF_SIZE - 1) == 0) {
            fprintf (stderr, "error: write failure.\n");
            return 1;
        }
    } while (lseek (src_file, n--, SEEK_END) > -1);
#else
    char buffer[BUFF_SIZE];
    do {    /* validate both read and write */
        if (read (src_file, buffer, BUFF_SIZE - 1) == 0) {
            fprintf (stderr, "error: read failure.\n");
            return 1;
        }
        buffer[1] = 0;          /* nul-terminate */
        printf ("%s", buffer);
        if (write (dest_file, buffer, BUFF_SIZE - 1) == 0) {
            fprintf (stderr, "error: write failure.\n");
            return 1;
        }
    } while (lseek (src_file, n--, SEEK_END) > -1);
#endif
    /* explicity write the newline you removed earlier */
    if (write (dest_file, &nl, BUFF_SIZE - 1) == 0) {
        fprintf (stderr, "error: write failure.\n");
        return 1;
    }
    putchar ('\n');
    return 0;
}

примечание: скомпилируйте как обычно, чтобы использовать buffer, Компилировать с -DWBUFCHAR использовать bufchar код.

Пример компиляции и вывода

$ cat testabcde.txt
ABCDE
abcde

$ gcc -Wall -Wextra -Ofast -o bin/extranl extranl.c

$ ./bin/extranl testabcde.txt testrev.txt
The filesize is: 12
edcba
EDCBA

$ cat testrev.txt
edcba
EDCBA

$ gcc -Wall -Wextra -Ofast -DWBUFCHAR -o bin/extranlwbc extranl.c

$ ./bin/extranlwbc testabcde.txt testrevwbc.txt
The filesize is: 12
edcba
EDCBA

$ cat testrevwbc.txt
edcba
EDCBA

Попробуйте и дайте мне знать, если у вас есть дополнительные вопросы.

#include <unistd.h>                                                         
#include <fcntl.h>                                                          
#include <sys/types.h>                                                      

#define CHAR_SIZE 2048                                                      
#define BUFF_SIZE 1                                                         
#define PERMS 0666                                                          

int main(int argc, char* argv[]){                                           
    if (argc < 3) {                                                         
        printf ("ERROR: not enough arguments\n");                           
        return 1;                                                           
    }                                                                       
    int src_file = 0; int dest_file = 0;                                    
    int n = -1;                                                             
    if((src_file=open(argv[1],O_RDONLY)) == -1) return 1;                   
    if((dest_file = creat(argv[2], PERMS)) == -1) return 1;                 
    printf ("The filesize is: %d\n", lseek(src_file, (off_t) 0, SEEK_END)); 
    char buffer[BUFF_SIZE];                                                 
    lseek (src_file,n--,SEEK_END);                                          
    do {                                                                    
        read(src_file,buffer,BUFF_SIZE);                                    
        printf("%02x\n", *buffer);                                          
        if (*buffer == '\n')                                                
            n--;                                                            
        write(dest_file,buffer,BUFF_SIZE);                                  
    }while (lseek (src_file,n--,SEEK_END) > -1);                            
    printf("\n");                                                           
    return 0;                                                               

}                                                                           

Это решение было лучшим способом исправить лишние пробелы новой строки (\n\n) в моем выходном файле.

добавив эту часть в цикл do/while, я могу компенсировать добавленный дополнительный \ n.

if (*buffer == '\n')                                                
                n--;
Другие вопросы по тегам