На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела Visual C++ / MFC / WTL (далее Раздела)
1) На Раздел распространяются все Правила Форума.
2) Перед тем, как создать новый топик, убедитесь, что Вы читали Правила создания тем в Разделе.
3) Вопросы, не связанные с программированием (настройки MS Visual Studio, книги, библиотеки и т.д.),
обсуждаются в разделе C/C++: Прочее
4) Вопросы разработки .NET (Windows Form, C++/CLI и т.п.) приложений на Visual C++/C# обсуждаются в разделе .NET.
5) Нарушение Правил может повлечь наказание со стороны модераторов.

Полезные ссылки:
user posted image FAQ Раздела user posted image Обновления для FAQ Раздела user posted image Поиск по Разделу user posted image MSDN Library Online
Модераторы: ElcnU
  
> wofstream wstring и запись русского текста в файл, При записи русского текста из wstring в поток типа wofstream поток рушится.
Написал программку для изучения вопроса:

ExpandedWrap disabled
    #include "stdafx.h"
    #include <string>
    #include <fstream>
    #include <locale.h>
    #include <iostream>
     
    using namespace std;
     
    #pragma setlocale("russian")
     
     
    int main()
    {
        int i;
        wchar_t *AnglWch=NULL;
        AnglWch=_wsetlocale(LC_ALL, _T("russian"));
        wstring rs = _T("Angliskie_BUKVY"), rsR = _T("Русские Буквы");
        wofstream os(_T("ProvRusBukv.txt"), ios_base::out | ios_base::trunc);
        wcout << _T("Vyvodim AnglText");
        os << rs;
        os << _T(" VkluchenieRusBukv  ");
        wcout << rsR;
        wcout << _T("Vyvodim RuslText");
        cin >> i;
        os << rs;
        os << rsR; ///  Вот в этом месте поток падает
        return 0;
    };


В консоль wcout русские буквы выводятся правильно, а в файл не выводятся.
Консоль – это одно, а файлы – это совсем другое. Для файлов есть std::codecvt<> и объекты std::locale.
Добавь
ExpandedWrap disabled
    os.imbue(std::locale("russian"));
после создания os. Такие вызовы imbue() нужны для каждого заинтересованного std::basic_stream, т.к. у каждого могут быть свои собственные объекты std::locale, не обязательно одинаковые.
По умолчанию все потоки наследуют глобальную локаль, поэтому, как вариант, можно поставить одну такую локаль глобально вызовом std::locale::global(), и тогда все потоки в конструкторе будут по умолчанию получать её.
Одни с годами умнеют, другие становятся старше.
Спасибо, программа работает, русские буквы в файле есть. Вопрос, в основной программе существует несколько классов, в которых производится потоковый вывод в файл и чтение из файла. Достаточно где-то в одном модуле вызвать std::locale::globale(...); Или надо в каждой функции, работающей с потоком, производить такую установку std::locale::globale(...); ?
Основная идея дизайна std::locale() в том, что в общем случае программе может потребоваться иметь разные наборы культурных и национальных особенностей одновременно. Если такой необходимости нет, то да, проще в начале работы построить нужный экземпляр и установить его глобальным. Тогда любой конструктор потокового класса ввода-вывода сразу будет брать его в качестве основного.
Но тут надо понимать, что std::locale::global() не повлияет на уже существующие экземпляры потоков, ибо они берут берут умалчиваемый std::locale только в конструкторе. И среди таких есть как минимум std::cout, std::cin итп, т.к. они конструируются ещё до main(). Для уже существующих нужно вызывать их метод imbue(). Он позволяет сменить экземпляр std::locale уже после конструирования.
Одни с годами умнеют, другие становятся старше.
В программе включена русская локаль. Если перенести мою программу на компьютер без русского языка, будут ли моя программа правильно работать?
std::locale завязаны на поддержку от ОС. Список поддерживаемых ею локалей довольно обширен и в целом от языка интерфейса не зависит. В Windows с русским интерфейсом, например, могут быть десятки поддерживаемых локалей. Попробуй, например, немецкую, почти наверняка получится.
Попытка создать неподдерживаемую локаль провалится с исключением. Чтобы узнать список поддерживаемых, есть API. Посмотри в сторону EnumSystemLocalesEx().
Одни с годами умнеют, другие становятся старше.
у меня была программка, в которой я выводил wstring в файл CFile. И я вспомнил, что в этом файле были коды Unicode. И каждый символ занимал 2 байта. Но в файле созданном при помощи потока, каждый символ занимает только один байт. Это следствие использования locale? Для изучения этого вопроса я написал программку:

ExpandedWrap disabled
    // FileUnikodDlg.cpp : файл реализации
    //
     
    #include "stdafx.h"
    #include <string>
    #include "FileUnikod.h"
    #include "FileUnikodDlg.h"
    #include "afxdialogex.h"
     
    ...
     
    void CFileUnikodDlg::OnBnClickedButtonUnikod()
    {
        // TODO: Add your control notification handler code here
        wstring w=_T("Рус wstring");
        CString s=_T("Рус CString");
        CFileException e;
     
        CFile fw, fs;
        if (!fw.Open(_T("fw.txt"), CFile::modeCreate | CFile::modeWrite, &e))
        {
            AfxMessageBox(_T("Ошибка открытия файла fw.txt")); return;
        };
        if (!fs.Open(_T("fs.txt"), CFile::modeCreate | CFile::modeWrite, &e))
        {
            AfxMessageBox(_T("Ошибка открытия файла fs.txt")); fw.Close(); return;
        };
        fw.Write(&w[0], w.size()*sizeof(w[0]));
        fs.Write(s, s.GetLength() * sizeof(s[0]));
        fw.Close(); fs.Close();
     
    }


Картинка FAR в файле Far_16.jpg, проект написанный в VC++ 2017 года в файле FileUnikod.rar
Прикреплённая картинка
Прикреплённая картинка

Прикреплённый файлПрикреплённый файлFileUnikod.rar (130,04 Кбайт, скачиваний: 2)
Цитата a_n_y_a @
Это следствие использования locale?
Если вопрос в этом, а других я не увидел, то ответ – нет. Потоки в std все и всегда байтовые, но вопрос в том, как интерпретировать пропускаемые через поток последовательности байт. Внутреннее и внешнее представления символов в этом потоке могут отличаться, и зачастую так и есть. Например, в файле лежит UTF8, а программа работает с std::wstring, т.е. с (не совсем так) UTF16, поэтому при вводе-выводе должно выполняться преобразование из одной формы в другую.
В файловых потоках за это отвечает фасет std::codecvt<>, который задействуется при форматном вводе/выводе. Любая локаль, даже стандартная std::locale::classic, по умолчанию содержит std::codecvt<>, который преобразует wchar_t (это если std::w(i/o)fstream) в char стандартным образом: в стандартные однобайтовые символы. Когда ты стандартную локаль заменяешь на кастомную, в std::codecvt<> всего лишь меняются правила соответствия между char и wchar_t, но преобразование в однобайтовую форму всё равно будет. Если такое поведение неприемлемо, то: либо это правило нужно изменить подменой фасета; либо – для простых операций это проще – вместо форматного ввода/вывода бинарный, он не задействует преобразование потока байтов. В первом примере у тебя использовался форматный, в следующем бинарный. Потому и разница.

P.S. Это что касается потоковых классов из Стандарта языка. CFile таковым не является, это продукт сугубо MS. Всё вышесказанное к нему может не иметь никакого отношения.
Сообщение отредактировано: Qraizer -
Одни с годами умнеют, другие становятся старше.
Изучаю вопрос установки std::locale::global для компьютера, на котором нет русской локали.
Для этого устанавливаю локаль с тестовым именем, которого точно нет на моем компе:
std::locale Loc = std::locale::global(std::locale("rrr"));
После такой установки моя программа не работает, но что-то не пойму где смотреть
результат установки?
Формально установка локали всегда успешна. Ну, не без того, вдруг где-то памяти не хватит, но к локалям это имеет мало отношения.
Вот создание локали может быть неуспешно. В таком случае кидается исключение std::runtime_error.
Одни с годами умнеют, другие становятся старше.
Цитата Qraizer @
Попытка создать неподдерживаемую локаль провалится с исключением.

Я написал вызов установки несуществующей локали, чтобы поймать исключение:

ExpandedWrap disabled
        try
        {
            std::locale Loc = std::locale::global(std::locale("rrr"));   ///  EnumSystemLocalesEx
        }
        catch (...)   ///  Или здесь надо писать catch(std::runtime_error e) ?
        {
            AfxMessageBox(_T("Ошибка установки локали"));
        };


Но исключения нет.
Должно быть. Проверь свои средства разработки и параметры компилятору.
Одни с годами умнеют, другие становятся старше.
1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
0 пользователей:


Рейтинг@Mail.ru
[ Script Execution time: 0,1556 ]   [ 22 queries used ]   [ Generated: 3.12.20, 07:26 GMT ]