На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА 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 Кбайт, скачиваний: 296)
                  Цитата 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("Ошибка установки локали"));
                              };


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


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,0630 ]   [ 18 queries used ]   [ Generated: 16.04.24, 22:01 GMT ]