📄 filecopy.vb
字号:
'==========================================================================
'
' File: FileCopy.vb
' Location: FileCopier <Visual Basic .Net>
' Description: 文件复制模块
' Version: 2007.07.28.
' Copyright(C) F.R.C.
'
'==========================================================================
Option Compare Text
Imports System
Imports System.Math
Imports System.Collections.Generic
Imports System.IO
Imports System.Data
Public Class FileCopy
#Region " 选项和参数 "
Enum SameFileIdentifierOption
Path = 1
First64K = 2
FullFile = 4
CorrectWriteTimeOffsetIn2s = 8
End Enum
Enum CreateTimeAndCharCaseHandlingOption
Source
Target
Earlier
End Enum
Enum DifferentFileHandlingOption
Backup
CopyNew
End Enum
Public SameFileIdentifier As SameFileIdentifierOption
Public CreateTimeAndCharCaseHandling As CreateTimeAndCharCaseHandlingOption
Public DifferentFileHandling As DifferentFileHandlingOption
Public PreserveDeleted As Boolean
Sub SetFileCopyOption(ByVal SameFileIdentifier As SameFileIdentifierOption, ByVal CreateTimeAndCharCaseHandling As CreateTimeAndCharCaseHandlingOption, ByVal DifferentFileHandling As DifferentFileHandlingOption, ByVal PreserveDeleted As Boolean)
Me.SameFileIdentifier = SameFileIdentifier
Me.CreateTimeAndCharCaseHandling = CreateTimeAndCharCaseHandling
Me.DifferentFileHandling = DifferentFileHandling
Me.PreserveDeleted = PreserveDeleted
End Sub
Public SourceDir As String
Public TargetDir As String
Public NewDir As String
Public BackupDir As String
Public ExceptionalDir As String
Public LogPath As String
Public Filters As String()
Sub SetFileCopyParameter(ByVal SourceDir As String, ByVal TargetDir As String, ByVal NewDir As String, ByVal BackupDir As String, ByVal ExceptionalDir As String, ByVal LogPath As String, ByVal Filters As String())
Me.SourceDir = SourceDir
Me.TargetDir = TargetDir
Me.NewDir = NewDir
Me.BackupDir = BackupDir
Me.ExceptionalDir = ExceptionalDir
Me.LogPath = LogPath
Me.Filters = Filters
End Sub
Protected LogFile As StreamWriter
Sub LogOpen(ByVal Append As Boolean)
If LogPath = "" Then Return
If Not IO.Directory.Exists(GetFileDirectory(LogPath)) Then IO.Directory.CreateDirectory(GetFileDirectory(LogPath))
LogFile = New StreamWriter(LogPath, Append, Text.Encoding.Default)
End Sub
Sub LogWriteLine()
If Not LogFile Is Nothing Then LogFile.WriteLine()
End Sub
Sub LogWriteLine(ByVal s As String)
If Not LogFile Is Nothing Then LogFile.WriteLine(s)
End Sub
Sub LogWriteLine(ByVal s As String, ByVal arg0 As Object)
If Not LogFile Is Nothing Then LogFile.WriteLine(s, arg0)
End Sub
Sub LogWriteLine(ByVal s As String, ByVal arg0 As Object, ByVal arg1 As Object)
If Not LogFile Is Nothing Then LogFile.WriteLine(s, arg0, arg1)
End Sub
Sub LogWrite(ByVal s As String)
If Not LogFile Is Nothing Then LogFile.Write(s)
End Sub
Sub LogWrite(ByVal s As String, ByVal arg0 As Object)
If Not LogFile Is Nothing Then LogFile.Write(s, arg0)
End Sub
Sub LogWrite(ByVal s As String, ByVal arg0 As Object, ByVal arg1 As Object)
If Not LogFile Is Nothing Then LogFile.Write(s, arg0, arg1)
End Sub
Sub LogClose()
If Not LogFile Is Nothing Then LogFile.Close()
End Sub
#End Region
Protected MappingTable As List(Of ActionFile)
Protected MappingTableDirs As List(Of ActionDir)
Public Delegate Sub ProgressEventHandler(ByVal Value As Double, ByVal Status As String)
#Region " 可行性分析 "
Sub AnalyzeFeasibility(ByVal PreCopyCmds As String(), ByRef Output As String, Optional ByVal ChangeProgress As ProgressEventHandler = Nothing)
#If CONFIG <> "Debug" Then
Try
#End If
LogOpen(False)
LogWriteLine("----------------")
LogWriteLine(DateAndTime.Now & " " & TimeZone.CurrentTimeZone.GetUtcOffset(DateAndTime.Now).TotalHours.ToString("+##.#;-##.#"))
LogWriteLine("------PreCopy批处理------")
Dim PreCopyResult As String = ExecuteCmds("PreCopy.cmd", PreCopyCmds)
Output = "------PreCopy批处理------" & Environment.NewLine & PreCopyResult
Application.DoEvents()
LogWriteLine("------可行性报告------")
If SourceDir = "" Then Throw New InvalidDataException("源文件夹路径不正确。")
If Not Directory.Exists(SourceDir) Then Throw New InvalidDataException("源文件夹不存在。")
LogWriteLine("源文件夹 {0}", SourceDir)
If TargetDir = "" Then Throw New InvalidDataException("目标文件夹路径不正确。")
If Not Directory.Exists(TargetDir) Then Directory.CreateDirectory(TargetDir)
LogWriteLine("目标文件夹 {0}", TargetDir)
If DifferentFileHandling = DifferentFileHandlingOption.Backup Then
If BackupDir = "" Then Throw New InvalidDataException("备份文件夹路径不正确。")
If Not Directory.Exists(BackupDir) Then Directory.CreateDirectory(BackupDir)
LogWriteLine("备份文件夹 {0}", BackupDir)
If ExceptionalDir = "" Then Throw New InvalidDataException("异常文件夹路径不正确。")
If Not Directory.Exists(ExceptionalDir) Then Directory.CreateDirectory(ExceptionalDir)
LogWriteLine("异常文件夹 {0}", ExceptionalDir)
Else 'If DifferentFileHandling = DifferentFileHandlingOption.CopyNew Then
If NewDir = "" Then Throw New InvalidDataException("更新文件夹路径不正确。")
If Not Directory.Exists(NewDir) Then Directory.CreateDirectory(NewDir)
LogWriteLine("更新文件夹 {0}", NewDir)
End If
LogWriteLine()
GenerateDataTable(ChangeProgress)
LogWriteLine("------文件映射表------")
GenerateMappingTable(ChangeProgress)
Dim s As New Text.StringBuilder
s.AppendLine("------可行性报告------")
If CalculateDiskSpace(s) Then
s.AppendLine()
s.AppendLine("可行")
Else
s.AppendLine()
s.AppendLine("不可行")
End If
s.AppendLine()
s.AppendLine("请自行确保所有需要写操作的磁盘可写。")
s.AppendLine()
s.AppendLine("请自行确保所有涉及的文件的句柄已经释放。")
s.AppendLine("可使用Unlocker之类的软件确认。")
s.AppendLine()
s.AppendLine("请关掉杀毒软件,防止杀毒软件删除文件导致错误。")
LogWriteLine(s.ToString)
LogWriteLine("----------------")
LogClose()
Output = PreCopyResult & s.ToString
Application.DoEvents()
#If CONFIG <> "Debug" Then
Catch ex As Exception
LogWriteLine()
LogWriteLine(ex.ToString)
LogClose()
Throw
End Try
#End If
End Sub
#Region " 生成文件数据表及文件映射表 "
Protected SourceDirs As DataTable
Protected TargetDirs As DataTable
Protected Source As DataTable
Protected Target As DataTable
Protected Sub GenerateDataTable(Optional ByVal ChangeProgress As ProgressEventHandler = Nothing)
SourceDirs = New DataTable()
SourceDirs.CaseSensitive = False
SourceDirs.Columns.Add("Name", GetType(System.String))
SourceDirs.Columns.Add("Path", GetType(System.String))
SourceDirs.PrimaryKey = New DataColumn() {SourceDirs.Columns("Path")}
TargetDirs = New DataTable()
TargetDirs.CaseSensitive = False
TargetDirs.Columns.Add("Name", GetType(System.String))
TargetDirs.Columns.Add("Path", GetType(System.String))
TargetDirs.PrimaryKey = New DataColumn() {TargetDirs.Columns("Path")}
Source = New DataTable()
Source.CaseSensitive = False
Source.Columns.Add("Name", GetType(System.String))
Source.Columns.Add("Length", GetType(System.Int64))
Source.Columns.Add("WriteTime", GetType(System.Int64))
Source.Columns.Add("Path", GetType(System.String))
Source.PrimaryKey = New DataColumn() {Source.Columns("Path")}
Target = New DataTable()
Target.CaseSensitive = False
Target.Columns.Add("Name", GetType(System.String))
Target.Columns.Add("Length", GetType(System.Int64))
Target.Columns.Add("WriteTime", GetType(System.Int64))
Target.Columns.Add("Path", GetType(System.String))
Target.PrimaryKey = New DataColumn() {Target.Columns("Path")}
If ChangeProgress IsNot Nothing Then ChangeProgress(0, "生成文件信息表(1/2)")
AddDirToSourceDirs(SourceDir)
If ChangeProgress IsNot Nothing Then ChangeProgress(0.05, Nothing)
AddDirToTargetDirs(TargetDir)
If ChangeProgress IsNot Nothing Then ChangeProgress(0.1, Nothing)
AddDirToSource(SourceDir)
If ChangeProgress IsNot Nothing Then ChangeProgress(0.55, Nothing)
AddDirToTarget(TargetDir)
If ChangeProgress IsNot Nothing Then ChangeProgress(1, Nothing)
End Sub
Protected Sub GenerateMappingTable(Optional ByVal ChangeProgress As ProgressEventHandler = Nothing)
'按照相同文件、已修改文件、异常文件、删除文件、更新文件的顺序排列映射表
'可以使得目标文件的空间使用先减小后增大
'在同一路径已有不同文件的情况下不再寻找相同文件,避免路径冲突
Dim DIVer As Integer = Source.Rows.Count + Target.Rows.Count
Dim DIVee As Integer = 0
If ChangeProgress IsNot Nothing Then ChangeProgress(0, "生成文件映射表(2/2)")
MappingTable = New List(Of ActionFile)
Dim a As ActionFile
Dim n As Integer = 0
While n < Source.Rows.Count
Dim s As DataRow = Source.Rows(n)
Dim Selected As DataRow() = Target.Select(String.Format("Path = '{0}'", Escape(s("Path"))))
If Selected Is Nothing OrElse Selected.Length = 0 Then
n += 1
Continue While
End If
If Selected.Length = 1 Then
Dim t As DataRow = Selected(0)
If IsSameFile(s, t) Then
a = New ActionFile(s, t, ActionTypeEnum.Same)
LogWriteLine("Same {0} -> {1}", a.Source.Path, a.Target.Path)
MappingTable.Add(a)
Else
If DateTime.FromBinary(s.Item("WriteTime")) > DateTime.FromBinary(t.Item("WriteTime")) Then
a = New ActionFile(s, t, ActionTypeEnum.Refresh)
LogWriteLine("Refresh {0} -> {1}", a.Source.Path, a.Target.Path)
MappingTable.Add(a)
Else
a = New ActionFile(s, t, ActionTypeEnum.Revert)
LogWriteLine("Revert {0} -> {1}", a.Source.Path, a.Target.Path)
MappingTable.Add(a)
End If
End If
Source.Rows.Remove(s)
Target.Rows.Remove(t)
If ChangeProgress IsNot Nothing Then
DIVee += 2
ChangeProgress(DIVee / DIVer, Nothing)
End If
Else
Throw New InvalidOperationException
End If
End While
If Not (SameFileIdentifier And SameFileIdentifierOption.Path) Then
n = 0
While n < Source.Rows.Count
Dim s As DataRow = Source.Rows(n)
Dim Selected As DataRow() = Target.Select(String.Format("Name = '{0}' AND Length = {1}", Escape(s("Name")), s("Length")))
If Selected Is Nothing OrElse Selected.Length = 0 Then
n += 1
Continue While
End If
Dim t As DataRow = GetBestFitted(s, Selected) '极端情况下可能遗漏真正符合的
If IsSameFile(s, t) Then
a = New ActionFile(s, t, ActionTypeEnum.Same)
LogWriteLine("Same {0} -> {1}", a.Source.Path, a.Target.Path)
MappingTable.Add(a)
Source.Rows.Remove(s)
Target.Rows.Remove(t)
If ChangeProgress IsNot Nothing Then
DIVee += 2
ChangeProgress(DIVee / DIVer, Nothing)
End If
Else
n += 1
End If
End While
End If
If Not PreserveDeleted Then
For Each t As DataRow In Target.Rows
a = New ActionFile(Nothing, t, ActionTypeEnum.Delete)
LogWriteLine("Delete NULL -> {0}", a.Target.Path)
MappingTable.Add(a)
If ChangeProgress IsNot Nothing Then
DIVee += 1
ChangeProgress(DIVee / DIVer, Nothing)
End If
Next
End If
For Each s As DataRow In Source.Rows
a = New ActionFile(s, Nothing, ActionTypeEnum.Create)
LogWriteLine("Create {0} -> NULL", a.Source.Path)
MappingTable.Add(a)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -