Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.118.200.197] |
|
Сообщ.
#1
,
|
|
|
Написал программку для изучения вопроса:
#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 русские буквы выводятся правильно, а в файл не выводятся. |
Сообщ.
#2
,
|
|
|
Консоль – это одно, а файлы – это совсем другое. Для файлов есть std::codecvt<> и объекты std::locale.
Добавь os.imbue(std::locale("russian")); По умолчанию все потоки наследуют глобальную локаль, поэтому, как вариант, можно поставить одну такую локаль глобально вызовом std::locale::global(), и тогда все потоки в конструкторе будут по умолчанию получать её. |
Сообщ.
#3
,
|
|
|
Спасибо, программа работает, русские буквы в файле есть. Вопрос, в основной программе существует несколько классов, в которых производится потоковый вывод в файл и чтение из файла. Достаточно где-то в одном модуле вызвать std::locale::globale(...); Или надо в каждой функции, работающей с потоком, производить такую установку std::locale::globale(...); ?
|
Сообщ.
#4
,
|
|
|
Основная идея дизайна std::locale() в том, что в общем случае программе может потребоваться иметь разные наборы культурных и национальных особенностей одновременно. Если такой необходимости нет, то да, проще в начале работы построить нужный экземпляр и установить его глобальным. Тогда любой конструктор потокового класса ввода-вывода сразу будет брать его в качестве основного.
Но тут надо понимать, что std::locale::global() не повлияет на уже существующие экземпляры потоков, ибо они берут берут умалчиваемый std::locale только в конструкторе. И среди таких есть как минимум std::cout, std::cin итп, т.к. они конструируются ещё до main(). Для уже существующих нужно вызывать их метод imbue(). Он позволяет сменить экземпляр std::locale уже после конструирования. |
Сообщ.
#5
,
|
|
|
В программе включена русская локаль. Если перенести мою программу на компьютер без русского языка, будут ли моя программа правильно работать?
|
Сообщ.
#6
,
|
|
|
std::locale завязаны на поддержку от ОС. Список поддерживаемых ею локалей довольно обширен и в целом от языка интерфейса не зависит. В Windows с русским интерфейсом, например, могут быть десятки поддерживаемых локалей. Попробуй, например, немецкую, почти наверняка получится.
Попытка создать неподдерживаемую локаль провалится с исключением. Чтобы узнать список поддерживаемых, есть API. Посмотри в сторону EnumSystemLocalesEx(). |
Сообщ.
#7
,
|
|
|
у меня была программка, в которой я выводил wstring в файл CFile. И я вспомнил, что в этом файле были коды Unicode. И каждый символ занимал 2 байта. Но в файле созданном при помощи потока, каждый символ занимает только один байт. Это следствие использования locale? Для изучения этого вопроса я написал программку:
// 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) |
Сообщ.
#8
,
|
|
|
Цитата a_n_y_a @ Если вопрос в этом, а других я не увидел, то ответ – нет. Потоки в std все и всегда байтовые, но вопрос в том, как интерпретировать пропускаемые через поток последовательности байт. Внутреннее и внешнее представления символов в этом потоке могут отличаться, и зачастую так и есть. Например, в файле лежит UTF8, а программа работает с std::wstring, т.е. с (не совсем так) UTF16, поэтому при вводе-выводе должно выполняться преобразование из одной формы в другую.Это следствие использования locale? В файловых потоках за это отвечает фасет std::codecvt<>, который задействуется при форматном вводе/выводе. Любая локаль, даже стандартная std::locale::classic, по умолчанию содержит std::codecvt<>, который преобразует wchar_t (это если std::w(i/o)fstream) в char стандартным образом: в стандартные однобайтовые символы. Когда ты стандартную локаль заменяешь на кастомную, в std::codecvt<> всего лишь меняются правила соответствия между char и wchar_t, но преобразование в однобайтовую форму всё равно будет. Если такое поведение неприемлемо, то: либо это правило нужно изменить подменой фасета; либо – для простых операций это проще – вместо форматного ввода/вывода бинарный, он не задействует преобразование потока байтов. В первом примере у тебя использовался форматный, в следующем бинарный. Потому и разница. P.S. Это что касается потоковых классов из Стандарта языка. CFile таковым не является, это продукт сугубо MS. Всё вышесказанное к нему может не иметь никакого отношения. |
Сообщ.
#9
,
|
|
|
Изучаю вопрос установки std::locale::global для компьютера, на котором нет русской локали.
Для этого устанавливаю локаль с тестовым именем, которого точно нет на моем компе: std::locale Loc = std::locale::global(std::locale("rrr")); После такой установки моя программа не работает, но что-то не пойму где смотреть результат установки? |
Сообщ.
#10
,
|
|
|
Формально установка локали всегда успешна. Ну, не без того, вдруг где-то памяти не хватит, но к локалям это имеет мало отношения.
Вот создание локали может быть неуспешно. В таком случае кидается исключение std::runtime_error. |
Сообщ.
#11
,
|
|
|
Цитата Qraizer @ Попытка создать неподдерживаемую локаль провалится с исключением. Я написал вызов установки несуществующей локали, чтобы поймать исключение: try { std::locale Loc = std::locale::global(std::locale("rrr")); /// EnumSystemLocalesEx } catch (...) /// Или здесь надо писать catch(std::runtime_error e) ? { AfxMessageBox(_T("Ошибка установки локали")); }; Но исключения нет. |
Сообщ.
#12
,
|
|
|
Должно быть. Проверь свои средства разработки и параметры компилятору.
|