如何在Windows中比较可能的备用文件名?

时间:2019-04-24 22:31:09

标签: c++ windows filenames

不幸的是,Windows中的目录/文件名不区分大小写。

当我将文本(来自用户的输入)与目录名称(来自CFileFind)进行比较时,如何检查它们是否表示相同的目录? 例如,C:\PIPPO\C:\Pippo\是同一目录,而C:\Pippò\是不同的目录(最后一个带有重音符号)。

我正在尝试:

if(CompareString(LOCALE_INVARIANT,NORM_IGNORECASE,q,-1,data_from_CfileFind->txt.GetBuffer(),-1)==CSTR_EQUAL)

({q是用户输入的一部分)

它是“种类繁多的作品”,因为它可以识别罗马,希腊和西里尔字母的大小写不同,但是却混淆了"weiß""weiss"(它们是我的两个不同目录光盘),因此不可靠。

[失败的测试是受Comparing and sorting Unicode filenames的启发:我已阅读它,但没有找到合适的解决方案-链接似乎无法正常工作

(我也读过Windows Invariant Culture Puzzle,但恐怕我对“文化”并不完全了解。)

有什么建议吗?

也许我应该使用不同的参数调用CompareString()?还是有更好,更轻松的方法?

请注意,我不需要对名称进行排序:我只想检查它们是否与Windows意味着相同的目录(或文件)。

“ Windows”是指2000(或至少XP)及更高版本。

编辑(对不起,这个问题第一次问得不好)

1)用户输入的路径不能保证引用到实际存在的目录(当然,在这种情况下,它们不是同一目录)。

2)我知道由于链接(硬或软),subst,对同一台计算机使用不同名称或IP的网络访问等原因,文件和目录可以用非常不同的名称来引用。 ..但我不是要检测所有这些情况。 我要检查的是用户写的名称是否是另一个现有名称的大小写变化(因此,例如,Windows会告诉我,如果我尝试创建一个具有相同名称的文件,则该文件已经存在。但情况不同。

第二次编辑

这可以完成工作(至少在我尝试过的情况下):

if(CompareStringOrdinal(q,-1,data_from_CfileFind->txt.GetBuffer(),-1,1)==CSTR_EQUAL)

但是CompareStringOrdinal()在较旧的Windows版本中不可用。 有什么等效的吗?

3 个答案:

答案 0 :(得分:2)

(据我所知)检查两个文件系统路径是否引用同一项目的最佳方法,求助于字符串比较的方法是:

  1. 使用CreateFile()打开HANDLE到两个路径,然后从HANDLE获得唯一的文件系统ID并比较它们是否相等。在FAT和NTFS上,使用GetFileInformationByHandle()dwVolumeSerialNumbernFileIndex(Low|High)的组合。在ReFS上,请使用GetFileInformationByHandleEx(FileIdInfo)VolumeSerialNumberFileId的组合。您可以使用GetVolumeInformation()来检测每个路径正在使用哪个文件系统。

    分别在BY_HANDLE_FILE_INFORMATIONFILE_ID_INFO文档中对此方法进行了描述:

      

    标识符(上下两部分)和卷序列号唯一地标识一台计算机上的文件。要确定两个打开的句柄是否代表同一个文件,请将每个文件的标识符和卷序列号组合起来并进行比较。

      

    文件的128位文件标识符。文件标识符和卷序列号唯一地标识一台计算机上的文件。要确定两个打开的句柄是否代表同一个文件,请将每个文件的标识符和卷序列号组合起来并进行比较。

  2. 与文件系统无关的方法是使用SHGetDesktopFolder()获取Shell命名空间的根桌面的IShellFolder接口,然后使用桌面的{{3 }}方法(或使用独立的IShellFolder::ParseDisplayName()函数),然后使用桌面的SHParseDisplayName()方法比较PIDL。

答案 1 :(得分:1)

首先在每个路径上调用GetFullPathName,然后进行GetLongPathName,最后对结果进行不区分大小写的比较。

import Carbon.HIToolbox.Events @IBAction func buttonPressed(_ sender: AnyObject) { //let keyCode = CGKeyCode(kVK_F11) let keyCode = CGKeyCode(kVK_VolumeUp) let keySource = CGEventSource(stateID: .hidSystemState) let keyDownEvent = CGEvent(keyboardEventSource: keySource, virtualKey: keyCode, keyDown: true) //keyDownEvent?.flags = .maskCommand //keyDownEvent?.flags = .maskControl //keyDownEvent?.flags = .maskAlternate //keyDownEvent?.flags = .maskSecondaryFn //keyDownEvent?.flags = .maskShift //keyDownEvent?.flags = .maskNumericPad //keyDownEvent?.flags = .maskHelp let keyUpEvent = CGEvent(keyboardEventSource: keySource, virtualKey: keyCode, keyDown: false) keyDownEvent?.post(tap: .cghidEventTap) keyUpEvent?.post(tap: .cghidEventTap) } 将为每个文件提供完全限定的路径。 GetFullPathName然后获得该路径的每个组件的真实名称,因此,如果有人使用Windows 95/98样式的文件/目录简称,就不会造成混乱。

答案 2 :(得分:0)

这就是它的工作方式:

1)在程序开始时,调用setlocale(LC_CTYPE, "");

2)然后将字符串与if(!data_from_CfileFind->txt.CompareNoCase(q))(调用_wcsicmp并调用_wcsicmp_l的字符串进行比较)