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) //или так
Первое что мне бросилось в глаза, так это то что вы пытаетесь записать все 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: А так же, не понятно зачем вы каждый раз в цикле открываете и закрываете файл.