C++11跨Windows/Linux创建Unicode文件名文件的问题求助
Let's break down why your previous attempts failed and fix the core issue first—then we'll build a working cross-platform solution that fits your constraints.
The Root Problem: Windows Terminal Encoding Mismatch
Linux terminals default to UTF-8, so your input äöüé.txt is directly stored as UTF-8 bytes in std::string, which the Linux kernel understands perfectly.
On Windows, however, your terminal uses an OEM code page (yours is CP850). The äöüé characters you type are stored as CP850-encoded bytes, not UTF-8. Your earlier code tried to convert these bytes as if they were UTF-8, which is why you got garbled filenames like „”‚.txt.
Working Cross-Platform Solution
This code uses only C11 standard libraries and Windows API functions (where needed), no C17 filesystem or third-party libraries.
Complete Code
#include <iostream> #include <fstream> #include <string> #include <cstdio> // For _wfopen, fclose #ifdef _MSC_VER #include <windows.h> // Convert OEM-encoded string (from Windows terminal) to UTF-16 (wstring) std::wstring OemToUtf16(const std::string& oem_str) { int wide_length = MultiByteToWideChar(CP_OEMCP, 0, oem_str.c_str(), static_cast<int>(oem_str.size()), nullptr, 0); if (wide_length == 0) { return {}; } std::wstring wide_str(wide_length, L'\0'); MultiByteToWideChar(CP_OEMCP, 0, oem_str.c_str(), static_cast<int>(oem_str.size()), &wide_str[0], wide_length); return wide_str; } #endif int main() { std::string fileName; std::cout << "Please enter the name of file ! " << std::endl; std::cin >> fileName; std::cout << "name = " << fileName << std::endl; bool fileCreated = false; #ifdef _MSC_VER // Convert terminal input (OEM) to UTF-16 for Windows API std::wstring wideFileName = OemToUtf16(fileName); if (!wideFileName.empty()) { // Use _wfopen to create file with Unicode filename FILE* fileHandle = _wfopen(wideFileName.c_str(), L"wb"); if (fileHandle != nullptr) { // Associate with std::ofstream if you want to use standard streams std::ofstream outputStream(fileHandle); outputStream << "Hello Unicode Filename!\n"; outputStream.close(); // Closes both stream and FILE* fileCreated = true; } } #else // Linux: Directly use UTF-8 string with std::fstream std::ofstream outputStream(fileName, std::ios::out | std::ios::trunc | std::ios::binary); if (outputStream.is_open()) { outputStream << "Hello Unicode Filename!\n"; outputStream.close(); fileCreated = true; } #endif if (fileCreated) { std::cout << "File created successfully!" << std::endl; } else { std::cout << "Failed to create file!" << std::endl; } return 0; }
Fixes for Your Previous Attempts
Let's clarify why your earlier approaches didn't work:
- Method 1: You used
MultiByteToWideChar(CP_UTF8, ...)—but Windows terminal input isn't UTF-8, it's OEM. Switching toCP_OEMCPfixes the conversion. - Method 2:
CreateFileAuses the system's ANSI code page (e.g., CP1252), not the terminal's OEM code page. UsingCreateFileWwith UTF-16 would work, but_wfopenis simpler for integrating with standard streams. - Method 3: Your
codecvtsetup didn't account for the OEM-to-UTF16 conversion, so the input string's encoding was invalid for Windows API calls.
Additional Windows Testing Tip
If you want to read filenames directly with std::wcin, set the correct locale first to handle OEM input properly. Add this to the start of main() on Windows:
setlocale(LC_ALL, ".OCP"); // Set locale to match terminal's OEM code page std::wstring wideFileName; std::wcout << L"Please enter the name of file ! " << std::endl; std::wcin >> wideFileName; // Use _wfopen(wideFileName.c_str(), L"wb") directly
内容的提问来源于stack exchange,提问作者Franck

