С++ чтение беззнакового символа из файлового потока
Вопрос
Я хочу прочитать беззнаковые байты из двоичного файла.Поэтому я написал следующий код.
#include <iostream>
#include <fstream>
#include <vector>
#include <istream>
std::string filename("file");
size_t bytesAvailable = 128;
size_t toRead = 128;
std::basic_ifstream<unsigned char> inf(filename.c_str(), std::ios_base::in | std::ios_base::binary) ;
if (inF.good())
{
std::vector<unsigned char> mDataBuffer;
mDataBuffer.resize(bytesAvailable) ;
inF.read(&mDataBuffer[0], toRead) ;
size_t counted = inF.gcount() ;
}
Это приводит к чтению всегда 0 байтов, как показывает подсчитанная переменная.
Кажется, в Интернете есть ссылки, в которых говорится, что мне нужно установить языковой стандарт, чтобы это работало.Как именно это сделать, мне не ясно.
Тот же код работает с использованием типа данных «char» вместо «unsigned char».
Приведенный выше код с использованием unsigned char, похоже, работает в Windows, но не работает в colinux Fedora 2.6.22.18.
Что мне нужно сделать, чтобы заставить его работать в Linux?
Решение
C++ требует реализации только для предоставления явной специализации для двух версий черт характера:
std::char_traits<char>
std::char_traits<wchar_t>
Потоки и строки используют эти свойства для определения множества вещей, таких как значение EOF, сравнение диапазона символов, расширение символа до целого числа и тому подобное.
Если вы создаете экземпляр потока, например
std::basic_ifstream<unsigned char>
Вы должны убедиться, что существует соответствующая специализация черт характера, которую поток может использовать, и что эта специализация действительно делает полезные вещи.Кроме того, потоки используют фасеты для фактического форматирования и чтения чисел.Точно так же вам придется указать их специализации вручную.Стандарт даже не требует, чтобы реализация имела полное определение первичного шаблона.Таким образом, вы также можете получить ошибку компиляции:
ошибка:Не удалось создать экземпляр специализации std::char_traits.
я хотел бы использовать ifstream
вместо этого (что является basic_ifstream<char>
), а затем пойти и прочитать в vector<char>
.При интерпретации данных в векторе вы все равно можете преобразовать их в unsigned char
позже.
Другие советы
Не используйте Basic_ifstream, поскольку он требует специализации.
Использование статического буфера:
linux ~ $ cat test_read.cpp
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main( void )
{
string filename("file");
size_t bytesAvailable = 128;
ifstream inf( filename.c_str() );
if( inf )
{
unsigned char mDataBuffer[ bytesAvailable ];
inf.read( (char*)( &mDataBuffer[0] ), bytesAvailable ) ;
size_t counted = inf.gcount();
cout << counted << endl;
}
return 0;
}
linux ~ $ g++ test_read.cpp
linux ~ $ echo "123456" > file
linux ~ $ ./a.out
7
используя вектор:
linux ~ $ cat test_read.cpp
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main( void )
{
string filename("file");
size_t bytesAvailable = 128;
size_t toRead = 128;
ifstream inf( filename.c_str() );
if( inf )
{
vector<unsigned char> mDataBuffer;
mDataBuffer.resize( bytesAvailable ) ;
inf.read( (char*)( &mDataBuffer[0]), toRead ) ;
size_t counted = inf.gcount();
cout << counted << " size=" << mDataBuffer.size() << endl;
mDataBuffer.resize( counted ) ;
cout << counted << " size=" << mDataBuffer.size() << endl;
}
return 0;
}
linux ~ $ g++ test_read.cpp -Wall -o test_read
linux ~ $ ./test_read
7 size=128
7 size=7
использование резерва вместо изменения размера при первом вызове:
linux ~ $ cat test_read.cpp
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main( void )
{
string filename("file");
size_t bytesAvailable = 128;
size_t toRead = 128;
ifstream inf( filename.c_str() );
if( inf )
{
vector<unsigned char> mDataBuffer;
mDataBuffer.reserve( bytesAvailable ) ;
inf.read( (char*)( &mDataBuffer[0]), toRead ) ;
size_t counted = inf.gcount();
cout << counted << " size=" << mDataBuffer.size() << endl;
mDataBuffer.resize( counted ) ;
cout << counted << " size=" << mDataBuffer.size() << endl;
}
return 0;
}
linux ~ $ g++ test_read.cpp -Wall -o test_read
linux ~ $ ./test_read
7 size=0
7 size=7
Как видите, без вызова .resize( counted ) размер вектора будет неправильным.Пожалуйста, имейте это в виду.обычно используется приведение, см. cppReference
Гораздо более простой способ:
#include <fstream>
#include <vector>
using namespace std;
int main()
{
vector<unsigned char> bytes;
ifstream file1("main1.cpp", ios_base::in | ios_base::binary);
unsigned char ch = file1.get();
while (file1.good())
{
bytes.push_back(ch);
ch = file1.get();
}
size_t size = bytes.size();
return 0;
}