目录
使用powershell工具,查找多个文件夹里的重复文件。不同指令及其效果展示,根据需要的效果选择使用对应方法。
前面是成品的方法,根据效果选择代码,代码复制即可用。
最后的总结和代码解释,可以根据需要调整代码。
powershell终端直接输入指令的方法
输出结果简陋
打开powershell终端,直接输入
Get-ChildItem -Path C:\222, D:\111 -Recurse | Group-Object -Property Name | Where-Object { $_.Count -gt 1 }
-Path的参数“ C:\222, D:\111 ”根据自己需要修改自己需要查找的文件夹。
结果输出在终端界面,输出效果:
Count Name Group
----- ---- -----
4 1.docx {1.docx, 1.docx, 1.docx, 1.docx}
3 1.pptx {1.pptx, 1.pptx, 1.pptx}
路径可以改为中文路径 ,即“ C:\222”等路径中可以包含中文字符。
输出结果完整
打开powershell终端,直接输入
Get-ChildItem -Path C:\222, D:\111 -Recurse | Group-Object -Property Name | Where-Object { $_.Count -gt 1 }| Select-Object -ExpandProperty Group | Select-Object FullName, Length, CreationTime, LastWriteTime
-Path的参数“ C:\222, D:\111 ”根据自己需要修改自己需要查找的文件夹。
结果输出在终端界面,输出效果:
FullName Length CreationTime LastWriteTime
-------- ------ ------------ -------------
C:\222\1.docx 12175 2023/5/15 19:01:13 2023/5/15 16:41:39
D:\111\1.docx 12175 2023/5/15 16:39:09 2023/5/15 16:41:39
D:\111\新建文件夹\1.docx 0 2023/5/15 16:39:44 2023/5/15 16:39:09
D:\111\新建文件夹\新建文件夹 (2)\1.docx 0 2023/5/15 16:39:53 2023/5/15 16:39:09
C:\222\1.pptx 0 2023/5/15 19:01:13 2023/5/15 16:39:37
D:\111\1.pptx 0 2023/5/15 16:39:37 2023/5/15 16:39:37
D:\111\新建文件夹\1.pptx 0 2023/5/15 16:39:44 2023/5/15 16:39:37
编写、执行.ps1文件的方法
编写、执行.ps1文件的方法可以实现复杂效果。
分类输出结果
在C:\222,D:\111两个文件夹查找:
新建文本文档,输入如下内容:
$folderspath = "C:\222", "D:\111"
$files = Get-ChildItem -Path $folderspath -Recurse | Where-Object { !$_.PSIsContainer }
$groups = $files | Group-Object -Property Name | Where-Object { $_.Count -gt 1 }
foreach ($group in $groups) {
$group.Group | Select-Object FullName, Length, CreationTime | Sort-Object FullName | Format-Table -AutoSize
}
$folderspath = "C:\222", "D:\111"根据情况修改。
保存为“.ps1”为后缀的文件,如“111.ps1”。在powershell中输入“ .\111.ps1”执行该文件。
效果:
.\12.ps1
FullName Length CreationTime
-------- ------ ------------
C:\222\1.docx 12175 2023/5/15 17:28:00
D:\111\1.docx 12175 2023/5/15 16:39:09
D:\111\新建文件夹\1.docx 0 2023/5/15 16:39:44
D:\111\新建文件夹\新建文件夹 (2)\1.docx 0 2023/5/15 16:39:53FullName Length CreationTime
-------- ------ ------------
C:\222\1.pptx 0 2023/5/15 17:23:57
D:\111\1.pptx 0 2023/5/15 16:39:37
D:\111\新建文件夹\1.pptx 0 2023/5/15 16:39:44
根据文件名、长度、拓展名查找
修改“ Group-Object -Property”参数,设置为所需的内容:
$folderspath = "C:\222", "D:\111"
$files = Get-ChildItem -Path $folderspath -Recurse | Where-Object { !$_.PSIsContainer }
$groups = $files | Group-Object -Property Length, Name, Extension | Where-Object { $_.Count -gt 1 }
foreach ($group in $groups) {
$group.Group | Select-Object FullName, Length, CreationTime | Sort-Object FullName | Format-Table -AutoSize
}
效果
FullName Length CreationTime
-------- ------ ------------
C:\222\1.docx 12175 2023/5/15 19:01:13
D:\111\1.docx 12175 2023/5/15 16:39:09FullName Length CreationTime
-------- ------ ------------
C:\222\1.pptx 0 2023/5/15 19:01:13
D:\111\1.pptx 0 2023/5/15 16:39:37
D:\111\新建文件夹\1.pptx 0 2023/5/15 16:39:44
根据MD5值查找
根据文件的MD5值来查找相同文件
$folderspath = "C:\222", "D:\111"
$files = Get-ChildItem -Path $folderspath -Recurse | Where-Object { !$_.PSIsContainer }
$md5s = $files | ForEach-Object { Get-FileHash $_.FullName | Select-Object -ExpandProperty Hash }
$groups = $files | Group-Object -Property @{ Expression={$md5s[$files.IndexOf($_)]} } | Where-Object { $_.Count -gt 1 }
foreach ($group in $groups) {
Write-Output "以下是 MD5 值为 $($group.Name) 的文件:"
foreach ($item in $group.Group) {
Write-Output $item.FullName
}
Write-Output "---------------------------------------------------------------`n"
}
这段代码首先使用 Get-ChildItem
获取指定路径下的所有文件,再用 Get-FileHash
计算每个文件的 MD5 值,并保存到 $md5s
变量中。
接着,使用 Group-Object
按照 MD5 值分组,并筛选出组内文件数大于1的组。最后,使用 foreach
循环每个组,输出该组中的文件完整路径和文件名,并在每两个组之间输出空行。
输出效果:
以下是 MD5 值为 23C2732778B8A5BFAD00AEA036D8F614430822C40E69A511E1E7AA5F4535B753 的文件:
C:\222\1.docx
D:\111\1.docx
---------------------------------------------------------------以下是 MD5 值为 E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 的文件:
C:\222\1.pptx
C:\222\1.txt
D:\111\1.pptx
D:\111\1.txt
D:\111\新建文件夹\1.pptx
D:\111\新建文件夹\新建文件夹 (2)\1.docx
---------------------------------------------------------------
可以看出,文件按照MD5值被查找出相同文件。
笔者实验发现,由同一文件复制出的文件,他们之间的MD5值是相同的,会被认为是重复文件。而如果复制出的文件被修改,其MD5值改变,不再被认为是重复文件。
另外,空文件的MD5值相同,如上例中最后的六个文件,都是空文件,被认为是重复文件。
MD5(Message Digest Algorithm 5)是一种常用的单向散列函数,也被称为消息摘要算法。它将任意长度的“消息”(例如文件内容或数据流)计算为固定长度的数字指纹,通常是128位(16个字节)的二进制数。
MD5 算法广泛应用于可验证数据完整性和加密签名等领域。常见的应用包括密码学、数字证书、文件校验和、安全传输等。通过比较两个文件的 MD5 值,可以判断它们的内容是否完全一致,如果不同则说明文件已被篡改或损坏。
需要注意的是,由于 MD5 算法存在碰撞(collision)漏洞,即可以构造出两个不同的消息,它们的 MD5 值却相同。因此,随着计算能力的提升,MD5 算法已经逐渐被更安全的算法所替代,如SHA-256、SHA-3等。
空文件的 MD5 值和非空文件不同。MD5 算法是通过将文件内容作为输入,并生成一个 128 位的散列值作为输出的一种算法。因此,文件大小、文件类型以及文件名等不同的因素都会影响 MD5 值的计算结果。
但是,对于多个空文件来说,它们的 MD5 值是相等的。这是因为空文件的内容都是相同的,都是一个字节都没有。因此,它们的 MD5 计算结果也都是相同的。
将结果写入文件中
结果太长一次看不完,可以保存在文本文件中以后再看。
保存方法是使用“$output”保存。
$OutputEncoding = [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$folderspath = "C:\222", "D:\111"
$files = Get-ChildItem -Path $folderspath -Recurse | Group-Object -Property Length,Name | Where-Object { $_.Count -gt 1 }
foreach ($file in $files) {
$output = "Duplicate file name: $($file.Name)`r`n"
foreach ($item in $file.Group) {
$output += "`tPath+File Name: $($item.FullName)`r`n"
}
$output += ('-'*80) + "`r`n"
$output | Out-File -FilePath .\11.txt -Append -Encoding UTF8
}
输出结果保存在.\11.txt中,文件内容:
Duplicate file name: 12175, 1.docx
Path+File Name: C:\222\1.docx
Path+File Name: D:\111\1.docx
--------------------------------------------------------------------------------Duplicate file name: 0, 1.pptx
Path+File Name: C:\222\1.pptx
Path+File Name: D:\111\1.pptx
Path+File Name: D:\111\新建文件夹\1.pptx
--------------------------------------------------------------------------------
先构建变量$output,再将$output输出到文件中。
代码解释(不重要,建议跳过)
GPT给出的相关代码解释:
好的,下面是每个参数的含义:
```powershell
$files = Get-ChildItem -Path "C:\your\folder" -Recurse | Where-Object { !$_.PSIsContainer }
```- `Get-ChildItem`:获取指定目录中的文件和子目录的列表。
- `-Path "C:\your\folder"`:指定要搜索的文件夹路径。可以在引号中替换为您想要搜索的文件夹的完整路径。
- `-Recurse`:递归地返回文件夹层次结构中的所有文件和文件夹。
- `Where-Object { !$_.PSIsContainer }`:使用条件筛选出不是文件夹的对象。您可以将其视为一个过滤器,只返回不是文件夹的项目。```powershell
$md5s = $files | ForEach-Object { Get-FileHash $_.FullName | Select-Object -ExpandProperty Hash }
```- `$files`:之前从文件夹中筛选出的所有文件对象的列表。
- `ForEach-Object`:对于 `$files` 列表中的每个元素,执行后续操作。
- `Get-FileHash`:计算指定文件的哈希值。在这里,我们使用 MD5 哈希算法来计算每个文件的哈希值。
- `Select-Object`:选择通过管道传递的对象的属性或其他数据。在这里,我们只需要哈希值。
- `-ExpandProperty Hash`:展开哈希值属性,方便后面的分组使用。```powershell
$files | Group-Object -Property @{ Expression={$md5s[$files.IndexOf($_)]} } | Where-Object { $_.Count -gt 1 }
```- `$files`:之前从文件夹中筛选出的所有文件对象的列表。
- `Group-Object`:按照指定属性值对输入对象进行分组。
- `-Property @{ Expression={$md5s[$files.IndexOf($_)]} }`:指定用于分组的属性名称。表达式 `@{ Expression={$md5s[$files.IndexOf($_)]} }` 将对 `$files` 列表中每个元素执行索引计算,以获取它的哈希值。
- `Where-Object { $_.Count -gt 1 }`:筛选出重复文件的分组。只有元素数量大于1的分组才会被保留。```powershell
foreach ($group in $groups) {
$group.Group | Select-Object FullName, Length, CreationTime | Sort-Object FullName | Format-Table -AutoSize
}
```- `foreach`:对于 `$groups` 列表中的每个元素,执行后续操作。
- `$group`:当前循环迭代中的分组对象。
- `$group.Group`:当前循环迭代中分组对象中的重复文件列表。
- `Select-Object FullName, Length, CreationTime`:选择要输出到控制台的文件属性。在这里,我们选择输出文件的完整路径、大小和创建时间。
- `Sort-Object FullName`:按照文件名的字母顺序对输出结果进行排序。
- `Format-Table -AutoSize`:格式化输出结果并自动调整列宽至合适的大小。`Where-Object { !$_.PSIsContainer }` 是一个 PowerShell 中管道符 `|` 后的过滤器,用于从输出结果中筛选出不是目录(文件夹)的项。
在此处,`Get-ChildItem -Path "D:\111" -Recurse` 命令用于获取指定路径下的所有子项,包括文件和文件夹。使用 `Where-Object` 过滤器可以对子项进行筛选,其中 `$_.PSIsContainer` 是一个布尔值属性,如果为 `$true`,则表示该项是一个目录,反之则为文件。因此,`!$_.PSIsContainer` 表达式的含义是取反后为 `$true` 的项即为非目录(文件)项,即只保留文件类型的子项。
这样做的目的是使得 `$files` 变量只包含指定目录下的文件信息,方便后续计算 MD5 值并按照值进行分组。
希望这样可以让您更好地理解代码!
报错
powershell运行指令,常出现的报错及处理参见:
Windows系统powershell运行指令常见报错及处理_weixin_56337147的博客-CSDN博客
总结
powershell终端直接输入指令的方法适合一行指令,操作较简单。编写、执行.ps1文件的方法可以实现复杂效果,但是二者代码意义相同。各代码的意义如下:
Get-ChildItem -Path $folderspath -Recurse:获取$folderspath路径内的的文件,-Recurse参数用来递归地返回文件夹层次结构中的所有文件和文件夹。
Where-Object { !$_.PSIsContainer }:筛选出不是文件夹的项目。有这个步骤的是查找重复文件,没有这个步骤的话既查找重复文件,又查找重复文件夹。
Group-Object -Property Name:将获取的文件按照“Name”分组,分组标准“Name”可以替换为其他,比如按照名称、长度、拓展名分组可以设置为“Length, Name, Extension",这种分组查重效果比较好。
Where-Object { $_.Count -gt 1 }:筛选出重复文件的分组。“ $_.Count -gt 1”表示只有元素数量大于1的分组才会被保留。“gt”表示“大于”。如果想要重复文件数量大于2的分组就设置成“ $_.Count -gt 2”。
foreach ($file in $files) {:对于 `$files` 列表中的每个元素,执行后续操作。
$output | Out-File -FilePath .\11.txt -Append -Encoding UTF8 :Out-File输出文件,将前面构建好的变量“$output ”输出,“ -FilePath .\11.txt ”文件路径是.\11.txt,保存方式是“-Append”追加保存,文本格式是“ -Encoding UTF8”。