C ++ читает неподписанный символ из файлового потока - PullRequest
11 голосов
/ 03 марта 2009

Я хочу прочитать неподписанные байты из двоичного файла. Поэтому я написал следующий код.

#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?

Ответы [ 3 ]

19 голосов
/ 03 марта 2009

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 позже.

14 голосов
/ 03 марта 2009

Не используйте 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 (считается) размер вектора будет неправильным Пожалуйста, имейте это в виду. это обычное использование приведение см

0 голосов
/ 03 марта 2009

Намного проще:

#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;
}
...