Не удалось записать последующие сжатые данные в выходной файл в C - PullRequest
0 голосов
/ 01 мая 2019

Я читаю данные из входного файла и сжимаю их с помощью функции библиотеки bzip, вызывающей BZ2_bzCompress в C. Я могу успешно сжать данные.Но я не могу записать все сжатые данные в выходной файл.Только первая сжатая строка может быть написана.Я что-то здесь упускаю.

int main()
{
    bz_stream bz;   
    FILE*   f_d;
    FILE* f_s;
    BZFILE* b;  
    int     bzerror = -10;  
    unsigned int nbytes_in;
    unsigned int nbytes_out;
    char buf[3000] = {0};
    int result = 0;
    char buf_read[500];
    char file_name[] = "/path/file_name";
    long int save_pos;

    f_d = fopen ( "myfile.bz2", "wb+" );    
    f_s = fopen(file_name, "r");

    if ((!f_d) && (!f_s)) {

        printf("Cannot open files");
        return(-1);
    }

    bz.opaque = NULL;
    bz.bzalloc = NULL;
    bz.bzfree = NULL;


    result = BZ2_bzCompressInit(&bz, 1, 2, 30); 


    while (fgets(buf_read, sizeof(buf_read), f_s) != NULL)
    {       
        bz.next_in = buf_read;
        bz.avail_in = sizeof(buf_read);
        bz.next_out = buf;
        bz.avail_out = sizeof(buf);

        printf("%s\n", buf_read);
        save_pos = ftell(f_d);
        fseek(f_d, save_pos, SEEK_SET);
        while ((result == BZ_RUN_OK) || (result == 0) || (result ==  BZ_FINISH_OK))
        {
            result = BZ2_bzCompress(&bz, (bz.avail_in) ? BZ_RUN : BZ_FINISH);                       

            printf("2 result:%d,in:%d,outhi:%d, outlo:%d \n",result, bz.total_in_lo32, bz.total_out_hi32, bz.total_out_lo32);
            fwrite(buf, 1, bz.total_out_lo32, f_d);         

        }
        if (result == BZ_STREAM_END)
        {
            result = BZ2_bzCompressEnd(&bz);                    
        }

        printf("3 result:%d, out:%d\n", result, bz.total_out_lo32);
        result = BZ2_bzCompressInit(&bz, 1, 2, 30); 
        memset(buf, 0, sizeof(buf));
    }   

    fclose(f_d);
    fclose(f_s);        
    return(0);
}

1 Ответ

1 голос
/ 02 мая 2019

TL; DR: Есть несколько проблем, но главная, которая объясняет проблему, о которой вы спрашивали, вероятно, заключается в том, что вы сжимаете каждую строку файла независимо, а не весь файл как единое целое.


  1. Согласно документам BZ2_bzCompressInit, аргумент bz_stream должен быть выделен и инициализирован перед вызовом.Ваша (автоматически) распределяется, но не (полностью) инициализируется.Было бы яснее и проще изменить его на

        bz_stream bz = { 0 };
    

    , а затем пропустить назначения на bz.opaque, bz.alloc и bz.free.

  2. Youхранить, но не проверять возвращаемое значение вашего BZ2_bzCompressInit вызова.В конечном итоге он проверяется в состоянии внутреннего цикла while, но вы не обнаруживаете там условия ошибки, а вместо этого просто успех и нормальные условия завершения.

  3. Ваша обработкавходной буфер имеет значительные недостатки.

    • Во-первых, вы неправильно указали количество доступных входных байтов:

      bz.avail_in = sizeof(buf_read);
      

      Поскольку вы используете fgets()для чтения данных в буфер ни при каких обстоятельствах не указывается полный размер буфера, занятого входными данными, поскольку fgets() гарантирует, что в массив записывается терминатор строки.На самом деле, это может быть и хуже, потому что fgets() остановится после новых строк, поэтому при успешном чтении он может предоставить всего один входной байт.

      Если вы хотите придерживаться fgets(), тогда вынеобходимо использовать strlen(), чтобы определить число байтов, доступных при каждом чтении, но я бы предложил вместо этого переключиться на fread(), который будет более надежно заполнять буфер, указать возвращаемым значением, сколько байтов было прочитано, иправильно обрабатывать вводы, содержащие нулевые байты.

    • Во-вторых, вы используете BZ2_bzCompress() для сжатия каждого буфера ввода, как если бы он был полным файлом .Когда вы подходите к концу буфера, вы завершаете цикл сжатия и повторно инициализируете bz_stream.Это определенно помешает распаковке и может объяснить, почему ваша программа (кажется) сжимает только первую строку своего ввода.Вы должны прочитать все содержимое файла (кусками подходящего размера) и передать все это до BZ2_bzCompress(... BZ_RUN) перед тем, как закончите.Должна быть одна последовательность вызовов BZ2_bzCompress(... BZ_FINISH) и, наконец, один вызов BZ2_bzCompressEnd() для всего файла, а не для каждой строки.

  4. Вы не выполняетеОбнаружение ошибок или обработка любых ваших вызовов в стандартные функции библиотеки или bzip.Вы обрабатываете ожидаемые успех-случай возвращаемые значения для некоторых из них, но вы также должны быть готовы к ошибкам.

  5. Есть некоторые дополнительные странности

    • у вас есть неиспользуемые переменные nbytes_in, nbytes_out, bzerror и b.
    • вы открываете входной файл как текстовый файлхотя то, имеет ли это какое-либо значение, зависит от платформы.
    • пара ftell() / fseek() не имеет никакого общего эффекта, кроме установки save_pos, которая не используется в противном случае.
    • хотя это не вредно, оно также не является полезным до memset() выходным буфером со всеми нулями в конце каждой строки (или изначально).
    • Учитывая, что вы Сжимая вход, странно (но опять же не вредно), что вы предоставляете в шесть раз больше выходного буфера, чем вы делаете входной буфер.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...