basic_ifstream<unsigned char> не читает файл до конца
От: Adriano  
Дата: 26.12.07 13:04
Оценка:
просто читаю файл:
template<class ValueT>
void simple_reading(const char* fileName)
{
    basic_ifstream<ValueT> in;
    in.open(fileName,ios::binary);
    if ( !in ){
        return;
    }

    basic_string<ValueT> buffer;
    buffer.resize(1024*1024*100);

    {
        size_t offset = 0;
        while( !in.eof() ){
            in.read(&buffer[0],static_cast<streamsize>( buffer.size() & 0xFFFFFFFF ) ); //правильно я делаю преобразование?
            offset += in.gcount();
            cout << "\roffset = " << offset;
        }
        cout << endl;
    }
    return;
}

int _tmain(int argc, _TCHAR* argv[])
{
    if ( argc < 2 ){
        return 1;
    }
    simple_reading<char>(argv[1]);
    simple_reading<unsigned char>(argv[1]);
    return 0;
}


Почему в случае с char файл считывается полностью, а в случае с unsigned char где-то после 7гб чтение прекращается, т.к. выставляется флаг eof?
размер файла ~12гб
Re: basic_ifstream<unsigned char> не читает файл до конца
От: codelord  
Дата: 26.12.07 13:45
Оценка:
Здравствуйте, Adriano, Вы писали:

A>просто читаю файл:

A>
A>template<class ValueT>
A>void simple_reading(const char* fileName)
A>{
A>    basic_ifstream<ValueT> in;
A>    in.open(fileName,ios::binary);
A>    if ( !in ){
A>        return;
A>    }

A>    basic_string<ValueT> buffer;
A>    buffer.resize(1024*1024*100);

A>    {
A>        size_t offset = 0;
A>        while( !in.eof() ){
A>            in.read(&buffer[0],static_cast<streamsize>( buffer.size() & 0xFFFFFFFF ) ); //правильно я делаю преобразование?
A>            offset += in.gcount();
A>            cout << "\roffset = " << offset;
A>        }
A>        cout << endl;
A>    }
A>    return;
A>}

A>int _tmain(int argc, _TCHAR* argv[])
A>{
A>    if ( argc < 2 ){
A>        return 1;
A>    }
A>    simple_reading<char>(argv[1]);
A>    simple_reading<unsigned char>(argv[1]);
A>    return 0;
A>}
A>


A>Почему в случае с char файл считывается полностью, а в случае с unsigned char где-то после 7гб чтение прекращается, т.к. выставляется флаг eof?

A>размер файла ~12гб
по моему по умолчанию char считается unsigned
поэтому вроде не должно быть разницы
Re[2]: basic_ifstream<unsigned char> не читает файл до конца
От: Adriano  
Дата: 26.12.07 14:13
Оценка:
C>по моему по умолчанию char считается unsigned
C>поэтому вроде не должно быть разницы

    {
        char x = 0xFF;//-1
        char y = 10;//10

        if ( x < y ) {
            cout << "x < y" << endl;
        }
    }

    {
        unsigned char x = 0xFF;//255
        unsigned char y = 10;//10

        if ( y < x ) {
            cout << "y < x" << endl;
        }
    }
    return 0;
Re: basic_ifstream<unsigned char> не читает файл до конца
От: quodum  
Дата: 26.12.07 14:21
Оценка: 1 (1)
Здравствуйте, Adriano, Вы писали:

A>Почему в случае с char файл считывается полностью, а в случае с unsigned char где-то после 7гб чтение прекращается, т.к. выставляется флаг eof?

A>размер файла ~12гб

Компилите ведь MSVC?

ИМХО, тут имеет место ошибка в реализации STL.

Файл iosfwd, STL от MSVC 7.1:
        // TEMPLATE STRUCT char_traits (FROM <string>)
template<class _Elem>
    struct char_traits
    {    // properties of a string or stream element
    typedef _Elem char_type;
    typedef _Elem int_type;

        .............

    static int_type __cdecl eof()
        {    // return end-of-file metacharacter
        return ((int_type)EOF);  // при _Elem == unsigned char, здесь будет '\xFF'!
        }


Выделенное выше, как я понимаю, неверно, так как (21.1.2 traits typedefs):

typedef INT_T int_type;

Requires: For a certain character container type char_type, a related container type INT_T shall be a type or class which can represent all of the valid characters converted from the corresponding char_type values, as well as an end-of-file value, eof()


Соответственно, на первом же байте с кодом FF чтение затыкается по "концу файла".

Почему работает для char? Потому что для char там специализация (как и требуется стандартом), в которой int_type это int.



As a side note:

A>    in.read(&buffer[0],static_cast<streamsize>( buffer.size() & 0xFFFFFFFF ) ); //правильно я делаю преобразование?

Преобразование преобразованием, но с точки зрения стандарта тут UB, потому что внутреннее представление строки не обязано быть массивом символов. Т.е. нужно понимать, что, теоретически, эта конструкция может не пережить переезда на очередную платформу/версию компилятора.
Re[2]: basic_ifstream<unsigned char> не читает файл до конца
От: Adriano  
Дата: 26.12.07 14:32
Оценка:
Здравствуйте, quodum, Вы писали:

Q>Здравствуйте, Adriano, Вы писали:


A>>Почему в случае с char файл считывается полностью, а в случае с unsigned char где-то после 7гб чтение прекращается, т.к. выставляется флаг eof?

A>>размер файла ~12гб

Q>Компилите ведь MSVC?


Q>ИМХО, тут имеет место ошибка в реализации STL.


Q>Файл iosfwd, STL от MSVC 7.1:

Q>
Q>        // TEMPLATE STRUCT char_traits (FROM <string>)
Q>template<class _Elem>
Q>    struct char_traits
Q>    {    // properties of a string or stream element
Q>    typedef _Elem char_type;
Q>    typedef _Elem int_type;

Q>        .............

Q>    static int_type __cdecl eof()
Q>        {    // return end-of-file metacharacter
Q>        return ((int_type)EOF);  // при _Elem == unsigned char, здесь будет '\xFF'!
Q>        }


Q>


Q>Выделенное выше, как я понимаю, неверно, так как (21.1.2 traits typedefs):

Q>

Q>typedef INT_T int_type;

Q>Requires: For a certain character container type char_type, a related container type INT_T shall be a type or class which can represent all of the valid characters converted from the corresponding char_type values, as well as an end-of-file value, eof()


Q>Соответственно, на первом же байте с кодом FF чтение затыкается по "концу файла".


Q>Почему работает для char? Потому что для char там специализация (как и требуется стандартом), в которой int_type это int.


Как с этим бороться? писать свой traits?

Q>As a side note:


Q>
A>>    in.read(&buffer[0],static_cast<streamsize>( buffer.size() & 0xFFFFFFFF ) ); //правильно я делаю преобразование?
Q>

Q>Преобразование преобразованием, но с точки зрения стандарта тут UB, потому что внутреннее представление строки не обязано быть массивом символов. Т.е. нужно понимать, что, теоретически, эта конструкция может не пережить переезда на очередную платформу/версию компилятора.

vector представляется как массив, это входит в стандарт?
Re[2]: basic_ifstream<unsigned char> не читает файл до конца
От: Adriano  
Дата: 26.12.07 14:52
Оценка:
Q>Почему работает для char? Потому что для char там специализация (как и требуется стандартом), в которой int_type это int.

как сделать специализацию для unsigned char? я новичек в этом деле
Re[3]: basic_ifstream<unsigned char> не читает файл до конца
От: quodum  
Дата: 26.12.07 15:11
Оценка:
Здравствуйте, Adriano, Вы писали:

A>Как с этим бороться? писать свой traits?


Наверно да. То есть, добавлять свою специализацию для unsigned char в пространство имен std, хотя это вроде бы не вполне корректно, так как это разрешается делать только для пользовательских типов (если я ничего не путаю), коим unsigned char не является.

Однако, действительно ли это нужно? Откуда вообще взялась необходимость работать с потоками из unsigned char?


A>vector представляется как массив, это входит в стандарт?

Касательно вектора -- входит. Именно вектор рекомендуют использовать в качестве "переходника" при работе с внешними API, требующими плоских строковых буферов.
Re[3]: basic_ifstream<unsigned char> не читает файл до конца
От: quodum  
Дата: 26.12.07 15:18
Оценка:
Здравствуйте, Adriano, Вы писали:

A>как сделать специализацию для unsigned char? я новичек в этом деле


Примерно так:

#include <iosfwd> // или где ваша STL определяет char_traits

namespace std
{
    // а сюда копируете специализацию char_traits<char> из stl,
    // меняете на char_traits<unsigned char>
    // и правите внутренности по смыслу
}


Но, действительно ли это необходимо? Я бы постарался обойтись без потоков на unsigned char (тем более, что до сих пор не могу представить, зачем они понадобились )
Re[4]: basic_ifstream<unsigned char> не читает файл до конца
От: Adriano  
Дата: 26.12.07 15:22
Оценка:
Здравствуйте, quodum, Вы писали:

Q>Здравствуйте, Adriano, Вы писали:


A>>Как с этим бороться? писать свой traits?


Q>Наверно да. То есть, добавлять свою специализацию для unsigned char в пространство имен std, хотя это вроде бы не вполне корректно, так как это разрешается делать только для пользовательских типов (если я ничего не путаю), коим unsigned char не является.


Q>Однако, действительно ли это нужно? Откуда вообще взялась необходимость работать с потоками из unsigned char?


мне нужно только читать и писать блоки(без форматирования) + кроссплатформенность. Похоже что проще составить свою оболочку с методами read write.

Если я буду использовать fread, fwrite при чтении блока размером 100мб, данные считаются прямиком в мой буффер или сначала во внутренний буффер FILE, а потом в мой?
Re[5]: basic_ifstream<unsigned char> не читает файл до конца
От: quodum  
Дата: 26.12.07 15:48
Оценка:
Здравствуйте, Adriano, Вы писали:

A>мне нужно только читать и писать блоки(без форматирования) + кроссплатформенность. Похоже что проще составить свою оболочку с методами read write.


Но что мешает использовать обычный std::ifstream?

A>Если я буду использовать fread, fwrite при чтении блока размером 100мб, данные считаются прямиком в мой буффер или сначала во внутренний буффер FILE, а потом в мой?


Это надо смотреть в конкретной реализации стандартной библиотеки. Исходники обычно доступны.

Но я бы сделал для начала как проще. А уже потом, если результаты замера производительности окажутся неудовлетворительными, смотрел на реализацию функции чтения. Скорее всего, лишнее копирование памяти (если оно и есть) потеряется на фоне чтения с диска.
Re[4]: basic_ifstream<unsigned char> не читает файл до конца
От: Adriano  
Дата: 28.12.07 14:03
Оценка:
Здравствуйте, quodum, Вы писали:

Q>Здравствуйте, Adriano, Вы писали:


A>>как сделать специализацию для unsigned char? я новичек в этом деле


Q>Примерно так:


Q>
Q>#include <iosfwd> // или где ваша STL определяет char_traits

Q>namespace std
Q>{
Q>    // а сюда копируете специализацию char_traits<char> из stl,
Q>    // меняете на char_traits<unsigned char>
Q>    // и правите внутренности по смыслу
Q>}
Q>


Q>Но, действительно ли это необходимо? Я бы постарался обойтись без потоков на unsigned char (тем более, что до сих пор не могу представить, зачем они понадобились )


все началось с string.
Сравниваю две строки(string, т.е. basic_string<char>). Заглянув в исходники basic_string — выяснил, что сравнение выполняется с помощью функции memcmp(название точно не помню, но это не важно), важно что она сравнивает как unsigned char т.е. без знака 'f' < 'ю', что уже не совсем правильно, ведь я работаю с char. Когда я формирую интервал boost::iterator_range<string::iterator> и выполняю сравнение двух интервалов, то сравнение выполняется при помощи lexicographical_compare и получаю 'ю' < 'f'. В итоге критерий сравнения меняется откуда вытекают разные сюрпризы при сортировке. Я оформил код в виде шаблонов и работаю c unsigned char, а это повлекло переход к basic_ifstream<CharT>...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.