Создайте новый файл (не читать существующий файл) с именем файла Unicode в Windows - PullRequest
0 голосов
/ 09 января 2020

Мне нужно использовать программу на C ++ для создания нового файла с символами Unicode (например, äöüé.txt) в Windows и Linux со следующим кодом:

int main(){
    std::string nameOfFile;

    std::cout << "Please enter the name of  file ! " << std::endl;

    std::cin >> nameOfFile;

    std::cout << "name = " << nameOfFile << std::endl;

    std::fstream mystream;

    mystream.open(nameOfFile, std::ios::out | std::ios::trunc | std::ios::binary);

    mystream.close();

    return 0;
}

I выполнить одну и ту же программу в Windows и Linux (с Visual Studio 2015 для Windows и g cc 5.4 для Linux), с вводом "äöüé.txt" в терминале.

Я обнаружил, что файл "äöüé.txt" создан правильно с правильным именем файла "äöüé.txt" в Linux. Но имя файла, созданное в Windows, кажется неправильным ("„”‚.txt").

Я знаю, что это из-за разницы в кодировке между Linux и Windows. Linux принимает UTF-8, а Windows принимает UTF-16.

Теперь мне нужно правильно создать файл в Windows, как и в Linux.

I пробовал следующие методы:

(1) в соответствии с std :: wstring VS std :: string , я пытался использовать функцию MultiByteToWideChar() от Microsoft, как подробно описано здесь: Откройте файл с кодировкой utf8 в c ++ Windows, но FAIL:

#ifdef _MSC_VER
std::wstring ToUtf16(std::string str)
{
    std::wstring ret;
    int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
    if (len > 0)
    {
        ret.resize(len);
        MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &ret[0], len);
    }
    return ret;
}
#endif

int main()
{
    std::string nameOfFile;

    std::cout << "Please enter the name of  file ! " << std::endl;

    std::cin >> nameOfFile;

    std::cout << "name = " << nameOfFile << std::endl;

    std::ifstream iFileStream(
        #ifdef _MSC_VER
        ToUtf16(nameOfFile).c_str()
        #else
        nameOfFile.c_str()
        #endif
        , std::ifstream::in | std::ifstream::binary);
    return 0;
}

(2) в соответствии с Как создать файл с UNICODE-путем на Windows с C ++ , Я пытался использовать функцию CreateFile(), но FAIL:

int main()
{
    std::string nameOfFile;

    std::cout << "Please enter the name of  file ! " << std::endl;

    std::cin >> nameOfFile;

    std::cout << "name = " << nameOfFile << std::endl;

    /*convert string to char array */
    int stringLen = nameOfFile.length();
    char* text = new char[stringLen + 1];
    std::strcpy(text, nameOfFile.c_str());

    /*Convert to utf-16*/
    HANDLE hFile = CreateFileA(nameOfFile.c_str(),
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_NEW,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    if (hFile != INVALID_HANDLE_VALUE) {
        int file_descriptor = _open_osfhandle((intptr_t)hFile, 0);

        if (file_descriptor != -1) {
            FILE* file = _fdopen(file_descriptor, "w");

            if (file != NULL) {
                std::ofstream stream(file);

                stream << "Hello World\n";

                // Closes stream, file, file_descriptor, and file_handle.
                stream.close();

                file = NULL;
                file_descriptor = -1;
                hFile = INVALID_HANDLE_VALUE;
            }
        }
    }

    return 0;
}

(3) в соответствии с https://en.cppreference.com/w/cpp/locale/codecvt_utf8_utf16 (см. Пример внизу), я пытался использовать codecvt, а затем используйте _wfopen(), как описано здесь: https://docs.microsoft.com/en-us/previous-versions/yeby3zcb (v% 3Dvs.140) , но FAIL.

Мои ограничения таковы:

  1. C ++ 11 (я знаю, что C ++ 17 включает файловую систему в STL, поэтому эту проблему можно решить), как описано здесь: Как открыть std :: fstream (ofstream или ifstream) с именем файла в юникоде?

  2. повышение не разрешено

  3. Библиотека QT не разрешена

Единственное, что я могу использовать, это стандартная библиотека C ++ и библиотека Microsoft.

У вас есть идеи?

Алану:

Благодаря вашему ответу я использовал следующий код для проверки кодировки символов в моем windows:

int main(){

    std::wstring nameOfFile;

    std::wcout << "Please enter the name of  file ! " << std::endl;

    std::wcin >> nameOfFile;

    std::wcout << "name = " << nameOfFile << std::endl;

    /*convert string to char array */
    int stringLen = nameOfFile.length();
    wchar_t* text = new wchar_t[stringLen + 1];
    std::wcscpy(text, nameOfFile.c_str());

    /*Get the coding number*/
    std::cout << "strlen(text)    : " << wcslen(text) << std::endl;

    std::cout << "text(ordinals)  :";

    for (size_t i = 0, iMax = wcslen(text); i < iMax; ++i)
    {
        std::cout << " " << static_cast<unsigned int>(
            static_cast<unsigned char>(text[i])
        );
    }

    _wfopen(text, L"w");

    return 0;
}

Кодовая страница моего Windows равна 850, и на выходе видно, что äöüé кодируется как 132 148 129 130, что, согласно таблице для кода страница 850 точно соответствует ä(132) ö'(148) ü(129) é(130).

. В конце кода выше я использую функцию _wfopen() для создания файла, но точный созданный файл все еще имеет неправильное имя.

Кстати, использование std::fstream(), как показано в моем втором примере, не может создать новый файл, оно может просто прочитать существующий файл.

Я думаю, fopen() или _wfopen() являются единственными функциями, которые могут создавать новый файл вместо чтения существующего файла.

...