需要合并 2 个文件夹,每个文件夹中有数十万个文件。 VB.net
Need to merge 2 folders that have hundreds of thousands of files in each. VB.net
我需要合并这些文件夹,每个目录中都有大量文件。我会使用 folder.copy 但这需要很长时间。
我大部分时间都在使用 xcopy 进程来处理这个问题,但我一直收到 xcopy 的错误,说有 none 时有重复项。所以我试图找到一个与 xcopy 一样快甚至更快的可靠解决方案。
我之前试过的是:
Private Sub MergeF(ByVal TargetFolder As String, ByVal MergeeFolder As String)
For Each F As String In IO.Directory.GetFiles(MergeeFolder)
If IO.File.Exists(IO.Path.Combine(TargetFolder, IO.Path.GetFileName(F))) Then
Dim FileA As New IO.FileInfo(IO.Path.Combine(
MergeeFolder, IO.Path.GetFileName(F)))
Dim FileB As New IO.FileInfo(IO.Path.Combine(
TargetFolder, IO.Path.GetFileName(F)))
If FileA.Length <> FileB.Length Then
Dim index As Integer = 1
Do
Dim NewFileName = IO.Path.Combine(TargetFolder,
IO.Path.GetFileName(F.Insert(F.Length - 4, CStr(index))))
If IO.File.Exists(NewFileName) Then
index += 1
Else
IO.File.Copy(F, NewFileName)
IO.File.Delete(F)
Exit Do
End If
Loop
End If
Else
IO.File.Move(IO.Path.Combine(MergeeFolder, IO.Path.GetFileName(F)),
IO.Path.Combine(TargetFolder, IO.Path.GetFileName(F)))
End If
Next
End Sub
https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-copy-directories
异步也应该加快速度;
https://docs.microsoft.com/en-us/dotnet/standard/io/asynchronous-file-i-o
如果这还不够快,那么我认为您的下一个选择是尝试直接使用 win32api
将代码转换为 vb 您可以使用;
https://codeconverter.icsharpcode.net/
要么
https://converter.telerik.com/
- 祝你好运!
您的实现问题在于您在循环内调用 File.Exists
。这会一次又一次地扫描目标目录中的文件并使其变慢。更好的方法是将目标目录中文件的文件名加载到HashSet(Of T)中。此集合中的查找速度非常快 - 比 File.Exists
.
快得多
Private Sub MergeF(ByVal TargetFolder As String, ByVal MergeeFolder As String)
Dim targetFiles = New HashSet(Of String)(
IO.Directory.GetFiles(TargetFolder) _
.Select(Function(f) IO.Path.GetFileName(f)),
StringComparer.OrdinalIgnoreCase)
For Each sourcePath As String In IO.Directory.GetFiles(MergeeFolder)
Dim file As String = IO.Path.GetFileName(sourcePath)
Dim targetPath As String = IO.Path.Combine(TargetFolder, file)
If targetFiles.Contains(file) Then
Dim sourceInfo As New IO.FileInfo(sourcePath)
Dim targetInfo As New IO.FileInfo(targetPath)
If sourceInfo.Length <> targetInfo.Length Then
Dim index As Integer = 1
Do
Dim fileWithoutExt =
Path.GetFileNameWithoutExtension(file)
Dim extension = Path.GetExtension(file)
file = fileWithoutExt & index & extension
If targetFiles.Contains(file) Then
index += 1
Else
targetPath = IO.Path.Combine(TargetFolder, file)
targetFiles.Add(file) 'Upate the HashSet
IO.File.Move(sourcePath, targetPath)
Exit Do
End If
Loop
End If
Else
targetFiles.Add(file) 'Upate the HashSet
IO.File.Move(sourcePath, targetPath)
End If
Next
End Sub
请注意,我还通过使用适当的变量减少了 Path.Combine
和 Path.GetFileName
的数量。我调用了不带目录的文件名 ...File
和完整路径 ...Path
.
我用 StringComparer.OrdinalIgnoreCase
初始化 HashSet
,使其忽略文件名的字符大小写,因为 Windows 文件系统也忽略大小写。
我需要合并这些文件夹,每个目录中都有大量文件。我会使用 folder.copy 但这需要很长时间。
我大部分时间都在使用 xcopy 进程来处理这个问题,但我一直收到 xcopy 的错误,说有 none 时有重复项。所以我试图找到一个与 xcopy 一样快甚至更快的可靠解决方案。
我之前试过的是:
Private Sub MergeF(ByVal TargetFolder As String, ByVal MergeeFolder As String)
For Each F As String In IO.Directory.GetFiles(MergeeFolder)
If IO.File.Exists(IO.Path.Combine(TargetFolder, IO.Path.GetFileName(F))) Then
Dim FileA As New IO.FileInfo(IO.Path.Combine(
MergeeFolder, IO.Path.GetFileName(F)))
Dim FileB As New IO.FileInfo(IO.Path.Combine(
TargetFolder, IO.Path.GetFileName(F)))
If FileA.Length <> FileB.Length Then
Dim index As Integer = 1
Do
Dim NewFileName = IO.Path.Combine(TargetFolder,
IO.Path.GetFileName(F.Insert(F.Length - 4, CStr(index))))
If IO.File.Exists(NewFileName) Then
index += 1
Else
IO.File.Copy(F, NewFileName)
IO.File.Delete(F)
Exit Do
End If
Loop
End If
Else
IO.File.Move(IO.Path.Combine(MergeeFolder, IO.Path.GetFileName(F)),
IO.Path.Combine(TargetFolder, IO.Path.GetFileName(F)))
End If
Next
End Sub
https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-copy-directories
异步也应该加快速度;
https://docs.microsoft.com/en-us/dotnet/standard/io/asynchronous-file-i-o
如果这还不够快,那么我认为您的下一个选择是尝试直接使用 win32api
将代码转换为 vb 您可以使用;
https://codeconverter.icsharpcode.net/ 要么 https://converter.telerik.com/
- 祝你好运!
您的实现问题在于您在循环内调用 File.Exists
。这会一次又一次地扫描目标目录中的文件并使其变慢。更好的方法是将目标目录中文件的文件名加载到HashSet(Of T)中。此集合中的查找速度非常快 - 比 File.Exists
.
Private Sub MergeF(ByVal TargetFolder As String, ByVal MergeeFolder As String)
Dim targetFiles = New HashSet(Of String)(
IO.Directory.GetFiles(TargetFolder) _
.Select(Function(f) IO.Path.GetFileName(f)),
StringComparer.OrdinalIgnoreCase)
For Each sourcePath As String In IO.Directory.GetFiles(MergeeFolder)
Dim file As String = IO.Path.GetFileName(sourcePath)
Dim targetPath As String = IO.Path.Combine(TargetFolder, file)
If targetFiles.Contains(file) Then
Dim sourceInfo As New IO.FileInfo(sourcePath)
Dim targetInfo As New IO.FileInfo(targetPath)
If sourceInfo.Length <> targetInfo.Length Then
Dim index As Integer = 1
Do
Dim fileWithoutExt =
Path.GetFileNameWithoutExtension(file)
Dim extension = Path.GetExtension(file)
file = fileWithoutExt & index & extension
If targetFiles.Contains(file) Then
index += 1
Else
targetPath = IO.Path.Combine(TargetFolder, file)
targetFiles.Add(file) 'Upate the HashSet
IO.File.Move(sourcePath, targetPath)
Exit Do
End If
Loop
End If
Else
targetFiles.Add(file) 'Upate the HashSet
IO.File.Move(sourcePath, targetPath)
End If
Next
End Sub
请注意,我还通过使用适当的变量减少了 Path.Combine
和 Path.GetFileName
的数量。我调用了不带目录的文件名 ...File
和完整路径 ...Path
.
我用 StringComparer.OrdinalIgnoreCase
初始化 HashSet
,使其忽略文件名的字符大小写,因为 Windows 文件系统也忽略大小写。