C не читает весь файл BMP - fopen

Итак, я пытаюсь прочитать файл .bmp на C. Позже я собираюсь зашифровать файл с помощью библиотек openssl, но это только справочная информация.

Мне нужно открыть файл в двоичном режиме (очевидно), но по какой-то причине, когда я пытаюсь открыть файл, он читает только 4 байта. Когда я пытаюсь вывести именно этот файл, который я только что открыл (для проверки на наличие ошибок), он выводит следующее: 88 24 AD FB.

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

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>

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

int main(){

    char * fileName="pic_original.bmp";

    //read the file from given filename in binary mode
    printf("Start to read the .bmp file \n");

    FILE *image;
    image = fopen(fileName,"rb");

    //print the size of the image (4 bytes every damn time)
    printf("Size of image: %d\n",sizeof(image));

    //output the exact file that was read (error testing)
    FILE *test;
    test = fopen("./test.bin", "w");
    fwrite(image, sizeof(image), 1, test);

    fclose(test);
    fclose(image);


    return 1;
}

Это изображение (загружено как png по какой-то причине)

изображение

Не совсем уверен, где я ошибаюсь, но я не очень опытен в C.

Привет, Лиам

РЕДАКТИРОВАТЬ 1:

//allocate memory for the header and image
char *headerBuf = (char *)malloc(54);
char *imageBuf = (char *)malloc(sizeof(image)-54); //this line is wrong - thanks to user EOF

//allocate memory for the final ciphertext
char *imagecipherCBC = (char *)malloc(sizeof(image)); //wrong also

//read first 54 bytes (header)
rewind(image);
fread(headerBuf,54,1,image);

//read the bitmap image until the end of the file
fread(imageBuf,sizeof(image),1,image); //also wrong

person Liam G    schedule 28.03.2019    source источник
comment
sizeof(image) равно sizeof (FILE*), а sizeof(FILE*) не зависит от размера файла.   -  person EOF    schedule 29.03.2019
comment
Хм, ладно, а как мне вывести именно тот файл, который я прочитал? Я даже правильно читаю в файле?   -  person Liam G    schedule 29.03.2019
comment
Это зависит от. На какой платформе вы находитесь? Вы должны использовать исключительно портативную версию c или можете использовать платформу? Если вы используете POSIX, fstatat() является разумным вариантом, при условии, что вы читаете файлы, а не общие (недоступные для поиска) потоки.   -  person EOF    schedule 29.03.2019
comment
В растровом файле сначала вы можете прочитать заголовок в struct, который сообщит вам размер изображения. Затем вы можете выделить память для растрового изображения и прочитать его.   -  person Weather Vane    schedule 29.03.2019
comment
Или, если вы просто копируете файл: size_t bytes; while((bytes = fread(buffer, 1, sizeof buffer, image)) != 0) { fwrite(buffer, 1, bytes, test); }   -  person Weather Vane    schedule 29.03.2019
comment
Я использую 32-битную виртуальную машину Linux Ubuntu. Я не совсем уверен, что такое Portable c. Моя главная цель — просто прочитать файл в двоичном режиме, чтобы потом можно было его зашифровать. Я правильно открываю файл? Я обновил свой вопрос, указав, как я читаю изображение в буферах.   -  person Liam G    schedule 29.03.2019
comment
Да - вы правильно открываете файл, но не читаете файл вообще. Вам нужно иметь fread(), чтобы получить фактические данные в файле. FILE *, которое вы возвращаете из fopen, является просто непрозрачным дескриптором, который вы используете для других вызовов.   -  person Carl Norum    schedule 29.03.2019


Ответы (2)


Ну, размер изображения, конечно, 4 байта, что является указателем файла на 32-битной машине.

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

static void read_from_image(char *imageBuf, int fileLength)
{
    const char * outFileName="c:/DEV/temp/test.bin";
    char headerBuf[54];
    char *imagecipherCBC;

    FILE *test;
    test = fopen(outFileName, "wb");

    //allocate memory for the final ciphertext
    imagecipherCBC = (char *)malloc(fileLength *sizeof(char));

    //read first 54 bytes (header)
    //fread(headerBuf,54,1,image);
    memcpy(headerBuf, imageBuf, 54 * sizeof(char));

    //read the bitmap image until the end of the file
    //fread(imageBuf,sizeof(image),1,image); //also wrong

    fwrite(imageBuf, fileLength * sizeof(char), 1, test);
    fflush(test);
    fclose(test);

    free(imagecipherCBC),imagecipherCBC = NULL;
    free(imageBuf),imageBuf = NULL;

    return;
}

Вы можете иметь длину файла и буфер изображения в основной функции.

    int main(int argc, char *argv[])
{
    const char * fileName="c:/DEV/temp/pic_original.bmp";

    int fileLength = 0;

    FILE *image;
    char *imageBuffer;

    imageBuffer = NULL;
    image = fopen(fileName,"rb");

    printf("read the file from given filename in binary mode \n");
    printf("Start to read the .bmp file \n");

    //try to get a file length;
    fseek(image, 0, SEEK_END);
    fileLength = ftell(image);
    fseek(image, 0, SEEK_SET);
    rewind(image);

    imageBuffer = (char*)malloc(fileLength * sizeof(char));

    //print the size of the image (4 bytes every damn time)
    printf("read the file from given filename in binary mode \n");
    printf("Size of image file pointer: %d\n",sizeof(image));
    printf("Size of image: %d\n",fileLength);

    //output the exact file that was read (error testing)
    fread(imageBuffer,sizeof(char),fileLength*sizeof(char), image);

    fclose(image);

    read_from_image(imageBuffer, fileLength);

    return 0;
}

удачи

person tommybee    schedule 29.03.2019
comment
Мне потребовалось некоторое время, чтобы понять это, потому что я не знаю C, но это объяснение идеально! Спасибо друг! - person Liam G; 02.04.2019

Если ваша цель — зашифровать файл, прочитайте весь файл в буфер, зашифруйте его и сохраните как двоичный файл. Размер файла можно узнать, переместив указатель файла в конец. Пример:

int main()
{
    FILE *fin;
    fin = fopen("pic_original.bmp", "rb");
    fseek(fin, 0, SEEK_END);
    int filesize = ftell(fin);
    rewind(fin);

    char *buf = malloc(filesize);
    fread(buf, 1, filesize, fin);
    fclose(fin);

    //encrypt the buffer...

    FILE *fout = fopen("output.bmp", "wb");
    fwrite(buf, 1, filesize, fout);
    fclose(fout);

    return 0;
}

Это будет работать с любым файлом. В OpenSSL уже есть функции для прямого шифрования файлов.

Если по какой-то причине вы хотите оставить заголовок прежним и изменить только следующие биты, прочитайте заголовок отдельно:

int main()
{
    FILE *fin = fopen("input.bmp", "rb");
    if(!fin) { printf("cannot open input\n"); return 0; }

    FILE *fout = fopen("output.bmp", "wb");
    if(!fout) { printf("cannot open output\n"); return 0; }

    fseek(fin, 0, SEEK_END);
    int filesize = ftell(fin);
    if(filesize <= 54)
    {
        printf("wrong filesize\n");
        return 0;
    }
    rewind(fin);

    char *header = malloc(54);
    char *buf = malloc(filesize - 54);
    //encrypt buf...
    fread(header, 1, 54, fin);
    fread(buf, 1, filesize - 54, fin);
    fclose(fin);

    fwrite(header, 1, 54, fout);
    fwrite(buf, 1, filesize - 54, fout);
    fclose(fout);

    free(header);
    free(buf);
    return 0;
}

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

Обратите внимание, что 8-битные, 4-битные и монохромные растровые изображения имеют палитру, которая идет после 54-байтового заголовка, затем идут биты изображения.

person Barmak Shemirani    schedule 29.03.2019
comment
Будет ли этот код работать для базовых монохромных файлов BMP? - person R1S8K; 06.02.2021