我正在尝试在包含非拉丁字符的 Qt/C++ 软件上加载文件。 一个使用俄语文件名的用户报告的问题,我试图用下面的代码快速修复它。
示例文件名是(我不会读或写俄语!):Летний сад.dgr
bool QDepthmapView::loadFile(const QString &fileName)
{
m_open_file_name = fileName;
m_redraw_all = 1;
// this fixes the problem on a MacOSX but NOT on Windows!
QByteArray ba = fileName.toUtf8();
char *file = ba.data();
// end of fix
if(pDoc->OnOpenDocument(file)) // quick fix for weird chars (russian filename bug report)
{
// removed
}
return false;
}
上面的修复是我在网上找到的一个快速的肮脏的东西,它适用于我的 MacOSX10.8,但似乎 Windows 处理非 ASCII 字符有点不同,我不熟悉它。
我正在寻找用于加载非 ASCII 文件名的多平台解决方案(该软件可在 Win、Mac 和 Linux 上运行)。
编辑以下评论:
OnOpenDocument
转到:
int QGraphDoc::OnOpenDocument(char* lpszPathName)
{
m_opened_name = QString(lpszPathName);
int ok = m_meta_graph->read( lpszPathName );
// removed //
}
####
int read( const pstring& filename )
{
// cleared
#ifdef _WIN32
ifstream stream( filename.c_str(), ios::binary | ios::in );
#else
ifstream stream( filename.c_str(), ios::in );
#endif
//cleared
stream.read( (char *) &version, sizeof( version ) );
// cleared
}
####
template <class T>
istream& pmemvec<T>::read( istream& stream, streampos offset )
{
if (offset != streampos(-1)) {
stream.seekg( offset );
}
// READ / WRITE USES 32-bit LENGTHS (number of elements)
// n.b., do not change this to size_t as it will cause 32-bit to 64-bit conversion problems
unsigned int length;
stream.read( (char *) &length, sizeof(unsigned int) );
m_length = size_t(length);
if (m_length >= storage_size()) {
if (m_data) {
delete [] m_data;
m_data = NULL;
}
while (m_length >= storage_size())
m_shift++;
m_data = new T [storage_size()];
if (!m_data)
throw pexception( pexception::MEMORY_ALLOCATION, sizeof(T) * storage_size() );
}
if (m_length != 0) {
stream.read( (char *) m_data, sizeof(T) * streamsize(m_length) );
}
return stream;
}
最佳答案
欢迎来到 Windows 本地编码的精彩世界。
Windows 在内部以 UTF-16 工作(如 QString
所做的那样),但它的“遗留”narrow-char API 使用“本地代码页”,通常与系统代码页相同(虽然它可以在每个线程的基础上进行自定义 - 但是不能,它不能设置为 UTF-8,因为 Windows 10 1903 现在可以了!)。
这意味着大多数使用 char
的函数将它们直接传递给 Windows API(通常发生在 C/C++ 文件设施中)期望使用当前代码页编码的字符串。
QString
确实支持 toLocal8Bit
方法以在当前系统编码中提供其内容的 narrow-char 表示,这应该是 Windows 上的本地 CP 和 UTF- 8 在任何配置合理的 UNIX 上。
问题是,QString
到 UTF-8 是无损转换,因为它们都可以表示所有 Unicode 代码点; QString
与本地代码页的关系不大 - 例如,俄语字符不能在通常的 Windows-1252 CP 中编码。
出于这个原因,使用toLocal8Bit
,您可以为流指定一个采用它期望的编码的文件名,但是您将无法打开包含当前代码页中未包含的字符的文件。
长话短说:通常避免任何问题的方法是始终将路径保持为 QString
并使用 QFile
打开文件。 QFile
通过使用 UTF-16 字符串调用 Windows API 的“widechar”版本并在 UNIX 系统上适本地转换为 UTF-8 来在内部处理这种错误。
如果您确实需要使用其他文件处理函数,您有两种选择:要么使用 toLocal8Bit
并放弃在 Windows 上处理具有“非本地”名称的文件,要么提供一个单独的代码适用于 wchar_t
的 Windows 路径(一直到 C 库和 Windows API 函数的宽字符版本)。
关于c++ - 俄语(或非拉丁语)文件名加载 Qt Windows,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23888263/