【问题标题】:Windows / NTFS: Two files with identical long-names in the same directory?Windows / NTFS:同一目录中具有相同长名称的两个文件?
【发布时间】:2017-04-13 00:43:42
【问题描述】:

多年来,我一直是 stackoverflow.com 的潜伏者(这里的网站和用户都很棒),但从来不需要问问题。现在是时候了 :-) 让我开始吧:

操作系统:x64 Windows 8.0 到 Windows 10 (15063.14)(这个问题多年来一直存在,但我从未完全研究过它,因此我们可以排除它特定于特定 Windows 版本)

FS:NTFS

问题:同一目录中有两个具有相同(长)名称的文件,我什至无法弄清楚这怎么可能。多年来,每当我手动升级我的电子邮件客户端时,都会发生这种情况。如果将新文件复制到同一目录,则它的主 .EXE 文件(MailClient.exe)永远不会要求替换。相反,它们都被放置在那里,具有完全相同的长名称。

该问题与特定目录无关,我可以将两个 .EXE 文件复制到 NTFS 驱动器上新创建的目录中而不会出现问题(那里也没有“覆盖”问题)。

让我告诉你:

C:\temp\2>dir
 Volume in drive C is SSD 840 Pro
 Volume Serial Number is 0C6D-D489

 Directory of C:\temp\2

13.04.2017  02:29    <DIR>          .
13.04.2017  02:29    <DIR>          ..
21.10.2016  17:10        24.742.760 MailClient.exe
27.12.2016  03:26        24.911.872 MailCliеnt.exe
               2 File(s)     49.654.632 bytes
               2 Dir(s)  78.503.038.976 bytes free

但是,如果执行 dir /x,则会出现以下情况:

C:\temp\2>dir /x
 Volume in drive C is SSD 840 Pro
 Volume Serial Number is 0C6D-D489

 Directory of C:\temp\2

13.04.2017  02:29    <DIR>                       .
13.04.2017  02:29    <DIR>                       ..
21.10.2016  17:10        24.742.760 MAILCL~2.EXE MailClient.exe
27.12.2016  03:26        24.911.872 MAILCL~1.EXE MailCliеnt.exe
               2 File(s)     49.654.632 bytes
               2 Dir(s)  78.503.038.976 bytes free

所以他们显然有一个不同的 8.3 名称,好吧,但完全相同的长名称。这是情况的另一个屏幕截图。这两个文件在 Windows“属性”对话框(右键单击)中也显示相同的位置。不幸的是,我还不允许发布图片(似乎)- 只是尝试过。所以你必须相信我的话。

我不知道这是怎么可能的,这让我很烦;)当我将这两个文件重命名为 1.exe 时,Windows 开始告诉我在同一个目录中已经有一个同名的文件。所以它显然与文件名有关,但它们完全相同,没有多余的空格,什么都没有,正如您从 DIR 命令中看到的那样。

我还尝试重命名它们并为两者手动重新编写确切的措辞“MailCient.exe”,以确保字符完全相同,Windows 仍然不会抱怨,它们都再次出现在那里同名。但是,将它们重命名为“Mail.exe”和“Mail.exe”将不起作用,然后 Windows 会说另一个具有该名称的文件已经存在。但是,将它们都命名为“MailClient.exe”绝对没问题,Windows 不会抱怨。

另一个有趣的事实是,如果我直接 dir for mailclient.exe,就会发生这种情况:

C:\temp\2>dir mailclient.exe
 Volume in drive C is SSD 840 Pro
 Volume Serial Number is 0C6D-D489

 Directory of C:\temp\2

21.10.2016  17:10        24.742.760 MailClient.exe
               1 File(s)     24.742.760 bytes
               0 Dir(s)  78.501.998.592 bytes free

但是,如果查找 *.exe,则会发生这种情况:

C:\temp\2>dir *.exe
 Volume in drive C is SSD 840 Pro
 Volume Serial Number is 0C6D-D489

 Directory of C:\temp\2

21.10.2016  17:10        24.742.760 MailClient.exe
27.12.2016  03:26        24.911.872 MailCliеnt.exe
               2 File(s)     49.654.632 bytes
               0 Dir(s)  78.501.990.400 bytes free

这也会产生有趣的结果:

C:\temp\2>ren mailclient.exe *.bak

C:\temp\2>dir
 Volume in drive C is SSD 840 Pro
 Volume Serial Number is 0C6D-D489

 Directory of C:\temp\2

13.04.2017  02:50    <DIR>          .
13.04.2017  02:50    <DIR>          ..
21.10.2016  17:10        24.742.760 MailClient.bak
27.12.2016  03:26        24.911.872 MailCliеnt.exe
               2 File(s)     49.654.632 bytes
               2 Dir(s)  78.501.990.400 bytes free

然后返回:

C:\temp\2>ren mailclient.bak MailClient.exe

C:\temp\2>dir
 Volume in drive C is SSD 840 Pro
 Volume Serial Number is 0C6D-D489

 Directory of C:\temp\2

13.04.2017  02:51    <DIR>          .
13.04.2017  02:51    <DIR>          ..
21.10.2016  17:10        24.742.760 MailClient.exe
27.12.2016  03:26        24.911.872 MailCliеnt.exe
               2 File(s)     49.654.632 bytes
               2 Dir(s)  78.501.982.208 bytes free

我还检查了文件的权限并取得了所有权,它没有任何改变。此外,我已经清除了 NTFS 日志,甚至还清除了事务日志 + 运行 chkdsk,这也没有显示任何错误。

对这个神秘的情况有什么想法吗?我错过了什么?

非常感谢:)

更新 #1:

我刚刚尝试过:转到 Windows 资源管理器并通过截断它们的名称来重命名两个文件。所以我首先将第一个“MailClient.exe”重命名为“MailClien.exe”,然后将第二个“MailClient.exe”重命名为“MailClien.exe”。同样,Windows 没有消息表明它们具有相同的名称,只是将两者都重命名了。然后我继续“MailClie.exe”。工作。 但是,一旦我尝试将两者重命名为“MailCli.exe”,Windows 就会抱怨并告诉我已经有另一个具有该名称的文件。尝试将两者从那里重命名为“MailClient.exe”也不起作用,仅适用于其中一个,因为 Windows 说(并且也是如此)具有该名称的文件已经存在。所以似乎归结为“e”可能在两个文件名中都有另一个 ANSI 字符?但是,我不知道“e”还有另一个,还是我遗漏了什么?

【问题讨论】:

  • 最佳猜测:其中一个文件名包含一个 Unicode 字符,看起来与 ANSI 字符相同。
  • 谢谢,根据我的更新#1(通过缓慢截断名称然后重建它的重命名测试),确实是这样。我会再次报告这个:)
  • 我刚刚 posted an answer on Super User 向您展示了一种让您准确查看文件名中的代码点的方法。

标签: windows file duplicates filesystems ntfs


【解决方案1】:

Harry Johnston is right其中一个文件名包含一个 Unicode 字符,它只是看起来与 ANSI 字符相同

阅读Naming Files, Paths, and Namespaces

在较新的文件系统上,例如 NTFS、exFAT、UDFS 和 FAT32,Windows 以 Unicode 将长文件名存储在磁盘上,这意味着 始终保留原始长文件名。这是真的,即使一个 长文件名包含扩展字符,与代码无关 在磁盘读取或写入操作期间处于活动状态的页面。

使用以下 PowerShell 脚本 43381802b.ps1 来检测和显​​示非 ANSI 文件名(请参阅下面的不同调用):

param( [string[]]$Path = '.',
       [switch]$Cpp,  ### list any non-ANSI character in file names like a C++ literal
                      ### i.e. a prefix \u followed by a four digit Unicode code point
       [switch]$All   ### list all files including pure ANSI-encoded file names
      )
Set-StrictMode -Version latest
$strArr = Get-ChildItem -path $Path
$arrDiff = @()
for ($i=0; $i -lt $strArr.Count; $i++) {
    $strDiff = 'ANSI'
    $strName = ''
    $auxName = $strArr[$i].Name
    for (  $k=0; $k -lt $auxName.Length; $k++ ) {
        if ( [int][char]$auxName[$k] -gt 255 ) {
            $strDiff  = 'UCS2'
            $strName += '\u{0:X4}' -f [int][char]$auxName[$k]
        } else { 
            $strName += $auxName[$k]
        }
    }
    if ( $All.IsPresent -or $strDiff -eq 'UCS2' ) { 
        $strArr[$i] | Add-Member NoteProperty Code    $strDiff
        $strArr[$i] | Add-Member NoteProperty CppName $strName
        $arrDiff += $strArr[$i]
    }
}
if ( $Cpp.IsPresent ) {
    $arrDiff | Select-Object -Property Code, Mode, LastWriteTime, Length, CppName | ft
} else {
    $arrDiff | Select-Object -Property Code, Mode, LastWriteTime, Length, Name | ft
}

输出

PS D:\PShell> .\SO\43381802b.ps1 'C:\testC\43381802'

Code Mode   LastWriteTime       Length Name
---- ----   -------------       ------ ----
UCS2 -a---- 02/05/2017 11:47:53    317 MailCliеnt.txt
UCS2 -a---- 02/05/2017 11:49:04    317 МailClient.txt
UCS2 -a---- 02/05/2017 11:50:16    399 МailCliеnt.txt

PS D:\PShell> .\SO\43381802b.ps1 'C:\testC\43381802' -Cpp

Code Mode   LastWriteTime       Length CppName
---- ----   -------------       ------ -------
UCS2 -a---- 02/05/2017 11:47:53    317 MailCli\u0435nt.txt
UCS2 -a---- 02/05/2017 11:49:04    317 \u041CailClient.txt
UCS2 -a---- 02/05/2017 11:50:16    399 \u041CailCli\u0435nt.txt


PS D:\PShell> .\SO\43381802b.ps1 'C:\testC\43381802' -Cpp -All

Code Mode   LastWriteTime       Length CppName
---- ----   -------------       ------ -------
ANSI -a---- 02/05/2017 11:44:05    235 MailClient.txt
UCS2 -a---- 02/05/2017 11:47:53    317 MailCli\u0435nt.txt
UCS2 -a---- 02/05/2017 11:49:04    317 \u041CailClient.txt
UCS2 -a---- 02/05/2017 11:50:16    399 \u041CailCli\u0435nt.txt

使用以下 43381802a.ps1 脚本获取有关非 ANSI 字符的更多信息(参见下面的第一个调用)及其在文件名中的位置(参见后面的带有 -Detail 开关的调用):

param(  [string[]] $strArr = @('ΗGreek', 'НCyril', 'HLatin'),
        [switch]$Detail )
Set-StrictMode -Version latest
$auxArr = @()
if ( ( Get-Command -Name Get-CharInfo -ErrorAction SilentlyContinue ) -and 
     ( -not $Detail.IsPresent ) ) {
    $auxArr = $strArr | Get-CharInfo | 
        Where-Object { [int]$_.Codepoint.Replace('U+', '0x') -ge 128 }
} else {
    foreach ($strStr in $strArr) {
        for ($i = 0; $i -lt $strStr.Length; $i++ ) {
            if ( [int][char]$strStr[$i] -ge  128 ) {
                $auxArr += [PSCustomObject] @{
                    Char        = $strStr[$i]
                    CodePoint   = 'U+{0:x4}' -f [int][char]$strStr[$i]
                    Category    = $i + 1                   ### 1-based index
                    Description = $strStr                  ### string itself
                }
            }
        }
    }
}
$auxArr

输出

PS D:\PShell> .\SO\43381802a.ps1 ( Get-childitem -path 'C:\testC\43381802' ).Name

Char CodePoint        Category Description
---- ---------        -------- -----------
   е U+0435    LowercaseLetter Cyrillic Small Letter Ie
   М U+041C    UppercaseLetter Cyrillic Capital Letter Em
   М U+041C    UppercaseLetter Cyrillic Capital Letter Em
   е U+0435    LowercaseLetter Cyrillic Small Letter Ie


PS D:\PShell> .\SO\43381802a.ps1 ( Get-childitem -path 'C:\testC\43381802' ).Name -detail

Char CodePoint Category Description
---- --------- -------- -----------
   е U+0435           8 MailCliеnt.txt
   М U+041c           1 МailClient.txt
   М U+041c           1 МailCliеnt.txt
   е U+0435           8 МailCliеnt.txt

在文件上测试

==> dir /-C /X /A-D C:\testC\43381802\
 Volume in drive C has no label.
 Volume Serial Number is …

 Directory of C:\testC\43381802

02/05/2017  11:44               235 MAILCL~1.TXT MailClient.txt
02/05/2017  11:47               317 MAILCL~2.TXT MailCliеnt.txt
02/05/2017  11:49               317 AILCLI~1.TXT МailClient.txt
02/05/2017  11:50               399 AILCLI~2.TXT МailCliеnt.txt
               4 File(s)           1268 bytes
               0 Dir(s)     69914857472 bytes free

==> 

【讨论】:

    猜你喜欢
    • 2010-09-10
    • 2016-01-05
    • 2022-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-13
    • 1970-01-01
    相关资源
    最近更新 更多