1

Тема: Відновлення jpg файлів з бінарного файлу

Треба відновити фото, що містяться у .raw копії флешки. Відомо, що там jpg файли. Тому я написав програму, що зчитує файл до буферу, а тоді з буфера повинна послідовно(відповідно до початку і кінця jpg файлу) записати n jpg файлів. При запуску створюється один jpg файл дуже великого розміру, до кінця виконання програми я не чекаю бо вже бачу, що щось не так. Підкажіть де помилка.

[code=C]
#include <stdio.h>
#include <stdlib.h>


int main(int argc, char* argv[])
{
    FILE *fileptr;
    unsigned char *buffer;
    long filelen;
    int jpgcount = 0;

    fileptr = fopen("card.raw", "r");  // Open the file in binary mode
    fseek(fileptr, 0, SEEK_END);          // Jump to the end of the file
    filelen = ftell(fileptr);             // Get the current byte offset in the file
    rewind(fileptr);                      // Jump back to the beginning of the file

    buffer = (unsigned char *)malloc((filelen+1)*sizeof(unsigned char)); // Enough memory for file + \0
    fread(buffer, filelen, 1, fileptr); // Read in the entire file
    fclose(fileptr); // Close the file
    //printf("%li\n", filelen);

    for(int i = 0; i < filelen; i++)
    {
        if(buffer[i] == 0xff && buffer[i+1] == 0xd8)
        {
            char filename[100];
            sprintf(filename, "%03d.jpg", jpgcount);
            FILE* outptr = fopen(filename, "wb");
            jpgcount++;
            do
            {
                fwrite(&buffer[i], 1, 1, outptr);
            }while((buffer[i] != 0xff && buffer[i+1] != 0xd9) || buffer[i] != '\0');
            fclose(outptr);
        }
    }
    free(buffer);
    return 0;
}[/code]

2

Re: Відновлення jpg файлів з бінарного файлу

                do
                  {
                    fwrite(&buffer[i], 1, 1, outptr);
                  }while((buffer[i] != 0xff && buffer[i+1] != 0xd9) || buffer[i] != '\0');

Цикл нескінчений, i не змінюється.

Подякували: Teg Miles, leofun012

3 Востаннє редагувалося Teg Miles (19.08.2018 15:49:47)

Re: Відновлення jpg файлів з бінарного файлу

koala написав:
                do
                  {
                    fwrite(&buffer[i], 1, 1, outptr);
                  }while((buffer[i] != 0xff && buffer[i+1] != 0xd9) || buffer[i] != '\0');

Цикл нескінчений, i не змінюється.

Чому? Він же наче повинен зупинятися, якщо досягає певних значень buffer(i).

Зрозумів, я ж лічильник для і не виставив у циклі:). Додав і++ після запису, тепер все працює як слід:)

Подякували: NaharD1

4 Востаннє редагувалося ReAl (19.08.2018 16:12:43)

Re: Відновлення jpg файлів з бінарного файлу

Vitaliy_Danmer написав:
...
    buffer = (unsigned char *)malloc((filelen+1)*sizeof(unsigned char)); // Enough memory for file + \0
    fread(buffer, filelen, 1, fileptr); // Read in the entire file
    fclose(fileptr); // Close the file
    //printf("%li\n", filelen);
    
    for(int i = 0; i < filelen; i++)
      {
        if(buffer[i] == 0xff && buffer[i+1] == 0xd8)
         {
...

Не впевнений, що це добра ідея — працювати з буфером побайтово. Файли починаються з початку сектора і хто його зна, чи не зустрінеться «заголовкова» комбінація всередині сектора — посекторна робота зменшує імовірність помилкового «розрізання» файла на два (і заголовків там же наче два можливих 4-байтових, перевірка обох на всі 4 байти ще зменшить імовірність збою). Та й набагато швидше буде перевіряти лише початок сектора.

Щодо зачитування всього файлу у пам'ять — можливо це просто питання смаку, але якщо потім з такими звичками почати відновлювати інформацію з образів хоча б 16-гігабайтних флешок, то це буде зайве навантаження на систему віртуальної пам'яті (а на 32-бітних системах просто не запрацює).
Тому краще б читати посекторно, а там хай ОС кешує дискові операції як їй зручно.

Подякували: Teg Miles1

5

Re: Відновлення jpg файлів з бінарного файлу

ReAl написав:

Не впевнений, що це добра ідея — працювати з буфером побайтово. Файли починаються з початку сектора і хто його зна, чи не зустрінеться «заголовкова» комбінація всередині сектора — посекторна робота зменшує імовірність помилкового «розрізання» файла на два (і заголовків там же наче два можливих 4-байтових, перевірка обох на всі 4 байти ще зменшить імовірність збою). Та й набагато швидше буде перевіряти лише початок сектора.

Щодо зачитування всього файлу у пам'ять — можливо це просто питання смаку, але якщо потім з такими звичками почати відновлювати інформацію з образів хоча б 16-гігабайтних флешок, то це буде зайве навантаження на систему віртуальної пам'яті (а на 32-бітних системах просто не запрацює).
Тому краще б читати посекторно, а там хай ОС кешує дискові операції як їй зручно.

Дійсно, у мене не всі фото вийшли правильно записаними. Потрібно відредагувати запис.
Щодо буферу, то я зробив це тому що завдання не вимагає обробки великих масивів даних. Треба обробити лише 20 Мб.

6

Re: Відновлення jpg файлів з бінарного файлу

Vitaliy_Danmer написав:

Щодо буферу, то я зробив це тому що завдання не вимагає обробки великих масивів даних. Треба обробити лише 20 Мб.

:)

Ну от, як використання функцій Get* з бібліотечки cs50, так це погано, а як робити рішення під конкретний розмір файлу завдання, так це добре

Але з посекторним зчитуванням логіка спрощується.

Поки не кінець вхідного файлу.
    Читаємо сектор у буфер.
    Дивимося його перші байти, чи це не заголовок.
    Якщо заголовок, то
        закриваємо попередній вихідний файл (якщо був), відкриваємо новий.
    Пишемо сектор у вихідний файл (тут він вже точно є).
Закриваємо (останній) вихідний файл (якщо був)
Подякували: Teg Miles1

7

Re: Відновлення jpg файлів з бінарного файлу

Не хоче записувати чомусь. Десь помилка, не бачу її.

[code=C]#include <stdio.h>
#include <stdlib.h>


int main(void)
{
    FILE *fileptr;
    int jpgcount = 0;

    fileptr = fopen("card.raw", "rb");
    if (fileptr == NULL)
    {
        printf("Could not open 'card.raw' file.\n");
        return 1;
    }
    unsigned char buffer[512];
    FILE *outptr = NULL;

    while(fread(buffer, 512, 1, fileptr) == 1)
    {
        if(buffer[0] == 0xff && buffer[1] == 0xd8)
        {
            if(outptr != NULL)
            {
                fclose(outptr);
            }
            char filename[10];
            sprintf(filename, "%03d.jpg", jpgcount);
            FILE* outptr = fopen(filename, "wb");
            jpgcount++;
        }
        if(outptr != NULL)
        {
            fwrite(&buffer, 512, 1, outptr);
        }
    }
    if(outptr != NULL)
    {
        fclose(outptr);
    }
    fclose(fileptr);
    return 0;
}[/code]

8 Востаннє редагувалося ReAl (20.08.2018 17:09:13)

Re: Відновлення jpg файлів з бінарного файлу

Vitaliy_Danmer написав:

Не хоче записувати чомусь. Десь помилка, не бачу її.

Тут приховується змінна, треба увімкнути і читати попередження компілятора, або навчитися бачити

int main(void)
{
    // ...
    FILE *outptr = NULL;  // оця змінна

    while(fread(buffer, 512, 1, fileptr) == 1)
    {
        if(buffer[0] == 0xff && buffer[1] == 0xd8)
        {
            // ...
            FILE* outptr = fopen(filename, "wb"); // отут прихована, змінено не її
            jpgcount++;
        }
        if(outptr != NULL) // а тут знову використано ту першу
        {
            fwrite(&buffer, 512, 1, outptr);
        }
    }
    // ...
}
Подякували: leofun01, Teg Miles2

9

Re: Відновлення jpg файлів з бінарного файлу

А де можна почитати як налаштувати ці попередження? Зараз я використовую clang 6.0, хоча і налаштування для gcc теж непогано буде знати. Загалом, що краще gcc чи clang?

10

Re: Відновлення jpg файлів з бінарного файлу

clang не користуюся
Для gcc, конкретно для таких ситуацій -Wshadow

Подякували: Teg Miles1