2009-03-02 8 views
8

Я хочу читать беззнаковые байты из двоичного файла. Итак, я написал следующий код.C++ чтение unsigned char из потока файлов

#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 байтов, как показано подсчитанной переменной.

Кажется, в Интернете есть ссылки, в которых говорится, что мне нужно установить локаль, чтобы выполнить эту работу. Как это сделать мне точно не ясно.

Тот же самый код работает, используя тип данных «обугленный» вместо «неподписанного символа»

выше кода, используя символ без знака, кажется, работает на Windows, но терпит неудачу работает в CoLinux Fedora 2.6.22.18.

Что мне нужно сделать, чтобы заставить его работать в Linux?

+0

Не ответ на этот вопрос, но связаны между собой.Помните, что определение строкового класса в C++ - это 'typedef basic_string string;', поэтому вы всегда можете сделать строковый класс unsigned char a la 'typedef basic_string bytestring;'. –

+0

true, но я хочу прочитать файл BINARY – David

+0

.read() и .write() могут использоваться для двоичного/текстового потока, операторы потока << and >> предназначены только для текстовых файлов. Все данные на компьютере в конечном счете являются двоичными, это то, как вы его интерпретируете. – sfossen

ответ

15

C++ требует реализаций только обеспечить явные специализации для двух версий черты характера:

std::char_traits<char> 
std::char_traits<wchar_t> 

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

Если экземпляр потока, как

std::basic_ifstream<unsigned char> 

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

error: specialization std::char_traits could not be instantiated.

я хотел бы использовать вместо ifstream (который является basic_ifstream<char>), а затем пойти и прочитать в vector<char>. При интерпретации данных в векторе вы можете преобразовать их в unsigned char.

+3

Я не получил ошибку компилятора, никаких указаний в документации, ничего, кроме молчаливого сбоя и потерянного дня. Спасибо, Бьярне Страуструп и Деннис Ритчи. – user1358

13

Не используйте 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

+0

Это чтение подписанных символов. Я знаю, что это работает. Я специально хочу читать неподписанные символы – David

+0

, просто измените char [] на unsigned char []. – sfossen

+0

и добавьте литье: P – sfossen

0

Гораздо более простой способ:

#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; 
} 
+0

Это очень неэффективно. Попробуйте запустить тесты с 1GB-файлами, накладные расходы вызовут большую разницу. – sfossen

+0

Почему это работает, но вызов читать не удается? – David

+0

Поскольку файл является подписанным символом char !!!! Я должен был это видеть. – David

 Смежные вопросы

  • Нет связанных вопросов^_^