c++ - 俄语(或非拉丁语)文件名加载 Qt Windows

标签 c++ windows macos qt utf-8

我正在尝试在包含非拉丁字符的 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/

相关文章:

c++ - 如何打印 NaN 的有效负载?

c++ - 链接错误 : Undefined Symbols, 很多(cpp 交叉编译)

C++,从函数返回字符串; boost::asio 读/写

c++ - 我如何在 C++ 中的 for 循环之外保存一个字符串

python - 在 Windows 下使用 NumPy 数组对图像进行快速傅里叶变换期间的内存错误

c++ - 手动加载 DLL 中的异常处理

windows - RHC 设置在 OpenShift 中失败 - UTF8 - SSH

python - 为什么 GCC 忽略 Snow Leopard 中的 ARCHFLAGS?

macos - 了解枚举和函数签名

c++ - B树递归搜索C++