C++ fwrite() из строки, повреждается картинка или текстовый документ

Собираюсь передавать картинку по UDP, для этого очень нужно превратить считанные данные в строку. Превращаю. Но обратно превратить строку в картинку уже не могу, картинка получается битая. Хотя никаких лишних данных я в нее не записываю (CRC-16 и размер каждого фрагмента сходится). Вот псевдо пример, где воспроизводится эта ошибка (без udp):

FILE* in_image_stream = fopen("C:\\Users\\Codeine\\source\\repos\\mt_2_lab_3\\Debug\\myfile.jpg", "rb");
size_t bytes_read = 0;
char buf[250];

while ((bytes_read = fread(&buf, sizeof(char), 250, in_image_stream)) > 0)
{
    FILE* out_image_stream = fopen("C:\\Users\\Codeine\\source\\repos\\mt_2_lab_3\\Debug\\result.jpg", "ab+");
    string string_buf(buf);

    fwrite(string_buf.c_str(), 250, sizeof(char), out_image_stream); // 10 строка
    fclose(out_image_stream);
}
fclose(in_image_stream);

Если поменять 10 строку на:

fwrite(&buf, 250, sizeof(char), out_image_stream);

То все хорошо, но с клиентом так не получится, он получит данные в виде const char[]. Грубо говоря мне нужно buf[250] превратить в строку, а потом записать её в файл. И чтобы при этом изображение не повредилось.

С текстовым файлом получается примерно такая проблема: Исходный выглядит так:

абвг
абвг
абвг
абвг
абвг
абвг
абвг
абвг
абвг

1544
9999

А при считывании->превращении в строку->превращении в const char[]->записи в это:

абвг
абвг
абвг
абвг
абвг
абвг
абвг
абвг
абвг

1544
9999ММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММ

Ответы (2 шт):

Автор решения: Джонни Кэтсвилл

Вы считываете бинарный файл в буфер buf:

bytes_read = fread(&buf, sizeof(char), 250, in_image_stream)

Среди считанных байтов вполне может оказаться и нулевой байт, который при преобразовании буфера buf в std::string:

string string_buf(buf);

будет интерпретироваться как конец строки. С другой стороны в buf может вообще не оказаться нулевых байтов, поэтому при конструировании строки произойдёт выход за пределы массива buf: конструктор string будет читать память до тех пор, пока не наткнётся на нулевой символ.

Передавайте размер буфера buf в конструктор string явно:

string string_buf(buf, bytes_read);

И десятую строку лучше переписать так:

fwrite(string_buf.c_str(), sizeof(char), string_buf.size(), out_image_stream); // 10 строка

И ещё при считывании

bytes_read = fread(&buf, sizeof(char), 250, in_image_stream)

Вы передаёте адрес всего массива, а нужно передавать адрес первого элемента массива

bytes_read = fread(&buf[0], sizeof(char), 250, in_image_stream) //так
bytes_read = fread(buf, sizeof(char), 250, in_image_stream)    //или так
→ Ссылка
Автор решения: mik.ov

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

Далее, что бы исправить вашу ситуацию, записывайте в файл/сокет, только ту длину, которая была прочитана из файла, т.е. ваша переменная bytes_read.

FILE *in_image_stream =
    fopen("C:\\Users\\Codeine\\source\\repos\\mt_2_lab_3\\Debug\\myfile.jpg", "rb");

size_t bytes_read = 0;
char buf[250] = { 0 };

while ((bytes_read = fread(buf, sizeof(char), 250, in_image_stream)) > 0)
{
    FILE* out_image_stream
        = fopen("C:\\Users\\Codeine\\source\\repos\\mt_2_lab_3\\Debug\\result.jpg", "ab+");

    // Делайте то что хотите, но не записывайте данные в файл отсюда!!!
    std::string string_buf(buf);

    // Записываем столько, сколько прочли, не больше!
    fwrite(buf, bytes_read, sizeof(char), out_image_stream);
    fclose(out_image_stream);
}
fclose(in_image_stream);

Offtop: А так же, не понятно зачем вы каждый раз в цикле открываете и закрываете файл.

→ Ссылка