Название: [РЕШЕНО] Почему образуются "лишние" байты при чтении из stringstream? Отправлено: schmidt от Январь 08, 2017, 16:53 Добрый день,
Понадобилось реализовать блочное шифрование. Чтобы не заботиться о том, поступают ли данные из строки или файла, решил передавать в функцию шифрования потоки istream, ostream. Столкнулся с тем, что в конце расшифрованной строки образуется какой-то мусор. Чтобы проверить себя, создал отдельный проект, который только пишет и читает текст в/из stringstream и обнаружил ту же проблему. Код
Вывод: Цитировать ss_in.str().length() = 13 16 bytes written into ss_intermediate ss_intermediate.str().length() = 16 'Hello, World! ' 24 bytes written into ss_out ss_out.str().length() = 24 'Hello, World! ' Непонятно, откуда берутся лишние 8 байт? ??? Название: Re: Почему образуются "лишние" байты при чтении из stringstream? Отправлено: Swa от Январь 08, 2017, 20:57 Может быть поэтому:
Цитировать std::istream::read istream& read (char* s, streamsize n); If the input sequence runs out of characters to extract (i.e., the end-of-file is reached) before n characters have been successfully read, the array pointed to by s contains all the characters read until that point, and both the eofbit and failbit flags are set for the stream. Название: Re: Почему образуются "лишние" байты при чтении из stringstream? Отправлено: schmidt от Январь 09, 2017, 06:19 Может быть поэтому: Цитировать std::istream::read istream& read (char* s, streamsize n); If the input sequence runs out of characters to extract (i.e., the end-of-file is reached) before n characters have been successfully read, the array pointed to by s contains all the characters read until that point, and both the eofbit and failbit flags are set for the stream. Здесь говорится о том, что если символов в потоке меньше, чем запрошенное n, то в массив, на который указывает s, запишутся только те байты, что есть в потоке, а для самого объекта istream будут установлены флаги eofbit и failbit. Меня же интересует природа нулевых байтов, которые появляются в хвосте потока, словно были туда записаны. Название: Re: Почему образуются "лишние" байты при чтении из stringstream? Отправлено: Old от Январь 09, 2017, 06:57 Так а что вам не понятно? :)
У вас в потоке 16 байт. Вы вычитали 8 байт - это good, вы вычитали еще 8 байт - это тоже good, в потоке они были. Дальше вы читаете еще 8 байт, а это уже не good, их в потоке нет. Все работает ровно так как вы написали. Название: Re: Почему образуются "лишние" байты при чтении из stringstream? Отправлено: schmidt от Январь 09, 2017, 08:27 Ох, во всем хочется видеть интуитивно понятные вещи. Но иногда все же приходится отбросить все предположения и рыться в документации до последней запятой.
Меня возмущает тот факт, что условие in.good() не останавливает меня до того, как я попытаюсь прочитать "пустой" поток. Как оказалось, в действительности дело обстоит так: 1. Я пишу в поток N байтов; 2. Я читаю из потока ровно N байтов; 3. Однако, чтобы isream понял, что байты закончились, его нужно пнуть еще на 1 байт вперед. чтобы он наткнулся на EOF. И только после пинка он установит eofbit. И методу good() на полном серьезе следовало бы называться testBitGood() в соответствии с его назначением, а вовсе не размытым "все_хорошо" :-\ Таким образом условием while нужно либо заглядывать (peek) в следующий байт, чтобы он не был EOF, либо смотреть число реально прочитанных байтов, вызывая gcount() и выходить из цикла если прочитано 0. Вот и пример такого интуитивно непонятного, но рабочего чтения из потока :) Код
Название: Re: Почему образуются "лишние" байты при чтении из stringstream? Отправлено: Old от Январь 09, 2017, 09:19 Наверно проще проверять флаг состояния сразу после чтения и сразу завершать цикл если чтение не удалось.
Название: Re: Почему образуются "лишние" байты при чтении из stringstream? Отправлено: schmidt от Январь 09, 2017, 09:52 Тогда мы рискуем "потерять" последние байты, которые не образуют целый блок :)
Цитировать http://www.cplusplus.com/reference/istream/istream/read/ (http://www.cplusplus.com/reference/istream/istream/read/) If the input sequence runs out of characters to extract (i.e., the end-of-file is reached) before n characters have been successfully read, the array pointed to by s contains all the characters read until that point, and both the eofbit and failbit flags are set for the stream. Например, мы читаем строку исходного текста перед шифрованием, длина которой может и не быть кратной размеру блока. Тогда в "хвосте" окажется несколько байт, пусть 2, а read мы просим постоянно читать 8. И в один прекрасный (последний) момент read читая следующие 8 байт прочитает 2 и натолкнется на EOF, после чего установит eofbit и failbit, но байты из "хвоста" все равно будут прочитаны. Название: Re: Почему образуются "лишние" байты при чтении из stringstream? Отправлено: Old от Январь 09, 2017, 09:58 Тогда мы рискуем "потерять" последние байты, которые не образуют целый блок :) Если блоки могут быть не полные, то не очень правильно читать блоками, без проверки "А сколько там осталось?"Всегда можно определить размер остатка и вычитать именно его. Название: Re: Почему образуются "лишние" байты при чтении из stringstream? Отправлено: Igors от Январь 09, 2017, 10:33 Таким образом условием while нужно либо заглядывать (peek) в следующий байт, чтобы он не был EOF, либо смотреть число реально прочитанных байтов, вызывая gcount() и выходить из цикла если прочитано 0. Насколько помню, так всегда и было (не очень удобно как и многое в std). Обычно проверяют good() сразу после read(). При форматированном I/O этой проблемы нет, можно просто while (!ss.eof()). Тогда мы рискуем "потерять" последние байты, которые не образуют целый блок :) А что это за байты такие? Просто и хорошо испускать exception если хоть что-то "не гуд", т.е. приложение не должно нарываться на конец файла. Для чтения данных переменной длины нужно предвычислить их число/размер используя длину файла/тега. А просто "прочитать все что есть в файле" может загнать приложение "куда Макар телят не гонял" Название: Re: Почему образуются "лишние" байты при чтении из stringstream? Отправлено: schmidt от Январь 09, 2017, 11:45 Так я нарочно читаю блоками, чтобы процедуру шифрования кормить 64-битными блоками :) Меня здесь интересует только чтобы были прочитаны все данные и при необходимости последние байты из "хвоста" были дополнены нулями до размера блока. Поэтому я заранее определяю буфер по размеру блока, который перед каждым чтением очищаю.
Цитировать А что это за байты такие? Просто и хорошо испускать exception если хоть что-то "не гуд", т.е. приложение не должно нарываться на конец файла. Для чтения данных переменной длины нужно предвычислить их число/размер используя длину файла/тега. А просто "прочитать все что есть в файле" может загнать приложение "куда Макар телят не гонял" Я всё же придерживаюсь идеи оставлять функции максимально простыми, чтобы их назначение было ясным и понятным, поведение - предсказуемым, а сами функции было легко документировать. Лучше строить приложения из вложенных вызовов простейших функций, чем писать одну супер-функцию, скрывающую с десяток режимов работы на основе десятка параметров. Меня, например, в дрожь бросает от воспоминаний о каком-нибудь Windows API. |