ファイルのバックアップ

自分で使うようにファイルのバックアップをとるプログラム書いてみた。あまりテストしてないので消すかも

Imports System.IO

''' <summary>
''' ファイルを簡単にバックアップ、リストアするためのクラス
''' ファイル、ディレクトリともに利用可能
'''
''' バックアップされたファイルは以下の形式で名前が付けられる
''' [元のファイル名と拡張子].backup[yyyyMMdd]_[HHmm]_[ID3桁]
''' 例えば「sample.txt」というファイルをバックアップした場合
''' 「sample.txt.backup20130702_2359_001」というファイル名になる。
''' ディレクトリの場合も同様。
''' </summary>
''' <remarks></remarks>
Public Class Backupper

    Sub New()
    End Sub

    Private ReadOnly BackupFileExpression As String = "^.backup20[0-9]{2}[01][0-9][0-3][0-9]_[0-2][0-9][0-5][0-9]_[0-9]{3}"

#Region "Public"

    ''' <summary>
    ''' 現在のディレクトリにバックアップファイルを作成
    ''' </summary>
    ''' <param name="path"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Backup(ByVal path As String) As String
        If path Is Nothing Then Throw New ArgumentNullException()
        Return Backup(path, IO.Path.GetDirectoryName(path))

    End Function

    ''' <summary>
    ''' 指定したディレクトリにバックアップファイルを作成
    ''' </summary>
    ''' <param name="path"></param>
    ''' <param name="destDir"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Backup(ByVal path As String, ByVal destDir As String) As String
        If path Is Nothing Then Throw New ArgumentNullException("path")

        Dim manager As FileOrDirManager
        Try
            manager = FileOrDirManager.Create(path)
        Catch ex As ArgumentException
            Throw ex
            Return Nothing
        End Try

        If destDir Is Nothing OrElse Not IO.Directory.Exists(destDir) Then
            Throw New ArgumentNullException("destDir")
        End If

        Dim target As String = GenerateFileName(manager, path, destDir)
        If manager.Copy(path, target) Then
            Return target
        Else
            Return Nothing
        End If
    End Function

    ''' <summary>
    ''' バックアップファイルから復元
    ''' </summary>
    ''' <param name="path"></param>
    ''' <remarks></remarks>
    Public Sub Restore(ByVal path As String)
        If path Is Nothing Then Throw New ArgumentNullException("path = Nothing")

        Dim manager As FileOrDirManager = FileOrDirManager.Create(path)

        Dim parentDirPath As String = IO.Path.GetDirectoryName(path)
        Dim nameWithoutExtension As String = IO.Path.GetFileNameWithoutExtension(path)
        Dim extension As String = IO.Path.GetExtension(path)

        If Not System.Text.RegularExpressions.Regex.IsMatch(extension, BackupFileExpression) Then
            MsgBox("指定されたパスはバックアップファイルではありません。")
            Return
        End If

        Dim targetPath As String = IO.Path.Combine(parentDirPath, nameWithoutExtension)

        '出力したい場所に既存のファイルがあるか
        If manager.IsExist(targetPath) Then
            '有るならそのファイルをバックアップファイルにする
            Dim backupFile As String = GenerateFileName(manager, targetPath, IO.Path.GetDirectoryName(targetPath))
            If String.IsNullOrEmpty(backupFile) Then Throw New InvalidOperationException
            manager.Move(targetPath, backupFile)
            MsgBox("ディレクトリ '" & targetPath & "'は既に存在するため、バックアップファイル '" & backupFile & "'として移動しました")
        End If

        manager.Copy(path, targetPath)

    End Sub


#End Region

#Region "Private"

    ''' <summary>
    ''' ファイル名を決定
    ''' </summary>
    ''' <param name="manager"></param>
    ''' <param name="path"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function GenerateFileName(ByVal manager As FileOrDirManager, ByVal path As String, ByVal destDir As String) As String

        '純粋なファイ名を取得  例「c:\temp\sample.txt」なら「sample.txt」
        Dim fileName = IO.Path.GetFileName(path)

        Dim resultPath As String
        Dim id As Integer = 0
        Do
            id += 1
            resultPath = IO.Path.Combine(destDir, GenerateNextFileName(fileName, id))
        Loop While manager.IsExist(resultPath)

        Return resultPath
    End Function

    ''' <summary>
    ''' fileNameを元に次のファイル名を生成
    ''' </summary>
    ''' <param name="fileName">純粋なファイ名  例「c:\temp\sample.txt」なら「sample.txt」</param>
    ''' <param name="id">ファイル名につける通し番号</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function GenerateNextFileName(ByVal fileName As String, ByVal id As Integer) As String

        Dim nameWithoutExtension As String = IO.Path.GetFileNameWithoutExtension(fileName)
        Dim extension As String = IO.Path.GetExtension(fileName)

        Dim prefix As String
        If System.Text.RegularExpressions.Regex.IsMatch(fileName, BackupFileExpression) Then
            'バックアップファイルが存在するとき
            prefix = nameWithoutExtension
        Else
            prefix = fileName
        End If
        Return prefix & ".backup" & DateTime.Now.ToString("yyyyMMdd_HHmm_") & id.ToString("D3")
    End Function
#End Region

End Class

もう一個クラス必要

''' <summary>
''' ファイルとディレクトリを同様に扱うためのクラス
''' </summary>
''' <remarks></remarks>
Public MustInherit Class FileOrDirManager
#Region "コンストラクタ"
    Private Sub New()
    End Sub

#End Region

#Region "共有メソッド"
    Public Shared Function Create(ByVal path As String) As FileOrDirManager

        If IO.File.Exists(path) Then
            Return New FileManager()
        ElseIf IO.Directory.Exists(path) Then
            Return New DirManager()
        Else
            Throw New ArgumentException("指定されたパスが見つかりません。path =" & path)
            Return Nothing
        End If
    End Function
#End Region

#Region "抽象メソッド"
    Public MustOverride Function CreateInfo(ByVal path As String) As IO.FileSystemInfo
    Public MustOverride Function IsExist(ByVal path As String) As Boolean
    Public MustOverride Function Copy(ByVal source As String, ByVal target As String) As Boolean
    Public MustOverride Function Move(ByVal source As String, ByVal target As String) As Boolean

#End Region


#Region "インナークラス"
    Private Class FileManager
        Inherits FileOrDirManager


        Public Overrides Function CreateInfo(ByVal path As String) As System.IO.FileSystemInfo
            Return New IO.FileInfo(path)
        End Function


        Public Overrides Function IsExist(ByVal path As String) As Boolean
            Return IO.File.Exists(path)
        End Function

        Public Overrides Function Copy(ByVal source As String, ByVal target As String) As Boolean
            My.Computer.FileSystem.CopyFile(source, target)
            Return True
        End Function

        Public Overrides Function Move(ByVal source As String, ByVal target As String) As Boolean
            IO.File.Move(source, target)
            Return True
        End Function

    End Class

    Private Class DirManager
        Inherits FileOrDirManager


        Public Overrides Function CreateInfo(ByVal path As String) As System.IO.FileSystemInfo
            Return New IO.DirectoryInfo(path)
        End Function

        Public Overrides Function IsExist(ByVal path As String) As Boolean
            Return IO.Directory.Exists(path)
        End Function

        Public Overrides Function Copy(ByVal source As String, ByVal target As String) As Boolean
            My.Computer.FileSystem.CopyDirectory(source, target)
            Return True
        End Function

        Public Overrides Function Move(ByVal source As String, ByVal target As String) As Boolean
            IO.Directory.Move(source, target)
            Return True
        End Function

    End Class
#End Region

End Class

日記にコード貼り付けたら、なんか見辛いね!
というわけで久しぶりの日記でした。