
Учитывая два каталога (DirA и DirB), какой наиболее эффективный способ найти список файлов, которые существуют в DirA, но не существуют в DirB?
Я попытался сделать это с помощью jdupes.exe --printunique --recurse -O
инструмента, однако это имеет побочный эффект в виде исключения файла, соответствующего вышеуказанным критериям, если в DirA существуют дубликаты указанного файла.
Файлы могут находиться в совершенно разных подкаталогах DirA и DirB и иметь разные имена. Поэтому содержимое файла является единственной устойчивой характеристикой.
решение1
Струны вернулись изPowerShell'sПолучить-FileHashмогут быть использованы в качестве ключей кхеш-таблицадля связывания содержимого с полностью определенным путем. Этот код создает хеш-таблицу для каждого пути со следующими оговорками.
- Пустые файлы игнорируются, поскольку хэш содержимого всех пустых файлов будет идентичен. (Вы также можете создать список пустых файлов, найденных в каждом каталоге)
- Если дубликаты найденыв пределахкаталог, который мы индексируем, только первый найденный файл будет добавлен в
$HashOut
таблицу.$Dups
Таблица будет содержать список всех путей, которые разделяют идентичный контент.
PowerShell:
Function Get-DirHash ( [String]$PathIn , [PSObject]$HashOut )
{
$HashOut.Clear()
gci $PathIn *.txt -Recurse | ? Length -gt 0 | Get-FileHash | %{
If ( $HashOut.Contains($_.Hash) )
{
If ( $Dups.Contains($_.Hash) )
{
$Dups[$_.Hash] += $_.Path
}
Else
{
$Dups.Add( $_.Hash , @( $HashOut[$_.Hash] , $_.Path ))
}
}
Else
{
$HashOut.Add( $_.Hash , $_.Path )
}
}
}
$DirA = 'c:\whatever'
$DirB = 'c:\whenever'
$TableA = @{}
$TableB = @{}
$Dups = @{}
$Unique2A = New-Object System.Collections.Generic.List[String]
Get-DirHash -PathIn $DirA -HashOut $TableA
Get-DirHash -PathIn $DirB -HashOut $TableB
$TableA.Keys | %{
If ( ! ( $TableB.Contains($_) ))
{
$Unique2A.Add( $TableA[$_] )
}
}
$Unique2A | Out-GridView
Полностью не протестировано, но я считаю, что это позволит вычислить хэш только для файлов, которые совпадают по размеру.
$DirA = 'c:\whatever'
$DirB = 'c:\whenever'
$TestA = [Regex]::Escape($DirA)
$MasterList = gci $DirA , $DirB -Filter *.txt -recurse | Group Length
$Unique2A_BySize = ( $MasterList | ? Count -eq 1 |
? { $_.Group[0].DirectoryName -match $TestA } ).Group.FullName
$Unique2A_ByHash = ( $MasterLIst | ? Count -gt 1 | %{
$_.Group | Get-FileHash | Group Hash |
? Count -eq 1 |
? { $_.Group[0].Path -match $TestA }
} ).Group.Path
( $Unique2A = $Unique2A_BySize + $Unique2A_ByHash ) | Out-GridView
Который может быть улучшен за счет более трудного для чтения:
$DirA = 'c:\whatever'
$DirB = 'c:\whenever'
$TestA = [Regex]::Escape($DirA)
$Unique2A = ( ( $MasterList = gci $DirA , $DirB -Filter *.txt -recurse | Group Length ) |
? Count -eq 1 |
? { $_.Group[0].DirectoryName -match $TestA } ).Group.FullName +
( $MasterLIst | ? Count -gt 1 | %{
$_.Group | Get-FileHash | Group Hash |
? Count -eq 1 |
? { $_.Group[0].Path -match $TestA }
} ).Group.Path
$Unique2A | Out-GridView
решение2
Я бы скопировал списки каталогов в Excel и использовал функцию UNIQUE