在Windows中使用UTF8字符串的fopen文件名

时间:2014-04-25 06:33:16

标签: c++ file winapi opencv utf-8

当我使用opencv的API cvLoadImage(const char *filename, int iscolor)时,它接受const char *作为文件名。当文件名不是ASCII字符时,我试图将其转换为UTF8字符串。它失败是因为fopen()中调用的cvLoadImage()无法将文件名的字符解释为ASCII字符串。如果尝试打开文件名,我可能会使用_wfopen(),但如果在第三方库中调用fopen(),是否有任何方法可以解决此问题? 谢谢。

4 个答案:

答案 0 :(得分:9)

使用GetShortPathName。它将返回该文件的旧名称(8.3),您应该能够将其转换为char*,因为它不应包含任何非ASCII字符。

我刚刚用一些语言特定的字符对其进行了测试,它按照我的描述工作。我已经使用fopen从C:\łęłęł\ąóąóą.tsttgbb成功打开了一个文件。

答案 1 :(得分:1)

除了人们说无法做到这一点之外,没有其他任何内容可以快速搜索。如果你不能改变cvLoadImage(这是合理的,你不想搞砸了),你可以尝试欺骗它。

  1. 您可以使用CreateSymbolicLink创建指向该文件的链接。不过,我不确定它是否可行,因为MKLINK命令行实用程序需要管理权限。
  2. 如果无法创建符号链接,则始终可以使用仅ASCII名称将文件复制到其他位置。
  3. 如果您确实不想复制文件并且符号链接不起作用,您可以创建文件代理 - 创建一个仅具有ASCII名称的命名管道,并将每个读取从管道转换为读取文件。
  4. 我会选择选项1或2,但更简单。

答案 2 :(得分:0)

这是对这个问题的后期贡献。我查看了运行时库的源代码(微软提供的),发现我可以替换fopen使用的例程,用以下代码映射ANSI字符串(只需将它链接到你的exe中,它将替换它中的例程)运行时库)。

列出的版本适用于使用v141_xp工具包的Visual Studio 2017。我还没有为其他版本测试它,但我想可能需要一些小的改动(比如例程本身的名称)。如果违规库是DLL,它当然不会起作用。按照你的意愿做好准备。

#ifdef _DEBUG
    #define _NORMAL_BLOCK   1
    #define _CRT_BLOCK      2
    #define _malloc_crt(s)  (_malloc_dbg  (s, _CRT_BLOCK, __FILE__, __LINE__))
#else
    #define _malloc_crt     _malloc_base
#endif

// A hack to make fopen et al accept UTF8 strings (as at Visual Studio 2017), see:
//    D:\Program Files (x86)\Windows Kits\10\Source\10.0.10240.0\ucrt\internal\string_utilities.cpp
//    D:\Program Files (x86)\Windows Kits\10\Source\10.0.10240.0\ucrt\inc\corecrt_internal_traits.h
extern "C" BOOL __cdecl __acrt_copy_path_to_wide_string (char const* const path, wchar_t** const result)
{
    #if _MSC_VER != 1910
        #define STRINGIZE_HELPER(x) #x
        #define STRINGIZE(x) STRINGIZE_HELPER(x)
        __pragma (message (__FILE__ "(" STRINGIZE (__LINE__) ") : Error: Code not tested for this version of Visual Studio"));
    #endif

    assert (path);
    assert (result);

    // Compute the required size of the wide character buffer:
    int length = MultiByteToWideChar (CP_UTF8, 0, path, -1, nullptr, 0);
    assert (length > 0);

    *result = (wchar_t *) _malloc_crt (T2B (length));

    // Do the conversion:
    length = MultiByteToWideChar (CP_UTF8, 0, path, -1, *result, length);
    assert (length);
    return TRUE;
}

答案 3 :(得分:0)

setlocale(LC_ALL, ".65001");

fopen(u8"中文路径.txt", "rb"); //window7(中文) vs2017 ok