なんだかGoodVibes

日々の勉強メモです。

【VBA】ログクラス作成(サイズ確認・書き込み・名前変更したりする)

こんにちは。
本日はちょっとしたサンプル。
テキストファイルに書き込みを行い、
ある一定のサイズになったら新しく新規のファイルを作成し、
これまでのファイルのインデックスをアップさせていく
クラスモジュールのサンプルです。


概要

Log20201030.txtのようなファイルを作ります。
指定したサイズを越えるまで、更新します。
サイズを越えるとき、ファイルのインデックスをアップさせて
Log20201030_1.txtを作成。
そして、Log20201030.txtをクリアします。
このインデックスが大きければ大きいほど古いファイルとなります。
インデックスが付いていないファイルが常に最新となります。
クラスモジュールの名前はLoggerとしておきます。


クラスモジュール(Logger)

Option Explicit

' 最大ファイルサイズ(byte)
Const MaxFileSize As Long = 2000

' ファイル関連
Private Const fileName As String = "Log"
Private Const Extension As String = ".txt"
Private Const SepaText As String = "_"
Private Const TmpText As String = "tmp"

Private FileDate As String
Private Path As String
Private FileFullName As String
Private FSO As Object

' [1]クラス初期化処理
Private Sub Class_Initialize()
    Set FSO = CreateObject("Scripting.FileSystemObject")
    Path = ThisWorkbook.Path
End Sub

' [2]クラス解放処理
Private Sub Class_Terminate()
    Set FSO = Nothing
End Sub

' [3]ログ出力[Info]
Public Sub Info(ByVal msg As String)
    Call MainProcess("[Info]  " & Now & " : " & msg)
End Sub

' [3]ログ出力[Warn]
Public Sub Warn(ByVal msg As String)
    Call MainProcess("[Warn]  " & Now & " : " & msg)
End Sub

' [3]ログ出力[Error]
Public Sub Error(ByVal msg As String)
    Call MainProcess("[Error] " & Now & " : " & msg)
End Sub

' [4]メイン処理
Private Sub MainProcess(ByVal msg As String)

    FileDate = Format(Now, "yyyymmdd")
    FileFullName = Path & "\" & fileName & FileDate & Extension

    ' ファイルの存在チェック
    If Not FSO.FileExists(FileFullName) Then
        FSO.CreateTextFile (FileFullName)
    End If
    
    ' サイズチェック
    If IsOverMaxFileSize(msg) = True Then
        Call AdjustFileName
    End If
    
    ' 出力処理
    Call WriteFileAppend(FileFullName, msg)
End Sub

' [5] サイズチェック処理
Private Function IsOverMaxFileSize(ByVal msg As String) As Boolean
    Dim result As Boolean: result = False

    Dim tmpFile As String: tmpFile = Path & "\" & fileName & FileDate & SepaText & TmpText & Extension
    FileCopy FileFullName, tmpFile
    
    Call WriteFileAppend(tmpFile, msg)

    Dim size As Long: size = FileLen(tmpFile)
    If size > MaxFileSize Then
        result = True
    End If
    
    Kill tmpFile
    
    IsOverMaxFileSize = result
End Function

' [6] 書き込み処理
Private Sub WriteFileAppend(ByVal fileName As String, ByVal msg As String)
    Open fileName For Append As #1
        Print #1, msg
    Close #1
End Sub

' [7] ファイル名調整処理
Private Sub AdjustFileName()

    Dim fileArr() As String
    ReDim fileArr(0)

    Dim buf As String
    buf = Dir(Path & "\" & fileName & FileDate & "*")
    Do While buf <> ""
        fileArr(UBound(fileArr)) = buf
        ReDim Preserve fileArr(UBound(fileArr) + 1)
        buf = Dir()
    Loop
    
    If UBound(fileArr) > 0 Then
        ReDim Preserve fileArr(UBound(fileArr) - 1)
    End If

    Dim item As Variant
    For Each item In fileArr
        Dim oriFile As String: oriFile = Path & "\" & fileName & FileDate
        
        If InStr(item, SepaText) = 0 Then
            FileCopy FileFullName, oriFile & SepaText & "1" & Extension
        Else
            Dim tmp() As String: tmp = Split(item, Extension)
            Dim tmp2() As String: tmp2 = Split(tmp(0), SepaText)
            Dim num As Integer: num = tmp2(1)
            
            FileCopy Path & "\" & item, oriFile & SepaText & num + 1 & Extension
        End If
        
    Next item
    
    Open FileFullName For Output As #1
    Close #1
    
End Sub


処理の詳細

[1]クラス初期化処理関数(Class_Initialize)

この関数は、クラスのインスタンスが生成された際に呼び出されます。
なので、処理で必要な情報をここで作成しておきます。

  • FileSystemObjectインスタンス作成
  • パスを取得して、ベースとなるファイル名を取得


[2]クラス解放処理関数(Class_Terminate)

この関数は、クラスのインスタンスが破棄された際に呼び出されます。
今回は、FSOの解放を行っています。


[3]ログ出力処理関数(Info,Warn,Error)

この関数が実際に呼び出されます。
Info,Warn,Errorのそれぞれの出力用関数を作成しました。


[4]メイン処理関数(MainProcess)

ログを出力するにあったて必要な処理のメイン部分です。
引数に、出力する文字列を受け取ります。

  1. ファイルの存在チェック
  2. インデックスなしのファイルのサイズをチェック
  3. データの出力を行う

今回、ファイル名に日付を入れたかったので
Nowを使用して日付を取得しています。


1.にて、FileExistsでファイルが存在するかどうかチェックします。
存在しない場合は、CreateTextFileでファイルの作成を行います。
どちらも、FileSystemObjectのメソッドです。


2.にて、サイズチェック処理関数を呼び出します。
サイズが越えていた場合は、ファイル名更新処理関数を呼び出し、
ファイル名の更新を行っています。

3.にて、データの出力を行います。


[5] サイズチェック処理関数(IsOverMaxFileSize)

サイズチェックを行っているのはIsOverMaxFileSize関数です。
引数に、出力する文字列を受け取ります。
流れとしては、

  1. 最新のファイルのコピーをとる(tmpFile)
  2. tmpFileに一旦書き込みを行う
  3. tmpFileが指定したサイズを越えているか判定(FileLenを使用)
  4. 判定後、tmpFileは削除(Killを使用)
  5. 結果を呼び元に返す

これで、追加したあとのサイズを判定できます。


[6] 書き込み処理関数(WriteFileAppend)

ファイルへの書き込みはWriteFileAppend関数にて行っています。
引数に、出力する文字列を受け取ります。
Open,Closeは以下の内容になっています。

' fileName を追加書き込みモードで番号1としてオープンする
Open fileName  For Append #1

    ' ファイル番号1にmsgを書き込む 
    Print #1, msg

' ファイル番号1を閉じる
Close #1


[7]ファイル名調整処理関数(AdjustFileName)

IsOverMaxFileSizeでサイズ越えてるよってなった場合
AdjustFileName関数にてファイルのインデックスを調整します。
一旦、指定場所(今回はマクロがおいてある場所)にある対象の日付を含む
テキストファイル名を取得します。
ここでの処理については以下の記事を参照して下さい。

ファイルの存在をチェックする - なんだかGoodVibes

VBAで動的配列 - なんだかGoodVibes

現在の最新となるインデックスなしのファイルはインデックス1をつけてコピーし、
すでにインデックスが振られているファイルは
現在のインデックスに1プラスしたインデックスのファイルにコピーします。

最後に、最新となるインデックスなしのファイルを空にします。
先程使用したOpen,Closeを使います。
ここでは、空にしたいだけなので、上書きモード(Output)で開いています。

' FileFullName を上書きモードで番号1としてオープンする
Open FileFullName For Output As #1

' ファイル番号1を閉じる
Close #1


使用方法

使用方法はこんな感じです。

Option Explicit

Sub Main()
    ' インスタンス生成
    Dim log As LogUtils
    Set log = New LogUtils
    
    log.Info ("情報を出力します。")
    log.Warn ("ワーニングを出力します。")
    log.Error ("エラーを出力します。")
    
    Set log = Nothing
End Sub


テキストファイルに以下の内容が出力されました。

[Info]  2020/10/27 13:56:23 : 情報を出力します。
[Warn]  2020/10/27 13:56:23 : ワーニングを出力します。
[Error] 2020/10/27 13:56:23 : エラーを出力します。



以上です。