重複しないファイル名を取得する関数

ファイルの名前を付けて保存する際に、重複しないファイル名を取得する関数です

Function zzz可能ファイル名(ByVal zz保存名 As String) As String

Dim zz保存名_前 As String, zz保存名_後 As String
Dim zz連番 As Long
Dim zz検証用文字列 As String
zz保存名_前 = Mid(zz保存名, 1, InStrRev(zz保存名, ".") - 1)
zz保存名_後 = Mid(zz保存名, InStrRev(zz保存名, "."))
zz連番 = 2

zz検証用文字列 = zz保存名
Do Until Dir(zz検証用文字列) = ""
    zz検証用文字列 = zz保存名_前 & "_(" & zz連番 & ")" & zz保存名_後
    zz連番 = zz連番 + 1
Loop
zzz可能ファイル名 = zz検証用文字列

End Function

ExcelVBAのコードで、ファイル名を付けて保存する処理があります
その際に、付けたいファイル名が使用済みであった場合上書き保存の確認が出てきたり、自動的に上書きされてしまったりします

エクスプローラー上での連番が振られて、ファイルが別ファイルとして保存されていくような処理はVBAで自動的に行うことは出来ません

実際に保存処理を行う前に、重複しない名前を取得しておく必要があります
その時に使用する関数です

この関数は、引数に指定したパス文字列のファイル名を重複する場合は連番を付けて返します
この関数で取得した文字列をファイル名の絶対パスとして指定すれば、重複することが無くなります

コードの使用方法

ThisWorkbook.SaveAs zzz可能ファイル名(ThisWorkbook.FullName)

このコードの様に、関数として引数を指定して使用します
ここでは、このコードのあるExcelブックを同じ場所に名前を付けて保存します

コードを数回実行した状態
コードを複数回実行

コードがある元々のExcelブックは「TestFile.xlsm」になります

そのファイルに上記の関数とコードを記載して、元ファイルを開きなおして数回実行したフォルダ内の状態です

元々のExcelブック名に連番を付けて保存します

コード解説

Function zzz可能ファイル名(ByVal zz保存名 As String) As String

・・・

End Function

使用可能な文字列を返すので、戻り値を利用するのでFunctionプロシージャで作成を行います
また、戻り値はパス文字列なのでString型で宣言しています

引数は1つ設定しています
zz保存名は、使用したいファイル名の絶対パス文字列を指定してもらいます
なお、ここでの処理ではその文字列があれば良いのでByValで引数を指定しています
これは引数を値渡しとするものです、処理中に変更したりはしませんので
参照渡しでもええっちゃええです

Dim zz保存名_前 As String, zz保存名_後 As String
zz保存名_前 = Mid(zz保存名, 1, InStrRev(zz保存名, ".") - 1)
zz保存名_後 = Mid(zz保存名, InStrRev(zz保存名, "."))

作成する保存名を作成するうえで必要なパス文字列として、引数として指定された文字列を一旦拡張子までで分割します
引数に指定する文字列は拡張子まで含めた絶対パス文字列になるので、文字列の最後にはファイルの拡張子が存在します

なので、この引数の文字列の後に単純に連番を追加しても有効なパス文字列にはなりません
その為に、分割した文字列を別々の変数にそれぞれ取得させます

その変数の宣言と、分割取得の箇所になります

Mid関数は、指定文字列の中から指定文字数を抜き出す関数です
これを文字数を指定することでパス文字列を分割取得することが出来ます

引数の中にある、InStrRev関数は指定文字列の中から特定の文字を検索して何文字目にあるかを返す関数です
InStrRev関数は、特定の文字を検索する場合に文字列の右側から検索を行います

今回分割したい文字列は拡張子の部分になります
なので「.」を検索する必要がありますが、この文字自体はファイル名やフォルダ名に使用することが可能です

その為、文字列の左側から検索した場合拡張子が取得できない可能性があります
また拡張子の文字数も3文字や4文字など固定されたものではありません
ですが、さすがにファイルの拡張子に「.」が使用されることはありませんので、文字列の右側から検索を行えば、確実に拡張子との分割箇所が特定できます

ちなみに、この関数は絶対パスから「\」を検索することでフォルダまでのパスに分割するような事にもよく使われます

Dim zz連番 As Long
zz連番 = 2

ファイルに結合する連番の整数値用の変数です
重複があれば数字を連結するので、この数値を使用するタイミングは前提として重複するものがあるという事なので、初期値は2から始めます

Dim zz検証用文字列 As String
zz検証用文字列 = zz保存名

検証用の文字列を一時的に代入するための文字列変数です

初期値として、引数の文字列をそのまま代入します
まず最初にこの代入した文字列で検証を行う形になります

Do Until Dir(zz検証用文字列) = ""
    zz検証用文字列 = zz保存名_前 & "_(" & zz連番 & ")" & zz保存名_後
    zz連番 = zz連番 + 1
Loop

ループ処理で、使用可能な連番の数値になるまで繰り返します

Dir関数でパス文字列が使用可能かどうかを検証しています
この関数は、引数のパスが有効であればそのファイル名のみを取得する関数です

パスのファイルが存在しない場合は、空白を返します
つまり、この関数で空白が取得されれば重複するファイル名が存在しないことが判定できます

ループ処理の中では、連番数字を連結した文字列を検証用文字列に代入しています
代入が終わってから、数値変数を加算しています

代入が終わったら、また上記の検証を行い
使用可能なパス文字列が生成されるまでループ処理を行います

zzz可能ファイル名 = zz検証用文字列

最後に、使用可能なパス文字列が代入された検証用文字列の文字列を関数名に代入します
これが、この関数の戻り値になります

関数の型は、String型なので文字列として、このパス文字列を返すことが出来ます