3日がかりのその仕事、3分で終わらせる方法教えます!
パソコンスキルの心技体

サブフォルダすべての中身を調べ、条件に合うファイルを移動させる – Excelマクロ・VBA

2012年2月17日
  • このエントリーをはてなブックマークに追加
  • follow us in feedly

達人養成塾 小川です。

さてさて。

前回書いた、以下のブログ。

不要な重複ファイルは自動削除するツールをVBAで自製してみた – Excel マクロ・VBA

で、紹介した、以下のプログラム。

‘Microsoft Scripting Runtime への参照設定をしてください
Sub mydel()
    Debug.Print “start”
    
    Dim c As Integer
    c = CInt(InputBox(“set max num”))
    myMove “.jpg”, c
    myMove “.png”, c
    
    Debug.Print “end”
End Sub
Sub myMove(ext As String, mx As Integer)
    Dim fs As New Scripting.FileSystemObject
    Dim fl(1) As Scripting.File
    Dim fBase As String
    Dim fname(2) As String
    Dim s As String
    Dim c As Long
    
    Dim suf As Long
    
    For c = 1 To mx
        s = String(4 – Len(CStr(c)), “0”) & c
        
        fBase = ThisWorkbook.path & “\IMG_” & s
        fname(0) = fBase & ext
        suf = 1
        fname(1) = fBase & “-” & suf & ext
        Do While fs.FileExists(filespec:=fname(1))
            Set fl(0) = fs.GetFile(fname(0))
            Set fl(1) = fs.GetFile(fname(1))
            If fl(0).DateLastModified = fl(1).DateLastModified And fl(0).Size = fl(1).Size Then
                fname(2) = ThisWorkbook.path & “\del\IMG_” & s & “-” & suf & ext
                Debug.Print “exists” & vbTab & fname(2)
                fs.MoveFile Source:=fname(1), Destination:=fname(2)
            End If
            suf = suf + 1
            fname(1) = fBase & “-” & suf & ext
        Loop
    Next
    
    For c = LBound(fl) To UBound(fl)
        Set fl(c) = Nothing
    Next
    Set fs = Nothing
End Sub

今日から、この完成形そのものではなく、ここに至るまでに書いた未完成のプログラムをいろいろ紹介していこうと思う。

何故、そんなことをするのか、というと。

どういう過程を踏んで、プログラムができあがるか、ということについて、ぜひ、あなたに知ってもらいたいからである。

世の中の実に多くの人が、ネットや書籍に載っているサンプルコードを見て、

「こういうのは、『アタマがよくて、特別な訓練を受けた人』が、『アタマの中で完成型を作ってから、特別な、厳粛な手続きを踏みながら、ダーッ!っと、上から順番に書いている』のだ。」

と思いこんでいる。
(そして、そういう人は、同じ機能のマクロを書こうとしたとき、ネットに転がっているサンプルを、上からなぞってマネしようとする)

しかし、実際には、違う。

プログラムを書ける人が、自分の手元の問題を解決する目的でプログラムを書くとき、実際にはどうやっているのかというと。

  1. 手元の資料や、過去に書いたサンプルコードをパクってきて
  2. とりあえず、テキトーにカスタマイズしてみて
  3. 別のところから、またパクってきて
  4. さっきのヤツに、無理矢理くっつけてみて
  5. そんなことをしていたらグチャグチャなコードになってしまったので、一度、スッキリさせて
  6. 気が向いたから、もう少し機能を追加して

なんて感じで、「けっこうテキトー」に作っているのだ。

ただ、その過程をそのまま晒すとカッコ悪そうだから、人に見せるときには、改めて、かなりスッキリしたコードになるまで書き直している、というだけのことである(笑

ちょうど、プログラムができあがる過程というのは、絵が描かれる過程に似ている。

展覧会に出品される作品の制作も、最初は、デッサンからはじまる。
デッサンのときには、ムダな線や、失敗の線、結果的に遠回りになってしまうような線も描かれる。

しかし、その過程を通じて、本当に描きたいラインを表現した、求める真の線が見つかるのだ。

はっきり言えば、「ネットに転がっているサンプルを、上からなぞってマネして書いていく」というのは、

「ゴッホのひまわり」をマネしようとして、ひまわりや花瓶からではなく、左上の背景から順番にマネしていくようなもの

である。

賢明なあなたならば、「そんなことをいくらくり返しても、達人の域に到達できない」ということは分かるだろう。

この一連の記事から、そんな感覚をつかんでもらいたい。

そして同時に、あなたのアタマの中から、「マクロなんて、アタマがよくて、特別な訓練を受けた人しか書けないものなんだ」という錯覚を外してもらいたい、というわけだ。

以下、僕が想定している読者層に比して内容的に若干レベルが高いので、個々のプログラムで各行が言わんとしていることについては細かく触れない。
ここでは、全体の流れだけを感じて欲しい。

さっそく、行ってみよう。

実は、前回紹介したマクロを書くよりだいぶ前に、やはり、画像の扱いに困ってマクロを書いたことがあった。

iPhoneからツールを使って吸い上げた写真が、作成日ごとに作られた 「2010 04 05」 みたいな名称のフォルダに格納されてしまい、そのフォルダが百を超えるような状態になってしまったのだ。

それで、それらを同じフォルダに移動させるツールを作った。
具体的には、あるフォルダのサブフォルダすべてを見にいって、「写真.jpg」というファイルと、「.mov」という拡張子のファイル以外は、「gather」という名のサブフォルダに移動させるようにした。

それが、以下。

以下、Microsoft Scripting Runtime への参照設定をしてから動かしてください。
あと、所定のフォルダはあらかじめ作っておくこと等々いろいろあるが、面倒なのと、今回イイタイコトと直接関係ないので、解説省略(笑

Sub fuga()
    Dim fs As Scripting.FileSystemObject
    Dim basefolder As Scripting.folder ‘調査対象のフォルダ
    
    Dim mySubFolders As Scripting.Folders ‘調査対象のフォルダ内のすべてのフォルダ
    Dim mySubFiles As Scripting.Files ‘調査対象のフォルダ内のすべてのファイル
    
    Dim mySubFolder As Scripting.folder
    Dim mySubFile As Scripting.File
    
    Set fs = New Scripting.FileSystemObject
    Set basefolder = fs.GetFolder(ThisWorkbook.path)
    
    Set mySubFolders = basefolder.subfolders
    For Each mySubFolder In mySubFolders
‘        Debug.Print mySubFolder.Name & ” ” & mySubFolder.DateLastModified
        
        Set mySubFiles = mySubFolder.Files
        For Each mySubFile In mySubFiles
‘            Debug.Print mySubFile.Name & ” ” & mySubFile.DateLastModified
            Debug.Print mySubFile.path
            If mySubFile.Name <> “写真.jpg” & InStr(LCase(mySubFile.Name), “.mov”) Then
                fs.MoveFile Source:=mySubFile.path, Destination:=ThisWorkbook.path & “\gather\” & mySubFile.Name
            End If
        Next
    Next
    
    Set mySubFile = Nothing
    Set mySubFolder = Nothing
    Set mySubFiles = Nothing
    Set mySubFolders = Nothing
    Set basefolder = Nothing
    Set fs = Nothing
End Sub

さあ、では、これを僕がどうやって作ったのかというと。

こんなの、イチから書いたりはしない。

実は、自分でやっている、エクセルマクロ・VBAの上級講座のために作ったテキストのサンプルコードからパクってきた(笑

最初にパクってきたモトネタのが、これ↓。あるフォルダにあるサブフォルダのリスト、ファイルのリストを出力する。

Sub GetSubFolders()
    Dim fs As Scripting.FileSystemObject
    Dim basefolder As Scripting.folder ‘調査対象のフォルダ
    
    Dim mySubFolders As Scripting.Folders ‘調査対象のフォルダ内のすべてのフォルダ
    Dim mySubFiles As Scripting.Files ‘調査対象のフォルダ内のすべてのファイル
    
    Dim mySubFolder As Scripting.folder
    Dim mySubFile As Scripting.File
    
    Set fs = New Scripting.FileSystemObject
    Set basefolder = fs.GetFolder(ThisWorkbook.path & “\fsosample”)
    
    Set mySubFolders = basefolder.subfolders
    For Each mySubFolder In mySubFolders
        Debug.Print mySubFolder.Name & ” ” & mySubFolder.DateLastModified
    Next
    
    Set mySubFiles = basefolder.Files ‘[1]
    For Each mySubFile In mySubFiles
        Debug.Print mySubFile.Name & ” ” & mySubFile.DateLastModified
    Next ‘[2]
    Set mySubFile = Nothing
    Set mySubFolder = Nothing
    Set mySubFiles = Nothing
    Set mySubFolders = Nothing
    Set basefolder = Nothing
    Set fs = Nothing
End Sub

そして、まずは、これを加工して、すべてのサブフォルダ内のファイルのリストを出力する、という趣旨のマクロを作った。
こんな感じ↓

Sub fuga()
    Dim fs As Scripting.FileSystemObject
    Dim basefolder As Scripting.folder ‘調査対象のフォルダ
    
    Dim mySubFolders As Scripting.Folders ‘調査対象のフォルダ内のすべてのフォルダ
    Dim mySubFiles As Scripting.Files ‘調査対象のフォルダ内のすべてのファイル
    
    Dim mySubFolder As Scripting.folder
    Dim mySubFile As Scripting.File
    
    Set fs = New Scripting.FileSystemObject
    Set basefolder = fs.GetFolder(ThisWorkbook.path)
    
    Set mySubFolders = basefolder.subfolders
    For Each mySubFolder In mySubFolders
        Debug.Print mySubFolder.Name & ” ” & mySubFolder.DateLastModified
        
        Set mySubFiles = mySubFolder.Files ‘[3]
        For Each mySubFile In mySubFiles
            Debug.Print mySubFile.Name & ” ” & mySubFile.DateLastModified
            Debug.Print mySubFile.path
        Next ‘[4]
    Next
    
    Set mySubFile = Nothing
    Set mySubFolder = Nothing
    Set mySubFiles = Nothing
    Set mySubFolders = Nothing
    Set basefolder = Nothing
    Set fs = Nothing
End Sub

まずは、サブプロシージャの名前に注目して欲しい。「fuga」なんて。ムチャムチャテキトーである(笑

そして、このとき、僕がどういう気分であったかを想像して欲しい。

そう。「テキトー」な気分で書いているのである。
何がどうなるかなんて、よく見えていない。厳粛な手続きを取る気もない。荘厳な作品を作るつもりもない。

直前で紹介した、[1]~[2]の部分を、[3]~[4]の部分に移動させて、ちょっと改変しただけ。

ついでに、 Debug.Print を使って、ここまでの目的どおりに動いているかを確認してみた。

うまく動いたので、もうちょっと改変。移動したいファイルを見つけたら移動させるようにしてみた。

Sub fuga()
    Dim fs As Scripting.FileSystemObject
    Dim basefolder As Scripting.folder ‘調査対象のフォルダ
    
    Dim mySubFolders As Scripting.Folders ‘調査対象のフォルダ内のすべてのフォルダ
    Dim mySubFiles As Scripting.Files ‘調査対象のフォルダ内のすべてのファイル
    
    Dim mySubFolder As Scripting.folder
    Dim mySubFile As Scripting.File
    
    Set fs = New Scripting.FileSystemObject
    Set basefolder = fs.GetFolder(ThisWorkbook.path)
    
    Set mySubFolders = basefolder.subfolders
    For Each mySubFolder In mySubFolders
‘        Debug.Print mySubFolder.Name & ” ” & mySubFolder.DateLastModified
        
        Set mySubFiles = mySubFolder.Files
        For Each mySubFile In mySubFiles
‘            Debug.Print mySubFile.Name & ” ” & mySubFile.DateLastModified
            Debug.Print mySubFile.path
            If mySubFile.Name <> “写真.jpg” & InStr(LCase(mySubFile.Name), “.mov”) Then ‘[5]
                fs.MoveFile Source:=mySubFile.path, Destination:=ThisWorkbook.path & “\gather\” & mySubFile.Name
            End If ‘[6]
        Next
    Next
    
    Set mySubFile = Nothing
    Set mySubFolder = Nothing
    Set mySubFiles = Nothing
    Set mySubFolders = Nothing
    Set basefolder = Nothing
    Set fs = Nothing
End Sub

[5]~[6]の部分が新しいが。

これも、If文はともかく、その中の、実際にファイルを移動させる部分は、自分の過去に書いたマクロ(というか、上級編講座用に書いたテキスト)からパクってきて、テキトーに書き換えただけ。

このように、マトモに動くプログラムが仕上がる過程では、プログラムは、上から順番に書かれていくのではなく、得てして、

  • ざっくりした全体像が描かれ
  • あとからあとから、中の部分に加筆がされていく

というステップを踏むのである。

あと、自分が過去に書いた遺産をそのまま活かして再利用することもしょっちゅうだ。

別に、悪いことではない。
あなたも、毎度毎度同じ書式の報告書とか請求書とかを書いたことがあるならそれと同じことをしている。

そのとき、イチイチ厳粛な気分にはならないだろう。

そもそも、こういう過程で作られたのだ、という認識もないまま「洗練された完成型」という雰囲気のサンプルコードを見ていても、絶対にマクロを書けるようにはならない。
「自分にはとてもできるとは思えない」と思う人の世界観と、「こんなのお茶の子再々」と思っている人の世界観は、根本的に異なるのだ。

だから、もしもあなたが「自分にはマクロなんてとても書けるとは思えない」と思っているならば、あなたがするべきことは、まずは、世界観を変えることだ。
実践的なノウハウは、それからついてくる。

キーワード

コメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

最新の記事

人気記事

最新記事

カテゴリ

最新コメント

タグクラウド