【问题标题】:Windows directory that will never contain non-ASCII characters for temp file?Windows 目录永远不会包含临时文件的非 ASCII 字符?
【发布时间】:2019-07-19 12:13:03
【问题描述】:

在 Windows 上使用 MinGW 7.3.0,由于 Windows 限制,Hunspell 无法从具有非 ASCII 字符的位置加载字典文件。我已经尝试了一切[1],现在我将文件复制到没有 ASCII 字符的路径,然后再将其提供给 Hunspell。将其复制到哪个位置比较好?

[1]

  1. Windows 需要 wchar_t 支持 std::iostream.open() 才能正常工作,MinGW 没有实现这一点
  2. std::filesystem 可以解决这个问题,但只能在 GCC 8 中使用
  3. Hunspell 坚持自己加载文件,无法将读取的文件作为字符串传递给它

【问题讨论】:

  • 检查是否可以将CreateFile 句柄强制转换为std::ifstream,如https://stackoverflow.com/a/476014/8666197。如果 gcc 实现了所需的功能,那么您需要修改 myopen 函数,可能还需要修改 FileMgr::~FileMgr。或者重新实现FileMgr 类。看来您需要实现一个基本功能getline

标签: windows winapi temporary-files hunspell


【解决方案1】:

“自然”适合使用用户选择的临时目录(或其子目录)(参见%temp%GetTempPath())。但是,默认情况下包含用户名(可以包含“非 ASCII”字符;例如 c:\users\Ø¥Ć¼\AppData\LocalLow\Temp)或任意内容(关于字符集)。

所以你很可能最好选择一些目录

a) 从一开始就不包含禁止字符。例如,您自己选择的 C:\ProgramData 下的目录(例如应用程序名称)您知道不包含非 ASCII 字符。

b) 让用户决定将这些文件放在哪里,并确保不允许输入仅包含允许字符的路径。

c) 将"short path name" 传递给 Hunspell,其中不应包含非 ASCII 字符以与 FAT 文件系统特征兼容。例如,c:\temp\Ø¥Ć¼ 的短路径名称为 c:\temp\571D~1

您可以使用cmd.exe /c dir /x查看目录的短名称:

C:\temp>dir /x
...    
19.07.2019  15:30    <DIR>                       .
19.07.2019  15:30    <DIR>                       ..
19.07.2019  15:30    <DIR>          571D~1       Ø¥Ć¼

我不知道如何从 MinGW 调用 GetShortPathName Win32 API,但我认为这是可能的。

还要确保查看 MSDN 页面以了解上述功能的 traitoffs,例如并非所有地方都支持短名称(例如 SMB + 请参阅下面的 cmets)。

【讨论】:

  • 谢谢 - 我不能写信给 a) 和 b) 是不行的。不确定 MinGW 是否为 C 提供了该 API,因此我决定复制到 C:\Windows\Temp - 它可以工作!
  • 应用程序文件不属于Windows 文件夹,只有系统文件可以。找到更合适的文件夹。
  • 我问这个问题是为了找出哪个是一个好的文件夹,所以,欢迎提出建议!
  • @VadimPeretokin 注意GetShortPathNameW 不可靠,因为8.3 file name generation may be disabled。未来的操作系统版本可能会默认禁用它以获得更好的性能。
  • @zett42, GetShortPathNameW 绝对不可靠——今天。我总是禁用 NTFS 卷上的短名称创建,因为它会减慢访问速度,尤其是在包含数千个文件的目录中。此外,较新的文件系统(如 ReFS 和 exFAT)根本不支持短名称,而且 Hunspell 不一定安装在 NTFS 系统驱动器上。
【解决方案2】:

来自this bug tracker

在 WIN32 环境下,使用以长开头的 UTF-8 编码路径 路径前缀 \\?\ 处理与系统无关的字符编码 和非常长的路径名(没有长路径前缀 Hunspell 将 将 fopen() 与系统相关的字符编码一起使用,而不是 _wfopen())。

所以实际的解决方案似乎是:

  1. 调用GetFullPathNameWnormalize 路径。必需,因为 paths with long path prefix \\?\ 被原封不动地传递给 NT API。
  2. L"\\\\?\\" 添加到规范化路径(由于C 字符串文字要求,反斜杠加倍)。
  3. 对于 UNC 路径,您必须直接使用“UNC”设备(即 L"\\\\server\\share"L"\\\\?\\UNC\\server\\share"(感谢 eryksun)
  4. 以 UTF-8 编码路径,例如。 G。使用WideCharToMultiByte()CP_UTF8
  5. 将最终的 UTF-8 编码路径传递给 Hunspell。

【讨论】:

  • 我希望只需要 UTF-8 编码,而不是将路径重写为扩展设备路径。这是假设这与最终组件中的保留名称无关(即 DOS 设备名称或以空格或点结尾的名称),也与 MAX_PATH (260) 长度限制无关。如果您确实使用扩展设备路径,那么对于 UNC 路径,您必须直接使用“UNC”设备(即"\\\\server\\share" -> "\\\\?\\UNC\\server\\share")。
  • 这应该是公认的答案。会删除我的,但它仍然被接受,所以我不能。
  • @Christian.K 看起来 OP 有 tried this before 没有成功。
  • 嗯...好的。所以我保持原样;-)
【解决方案3】:

看起来C:\Windows\Temp 仍然是您可以写给自己的有效路径。

【讨论】:

  • 虽然不能保证这样的文件夹是实际使用的%TEMP% 路径(事实上,它可能不是)。并且非管理员用户在 Windows 文件夹或其子文件夹中没有写入权限。
猜你喜欢
  • 1970-01-01
  • 2013-08-30
  • 2011-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-20
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多