fstream и unicode
От: pick_catcher  
Дата: 31.07.09 19:51
Оценка:
Господа, помогите, я столкнулся с проблемой.

Надо в файл скинуть бинарные данные.
Имя файла в широких символах.

#include <fstream>
#include <tchar.h>

...

std::wfstream wfile(_T("мой файл"), std::ios_base::out | std::ios_base::binary);
if(wfile.is_open())
{

std::string strEng = "bingo";
wfile.write(reinterpret_cast<const wchar_t*>(strEng.c_str()), strEng.length());
wfile.flush();
}
wfile.close();

Естественно, ничего и не записывает из-за неправильного приведения типов.
Размер нужно указывать, как количество двухбайтных символов wchar_t, а надо
записать допустим 5 байт (строка char символов).
Что делать? (желательно, без локалей)
Re: fstream и unicode
От: Sharpeye Россия  
Дата: 03.08.09 10:42
Оценка:
Здравствуйте, pick_catcher, Вы писали:

_>Господа, помогите, я столкнулся с проблемой.


_>Надо в файл скинуть бинарные данные.

_>Имя файла в широких символах.

_>#include <fstream>

_>#include <tchar.h>

_>...


_>std::wfstream wfile(_T("мой файл"), std::ios_base::out | std::ios_base::binary);

_>if(wfile.is_open())
_>{

_> std::string strEng = "bingo";

_> wfile.write(reinterpret_cast<const wchar_t*>(strEng.c_str()), strEng.length());
_> wfile.flush();
_>}
_>wfile.close();

_>Естественно, ничего и не записывает из-за неправильного приведения типов.

_>Размер нужно указывать, как количество двухбайтных символов wchar_t, а надо
_>записать допустим 5 байт (строка char символов).
_>Что делать? (желательно, без локалей)

Если для Visual Studio, то там есть перегрузка конструктора fstream для широких символов

    std::fstream file( L"мой файл", std::ios_base::out | std::ios_base::binary );

    if( file )
    {
        std::string str = "bingo";
        file.write( str.c_str(), str.length() );
        file.flush();
    }
Re: fstream и unicode
От: Аноним  
Дата: 03.08.09 10:46
Оценка: +1
Здравствуйте, pick_catcher, Вы писали:


_> std::string strEng = "bingo";


Тут вроде нужно не std::string, а std::wstring. И L"bingo".
Re[2]: fstream и unicode
От: pick_catcher  
Дата: 03.08.09 18:06
Оценка:
Поясню суть проблемы еще раз.

Если в конструкторе использовать широкие символы (имя файла — что очень хочеться), то записывать в файл тоже
придется широкие символы, то есть 3 байта записать не удасться, можно либо 2 либо 4 !!! (добавлять байт к буферу, до четного размера считаю извращением).

Если использовать, как обычно ANSI символы, то возникают проблемы с именем файла — нужно грамотно использовать локализацию,
чего я не умею (видел примеры с претензиями на кроссплатформенность — так там полсотни строк нечитаемого кода).

Вот и не знаю, что делать, похоже придется извращаться...
Re[3]: fstream и unicode
От: Sharpeye Россия  
Дата: 03.08.09 19:53
Оценка: 10 (3)
Здравствуйте, pick_catcher, Вы писали:

_>Поясню суть проблемы еще раз.


_>Если в конструкторе использовать широкие символы (имя файла — что очень хочеться), то записывать в файл тоже

Это если использовать wfstream, а не fstream. Иногда встречается перегрузка для fstream, которая принимает имя в виде wchar_t.

_>придется широкие символы, то есть 3 байта записать не удасться, можно либо 2 либо 4 !!! (добавлять байт к буферу, до четного размера считаю извращением).


_>Если использовать, как обычно ANSI символы, то возникают проблемы с именем файла — нужно грамотно использовать локализацию,

_>чего я не умею (видел примеры с претензиями на кроссплатформенность — так там полсотни строк нечитаемого кода).

_>Вот и не знаю, что делать, похоже придется извращаться...


Можно придумать такие извращения.

Использовать boost (да святится имя Его):

    #include <boost/filesystem/fstream.hpp>    

    namespace fs = boost::filesystem;

    fs::fstream file( L"мой файл.txt", std::ios_base::out | std::ios_base::binary );

    if( file.is_open() )
    {
        std::string str = "bingo";
        file.write( str.c_str(), (std::streamsize) str.length() );
        file.flush();
    }


Либо проимитировать его действия:
    std::wstring name = L"мой файл";

    // создаём файл
    {
        HANDLE handle = CreateFileW( name.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
        CloseHandle( handle );
    }

    // Получаем короткую форму (8.3) имени

    std::wstring short_form;

    for( DWORD size = (DWORD) name.size() + 1; ; )
    {
        boost::scoped_array< wchar_t > buffer( new wchar_t[ size ] );

        DWORD len = ::GetShortPathNameW( name.c_str(), buffer.get(), size );

        if( len == 0 ) 
        {
            // шота не то

            return -1;
        }

        if( len <= size )
        {
            short_form.assign( buffer.get(), len );

            break;
        }

        size = len + 1;
    }

    // Сужаем

    std::string narrow;

    {
        int size = ::WideCharToMultiByte( CP_ACP, 0,
            short_form.c_str(), (int) short_form.size(), 0, 0, 0, 0 );

        boost::scoped_array< char > buffer( new char[ size ] );

        ::WideCharToMultiByte( CP_ACP, 0,
            short_form.c_str(), (int) short_form.size(),
            buffer.get(), size, 0, 0 );

        narrow.assign( buffer.get(), size );
    }

    // Открываем файл

    std::fstream file( narrow.c_str(), std::ios_base::out | std::ios_base::binary );

    if( file.is_open() )
    {
        std::string str = "bingo";
        file.write( str.c_str(), (std::streamsize) str.length() );
        file.flush();
    }


Таким способом действует boost.filesystem.
Re[4]: fstream и unicode
От: pick_catcher  
Дата: 04.08.09 07:44
Оценка:
Не знал, что в boost'е есть аналог fstream'а.
СПАСИБО!!!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.