Сравнивая 2 файла в c linux fgets - PullRequest
0 голосов
/ 09 января 2019

Мне нужно сравнить 2 файла и вернуть 1, если они совпадают, или 0, если нет, но функция всегда возвращает 0. Я понятия не имею, почему. Может быть, вы знаете разные функции, которые могут это сделать.

int compare(char *file_1, char *file_2)
{
    FILE *data_1 = fopen(file_1,"r");
    FILE *data_2 = fopen(file_2,"r");
    char line1[1000];
    char line2[1000];
    while(fgets(line1, sizeof(line1), data_1)&&fgets(line2, sizeof(line2), data_2)){
        if(strcmp(line1,line2)==0){
          fclose(data_1);
          fclose(data_2);
          return 0;
        }
    }
    fclose(data_1);
    fclose(data_2);
    return 1;
}

Ответы [ 6 ]

0 голосов
/ 09 января 2019

Другие проблемы, связанные со сравнением файлов, которые еще не рассмотрены в ответах

Файл данных с '\0'

Если файл содержит нулевой символ , fgets() будет читать этот символ, как и любой другой символ не в конце строки. Тогда следующий strcmp() будет не сравнивать всю прочитанную строку. Лучше использовать fread()/memcmp(), чтобы избежать этого недолгого.

Сравнение как текстовое или двоичное?

Открытие файла с помощью "r", как и в fopen(file_1,"r"), допускает различные переводы: конец строки, конец файла, метки порядка байтов.

Открытие с "r" имеет смысл сравнивать как text . В противном случае откройте файл в двоичном режиме "rb". Используйте fread() в любом случае.

Строка текста с "\r\n" в одном файле и строка текста с "\n" в другом файле могут сравниваться в режиме text , но могут отличаться в режиме binary .

Поскольку запись помечена как [linux], в режиме text не ожидается перевода.

несопоставимо

Во время чтения может произойти ошибка ввода, приводящая к спору сравнения.


Пример сравнительного кода

#include <stdbool.h>
#include <stdio.h>
#define FILE_COMPARE_N 1024

// 1: match
// 0: mis-match
// -1: failure
int stream_compare(FILE *f1, FILE *f2) {
  unsigned char buf1[FILE_COMPARE_N];
  unsigned char buf2[FILE_COMPARE_N];
  size_t l1, l2;
  do {
    l1 = fread(buf1, sizeof buf1[0], FILE_COMPARE_N, f1);
    if (ferror(f1))
      return -1;

    l2 = fread(buf2, sizeof buf2[0], FILE_COMPARE_N, f2);
    if (ferror(f2))
      return -1;

    if (l1 != l2 || memcmp(buf1, buf2, l1) != 0)
      return 0; // mis-match

  } while (l1);
  return 1; //match
}

int file_compare(const char *name1, const char *name2, bool as_text) {
  FILE *f1 = fopen(name1, as_text ? "rb" : "r");
  if (f1 == NULL)
    return -1;

  FILE *f2 = fopen(name2, as_text ? "rb" : "r");
  if (f2 == NULL) {
    fclose(f1);
    return -1;
  }

  int compare = stream_compare(f1, f2);

  fclose(f1);
  fclose(f2);
  return compare;
}
0 голосов
/ 09 января 2019

Вот решения: один символ для чтения / сравнения символов (вдохновлен ответом от myxaxa, но с исправлениями ошибок), а другой блок для чтения / сравнения блоков. Проверка ошибок была пропущена из-за лени, но надежная реализация ДОЛЖНА ИМЕТЬ ПРОВЕРКУ ОШИБКИ. (См. Комментарии)

#include <stdio.h>

int main(int argc, char **argv)
{
    int equal = 1;

    // TODO: check argc == 3

    FILE *data_1 = fopen(argv[1],"r");
    FILE *data_2 = fopen(argv[2],"r");

    // TODO: check data_1 and data_2 !=NULL

    for (;;)
      {
        int ch1, ch2;
        ch1 = fgetc(data_1); 
        ch2 = fgetc(data_2); 

        if (ch1 != ch2)
         { 
           equal = 0;
           break;
         }
        // We only need to test ch1, because at this point ch1 == ch2;   
        if (ch1 == EOF)
          break;
      }

    // TODO: check for read errors in data_1 and data_2 using ferror

    fclose(data_1);
    fclose(data_2);

    if (equal)
      printf("equal\n");
    else
      printf("not equal\n");
}

Второе решение с использованием блока чтения / сравнения:

#include <stdio.h>
#include <string.h>

#define BUFFSIZE 4096

int main(int argc, char **argv)
{
    int equal = 1;

    // TODO: check argc == 3

    FILE *data_1 = fopen(argv[1],"r");
    FILE *data_2 = fopen(argv[2],"r");

    // TODO: check data_1 and data_2 !=NULL

    for (;;)
      {
        char b1[BUFFSIZE];
        char b2[BUFFSIZE];

        size_t r1 = fread(b1, 1, BUFFSIZE, data_1); 
        size_t r2 = fread(b2, 1, BUFFSIZE, data_2);

        if (r1 != r2)
          {
            equal = 0;
            break;
          }

        // We only need to test r1, because at this point r1 == r2;   
        if (r1 == 0)
          break;
        if (memcmp(b1, b2, r1) != 0)
          { 
            equal = 0;
            break;
          }
      }

    // TODO: check for read errors in data_1 and data_2 using ferror 

    fclose(data_1);
    fclose(data_2);

    if (equal)
      printf("equal\n");
    else
      printf("not equal\n");
}

Время выполнения для чтения / сравнения char по файлу 840Mb по сравнению с самим собой:

real    0m5.158s
user    0m4.880s
sys     0m0.277s

... и для блока за блоком в одном файле:

real    0m0.353s
user    0m0.083s
sys     0m0.270s

Оба теста выполнили несколько прогонов, чтобы убедиться, что файл уже был кэширован

0 голосов
/ 09 января 2019

вы можете сравнивать файлы char по char (или byte byte), чтобы получить более быстрый результат в случае, если файлы не равны:

int compare(char *file_1, char *file_2)
{
    FILE *data_1 = fopen(file_1,"r");
    FILE *data_2 = fopen(file_2,"r");
    int ch1, ch2;
    for (;;) {
        ch1 = getc(data_1); 
        ch2 = getc(data_2); 

        if ((ch1 != ch2) || (ch1 == EOF)) break;
    }

    fclose(data_1);
    fclose(data_2);

    return (ch1 == ch2);
}
0 голосов
/ 09 января 2019

Ну, если эти файлы не слишком большие, хороший подход будет выглядеть так:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>

void fileExistence( const char *fileName );
char *readFile( const char *const fileName  );
size_t getFileSize ( FILE *const file );

int main ( void )
{
    const char *const file_1 = "file1.txt";
    const char *const file_2 = "file2.txt";

    char *const getFile_01 = readFile( file_1 );
    char *const getFile_02 = readFile( file_2 );

    if (strcmp( getFile_01, getFile_02 ) == 0 )
    {
        printf( "Files are the same\n" );
    }else
    {
        printf( "Files are not the same\n" );
    }

    free( getFile_01 );
    free( getFile_02 );

    return 0;
}

char *readFile( const char *const fName )
{
    fileExistence( fName );
    size_t size, length;
    char *buffer;
    FILE *file = fopen ( fName , "rb" );
    if ( file == NULL )
    {
        fprintf( stderr, "Can't open output file %s!\n", fName );
        exit( EXIT_FAILURE );
    }

    length = getFileSize( file );
    if ( length == 0 )
    {
        printf( "Error, getFileSize()\n" );
    }

    buffer = malloc( length + 1 );
    if ( buffer == NULL ){
        printf( "Error, malloc().\n" );
        exit( EXIT_FAILURE );
    }

    size = fread ( buffer , 1 , length, file );
    if ( size != length ){
        printf( "Error, fread().\n" );
        exit( EXIT_FAILURE );
    }

    buffer[length] = '\0';
    fclose ( file );
    return buffer;
}

size_t getFileSize ( FILE *const file )
{
    int fsk = fseek ( file , 0 , SEEK_END );
    if ( fsk == -1 )
    {
        printf( "Error, fseek()\n" );
        return 0;
    }
    long tel = ftell( file );

    if ( tel < 0 || (unsigned long) tel >= SIZE_MAX )
    {
        printf( "Error, ftell()\n" );
        return 0;
    }

    fsk = fseek (file , 0 , SEEK_SET );
    if ( fsk == -1 )
    {
        printf( "Error, fseek()\n" );
        return 0;
    }
    return ( size_t )tel;
}

void fileExistence( const char *const fileName )
{
    if( access(fileName, F_OK ) )
    {
        printf("The File %s\t not Found\n",fileName);
        exit( EXIT_FAILURE );
    }

    if( access(fileName, R_OK ) )
    {
        printf("The File %s\t cannot be readed\n",fileName);
        exit( EXIT_FAILURE );
    }

    if( access( fileName, W_OK ) )
    {
        printf("The File %s\t it cannot be Edited\n",fileName);
        exit( EXIT_FAILURE );
    }
}

Где вы читаете оба файла и сохраняете их в двух буферах и используете strcmp() для сравнения обоих.

Если вам нужно сравнить файлы без заглавных букв, вы можете использовать функцию strcasecmp(), которая находится в strings.h

0 голосов
/ 09 января 2019

Попробуйте прочитать весь файл за один раз, цикл будет выполняться до тех пор, пока не будет прочитан весь файл, и если он совпадет один раз, он всегда будет возвращать 0. Получите размер файла примерно так, используйте malloc и прочитайте>

fseek(fp, 0, SEEK_END); 
size = ftell(fp);
fseek(fp, 0, SEEK_SET); 
0 голосов
/ 09 января 2019

strcmp(line1,line2)==0 означает line1 и line2 равны равно , ваш код предполагает, что они различны

Существует другая ошибка, если файл начинается с содержимого другого файла, который вы считаете равным (если вы исправили strcmp )


Я рекомендую вам проверить результат fopen в случае, если хотя бы один из них не существует / не может быть открыт


решение может быть:

int compare(char *file_1, char *file_2)
{
  FILE *fp1 = fopen(file_1,"r");

  if (fp1 == 0)
    return 0;

  FILE *fp2 = fopen(file_2,"r");

  if (fp2 == 0) {
    fclose(fp1);
    return 0;
  }

  char line1[1000];
  char line2[1000];
  char * r1, * r2;
  int result;

  for (;;) {
    r1 = fgets(line1, sizeof(line1), fp1);
    r2 = fgets(line2, sizeof(line2), fp2);

    if ((r1 == 0) || (r2 == 0)) {
      result = (r1 == r2);
      break;
    }

    if (strcmp(line1,line2) != 0) {
      result = 0;
      break;
    }
  }

  fclose(fp1);
  fclose(fp2);

  return result;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...