2013年10月26日土曜日

コラム:FileSystemObjectとNothing

 『FileSystemObjectのオブジェクトは解放しなければならない。』は本当?

        Dim fso as new FileSytemObject
           ・
           ・
     ・
         Set fso = Nothing


 前々から気になっていたVBAのガーベージコレクションの動作について、検証を試みました。なにが気になっていたかというと・・・

【気になっていたこと】
  VBAってガーベージコレクション機能があるんじゃないの!
  なんでオブジェクトを作ったあとにNothingを代入してメモリを解放するの?
  これじゃ、CやC++と同じじゃない!めんどうくさい。


 VBAを使い始めたころは、ネットのコードをまねして、必ずNothingを使って”きれいに”していました。しかし、最近では、もともとのいいかげんな性格がでてきて、Nothingを使わなくなりました。それでも、これまでメモリ不足なんて見たことはありません。



  さて本題です。解説が長くなりそうなので、検証結果から。

【検証総合結果】

  VBAのコード実行が終了すると、ガーベージコレクションが”きちんと”働き、Nothingを代入していないFileSystemObjectが自動で解放されている。
  したがって、何時間も何日も実行しつづける関数を実行しない限り、Nothingを使って解放する必要はない。



【検証】
   ①現在のメモリ情報を取得する関数を実行する。
   ②FileSystemObjectを100万個つくるだけの関数を実行する。
     (Nothingによる解放をしない)
   ③現在のメモリ情報を取得する関数を実行する。

   フリー物理メモリ
     ①    1,687,674,880バイト
     ②-1  1,687,359,488バイト(②の関数のはじめでチェック)
     ②-2  1,686,659,072バイト(②の関数のおあわりでチェック)
     ③    1,687,969,792バイト


   確かに②の関数内では、Nothingで解放していないため、700kバイトの
  メモリが使われているのがわかる。
   しかし②の関数を抜けてしまうと、700kバイトのメモリは解放されている。
   (逆に増えているのは、その他の要因か)

     10回ほど繰り返したが、全部同様の結果となった。

   尚、FileSystemObjectは1個につき7バイトを使用することも分かった。

   心配することなかれ、VBAのガーベージコレクションは、”きちんと”
  働いてくれているのだ。


【コード1】メモリの状態を取得する

Private Declare Sub GlobalMemoryStatus Lib "kernel32" (lpBuffer As MEMORYSTATUS)

Public Type MEMORYSTATUS
    dwLength As Long
    dwMemoryLoad As Long
    dwTotalPhys As Long
    dwAvailPhys As Long
    dwTotalPageFile As Long
    dwAvailPageFile As Long
    dwTotalVirtual As Long
    dwAvailVirtual As Long
End Type

Function GetMemoryInfo() As MEMORYSTATUS
    
    Dim memInfo As MEMORYSTATUS
    GlobalMemoryStatus memInfo
    GetMemoryInfo = memInfo

End Function


【コード2】FileSystemObjectを指定しただけつくる

Sub testFSO2(numFSO As Long)

    Dim index As Long
    Dim fso() As FileSystemObject
    
    ReDim fso(numFSO)
    
    For index = 0 To numFSO - 1
        Set fso(index) = New FileSystemObject
    Next
    
    ReDim fso(1)

End Sub



今日はここまでです。

<script data-ad-client="ca-pub-1118677719612861" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>

2013年10月19日土曜日

移動の実装 MoveFile

 ファイルの移動も簡単です。コピーの場合と同じように、FileSystemObjectのメンバー関数であるMoveFile関数を使います。
 MoveFileは、名前の変更と移動の二つの機能がいっしょになった関数です。
下の例では、同じフォルダに元のファイルと違う名前を指定しているので、ファイル名の変更をしたことになります。
 移動する場合は、2番目の引数を元のファイルと違う場所にすればよいだけです。

=====================================================
Sub testForMove()

    Dim fso As New FileSystemObject
    
    On Error GoTo Err_testForMove
    
    fso.MoveFile "c:\test.xlsx", "c:\hogehoge.xlsx"
    
    Exit Sub
    
Err_testForMove:

    MsgBox "ファイルの移動中にエラーが発生しました。" & _
     vbCr & "エラー詳細:" & Err.Description

End Sub
=====================================================

MoveFile関数も、戻り値がありません。しかし、移動先のファイルが既に存在する場合などはエラーが発生します。
  エラー原因を調べるために、3行目の"On Error ・・・"を宣言しています。
  エラー処理では、メッセージボックスでエラーの発生した原因を調べるために便利な、Err.Descriptionを表示させています。

  前回と今回で、ファイルのコピーと移動の基礎知識を紹介しました。次回以降、この基礎知識をもとに、大量のファイルを分別するコピー(移動)する方法を紹介いたします。



*********  コラム Option Explicitの意義 ******************

 C,C++,C#など、私のこれまで使用してきた言語は、変数をあらかじめ宣言しないとコンパイルエラーになります。しかし、VBAでは、この宣言をしない限りコンパイルエラーになりません。
 VBAで、変数を宣言しないで使用することのメリット、デメリットを考えてみました。

【メリット】
  なによりも、変数宣言のキータイプをしなくてもよいのでらくちんです。また自由に変数を作って代入ができるので、精神的な解放感もあります。

【デメリット】
  タイプミスがVBAを実行したときに判明します。このデバッグがけっこうやっかいで、なかなか見つけることができません。


 一般的に、ソフトウェア開発はより上流工程で不具合を発見し修正したほうが制作コストが安くなると言われています。
 Option Explicitは、実行する前にタイプミスを見つけることができるので、その理屈に合っています。
 ただし、関数の引数のタイプ途中に別の行へ移ろうとすると、エラーのメッセージボックスがでるのが非常に面倒です。これだけは、なんとかなりませんかね。(C#などは、その行に波線が入るだけで、スマートです)

VBAのコンパイル操作
<script data-ad-client="ca-pub-1118677719612861" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>

2013年10月15日火曜日

コピーの実装

 ファイルのコピーは、そのまま”CopyFile"関数を使います。

=====================================================
Sub test()

    Dim fso As New FileSystemObject
    
    On Error GoTo Err_test
    
    fso.CopyFile "c:\test.xlsx", "c:\hogehoge.xlsx", True
    
    Exit Sub
    
Err_test:

    MsgBox "ファイルのコピー中にエラーが発生しました。" & _
     vbCr & "エラー詳細:" & Err.Description

End Sub
=====================================================

CopyFile関数は、戻り値がありません。しかし、コピー元のファイルがなかった
場合などはエラーが発生します。
  確実な動作を目指すためには、エラー処理が欠かせません。3行目の"On Error ・・・"は、CopyFileでエラーが発生した場合に処理を宣言しています。
  エラー処理では、メッセージボックスでエラーの発生した原因を調べるために便利な、Err.Descriptionを表示させています。


あとがき:
  インテリセンスは、関数やプロパティを自動的に表示するだけでなく、関数の引数の説明も表示してくれます。本当に至れりつくせりです。

インテリセンスによる引数の説明

<script data-ad-client="ca-pub-1118677719612861" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>

2013年10月11日金曜日

ファイルコピーの準備 FileSystemObject

【第1章】 ファイルのコピー、移動をする

第一節 FileSystemObject
=========================================

  ファイルを扱うとき、私はよくFileSystemObjectを使います。

 メリット:ファイルに関するいろいろな関数が準備されている。
      たとえば、拡張子、親フォルダ、ファイル日付など簡単にしらべる
      ことができます。

 
 ポイント:ツールの参照設定で、”Microsoft Scripting Runtime”をチェック
       しておくと、インテリセンスが使えて非常に便利です。


解説:インテリセンスは、作成したオブジェクトの次にピリオドを打つと、
    自動で使用できる関数やプロパティの一覧が見える機能です。
    一度使ったら手放せません。

インテリセンス

     インテリセンスを使うためには、FileSystemObjectの参照設定を
    する必要があります。

ツールの参照設定を開く

      FileSystemObjectは、”Microsoft Scripting Runtime”という
     ライブラリに入っています。
Microsoft Scripting Runtimeを選択

<script data-ad-client="ca-pub-1118677719612861" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>