Как записать неанглийскую строку в файл и прочитать из этого файла с C++?

Я хочу написать std::wstring на файл и нужно прочитать этот контент как std:wstring, Это происходит, как ожидается, когда строка L"<Any English letter>", Но проблема возникает, когда у нас есть такие персонажи, как бенгальский, каннада, японский и т. Д., Иные неанглийские буквы. Пробовал различные варианты, такие как:

  1. Преобразование std::wstring в std::string и записать в файл и время чтения читать как std::string и преобразовать как std::wstring
    • Запись происходит (я мог видеть из edito), но время чтения становится неправильным
  2. Пишу std::wstring на wofstream, это также не помогает для букв на родном языке, таких как std::wstring data = L"হ্যালো ওয়ার্ল্ড";

Платформа Mac и Linux, язык C++

Код:

bool
write_file(
    const char*         path,
    const std::wstring  data
) {
    bool status = false;
    try {
        std::wofstream file(path, std::ios::out|std::ios::trunc|std::ios::binary);
        if (file.is_open()) {
            //std::string data_str = convert_wstring_to_string(data);
            file.write(data.c_str(), (std::streamsize)data.size());
            file.close();
            status = true;
        }
    } catch (...) {
        std::cout<<"exception !"<<std::endl;
    }
    return status;
}


// Read Method

std::wstring
read_file(
    const char*  filename
) {
    std::wifstream fhandle(filename, std::ios::in | std::ios::binary);
    if (fhandle) {
        std::wstring contents;
        fhandle.seekg(0, std::ios::end);
        contents.resize((int)fhandle.tellg());
        fhandle.seekg(0, std::ios::beg);
        fhandle.read(&contents[0], contents.size());
        fhandle.close();
        return(contents);
    }
    else {
        return L"";
    }
}

// Main

int main()
{
  const char* file_path_1 = "./file_content_1.txt";
  const char* file_path_2 = "./file_content_2.txt";

  //std::wstring data = L"Text message to write onto the file\n";  // This is happening as expected
  std::wstring data = L"হ্যালো ওয়ার্ল্ড";
// Not happening as expected.

  // Lets write some data
  write_file(file_path_1, data);
 // Lets read the file
 std::wstring out = read_file(file_path_1);

 std::wcout<<L"File Content: "<<out<<std::endl;
 // Let write that same data onto the different file
 write_file(file_path_2, out);
 return 0;
}

5 ответов

Решение

Как wchar_t вывод зависит от локали. Язык по умолчанию ("C") обычно не принимает ничего, кроме ASCII (кодовые точки Unicode 0x20...0x7E, плюс несколько управляющих символов.)

Каждый раз, когда программа обрабатывает текст, самое первое утверждение вmain должно быть:

std::locale::global( std::locale( "" ) );

Если программа использует какой-либо из стандартных потоковых объектов, код должен также наполнить их глобальной локалью перед любым вводом или выводом.

Не используйте wstring или wchar_t. На платформах, отличных от Windows, в наши дни wchar_t практически ничего не стоит.

Вместо этого вы должны использовать UTF-8.

bool
write_file(
    const char*         path,
    const std::string   data
) {
    try {
        std::ofstream file(path, std::ios::out | std::ios::trunc | std::ios::binary);
        file.exceptions(true);
        file << data;
        return true;
    } catch (...) {
        std::cout << "exception!\n";
        return false;
    }
}


// Read Method

std::string
read_file(
    const char*  filename
) {
    std::ifstream fhandle(filename, std::ios::in | std::ios::binary);

    if (fhandle) {
        std::string contents;
        fhandle.seekg(0, std::ios::end);
        contents.resize(fhandle.tellg());
        fhandle.seekg(0, std::ios::beg);
        fhandle.read(&contents[0], contents.size());
        return contents;
    } else {
        return "";
    }
}

int main()
{
  const char* file_path_1 = "./file_content_1.txt";
  const char* file_path_2 = "./file_content_2.txt";

  std::string data = "হ্যালো ওয়ার্ল্ড"; // linux and os x compilers use UTF-8 as the default execution encoding.

  write_file(file_path_1, data);
  std::string out = read_file(file_path_1);

  std::wcout << "File Content: " << out << '\n';
  write_file(file_path_2, out);
}

Для чтения и записи файлов Unicode (при условии, что вы хотите писать символы Unicode) вы можете попробовать fopen_s

FILE *file;

if((fopen_s(&file, file_path, "w,ccs=UNICODE" )) == NULL)
{
    fputws(your_wstring().c_str(), file);
}

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

Если вы имеете дело с текстовыми файлами, почему бы просто не использовать обычные операторы вывода и ввода << а также >> или другие текстовые функции, такие как std::getline?

Позднее редактирование: это для Windows (поскольку на момент ответа не было тега)

Вам нужно установить поток в локаль, которая поддерживает эти символы. Попробуйте что-то вроде этого (для UTF8/UTF16):

std::wofstream myFile("out.txt"); // writing to this file 
myFile.imbue(std::locale(myFile.getloc(), new std::codecvt_utf8_utf16<wchar_t>));

И когда вы читаете из этого файла, вы должны сделать то же самое:

std::wifstream myFile2("out.txt"); // reading from this file
myFile2.imbue(std::locale(myFile2.getloc(), new std::codecvt_utf8_utf16<wchar_t>));
Другие вопросы по тегам