dポイントプレゼントキャンペーン実施中!

マクロ独学で勉強中です。
検索しましたが、下記コードしか自分では組めず、最終手段で質問いたします。
【やりたいこと】
1.フォルダ内のすべてのcvsファイルの作成日時を確認。
2.現在の日付から直近三日間で作成されたファイルを判別。
3.判別されたcsvファイルを新規ファイルの1列目から順にコピー。

それぞれのcsvファイルにはA1からQ1までデータが入力されています。
フォルダ内にあるcsvファイル数は5000ほどあり、下記のマクロですべて取り込んでそこから日付で判別していくとなると時間がかかります。
(いちいち開いてこぴーしてるというのもあると思いますが、、、)
ちなみに、csvファイルの名前は、”○○0414○○○.csv" みたいに一応日付がファイル名として記載されています。
このファイル名から判別できるとよりありがたいです。
(作成日時だと意図しないものもコピーされる恐れがあるため)

どなたかご教授いただければ幸いです。

Sub test()
Const FolderPath As String = "C:TestFolder"
Dim Filename As String
Dim Sh0 As Worksheet, Sh As Worksheet
Dim c As Long

Set Sh0 = ActiveSheet
Filename = Dir(FolderPath & "\*.csv")
Do Until Filename = ""
c = c + 1
Set Sh = Workbooks.Open(FolderPath & "\" & Filename).Sheets(1)
Sh.Range("A1:Q1").Copy Sh0.Range("A" & c & ":Q" & c)
Application.DisplayAlerts = False
Sh.Parent.Close
Application.DisplayAlerts = True
Filename = Dir()
Loop
End Sub

質問者からの補足コメント

  • 回答ありがとうございます。
    日付でフィルターは、同作成日で10個ほどファイルがあり、それを隔週で行うためあまり効率的ではないと思いました。
    ファイル名の規則は、4文字目からmmdd形式の日付となっています。
    上記のコード追加して実行しましたが、延々ループとなってしまいました。

    No.1の回答に寄せられた補足コメントです。 補足日時:2021/04/14 16:02
  • うーん・・・

    上記No1様への回答です。慣れてないもので補足に投稿いたしました。

    下記追加補足です。
    ・同じ作成日が複数あり、(10個ほど)一つずつ開いてするのは非効率
    ・各csvファイルにはA1からQ1までで数値しか入っておりません。(通常の貼付けで対応可です。)
    ・貼り付け先(例:sheet仮)のA2からQ2に貼付け。張り付けられていたらA~Qのの最終行に貼付け。

    拙い文ですがご査収ほど宜しくお願い致します。

      補足日時:2021/04/14 16:11

A 回答 (9件)

#3#5は独学中とのことですのであえて


処理部分を分け、配列に入れています。
ファイルのフルパスを取得する所で#5の処理を入れても良いと思いますが
エラー対策などの事もあるのでこのようロジックもなんとなく、、知っておいた方が良いと思います。
横から失礼しますが、ちなみにご質問2のファイル名で操作する場合、

#3のコード
Do While fileName <> "" から Loopまでを

Do While fileName <> ""
Set TrgFile = fso.GetFile(FolderPath & "\" & fileName)
'該当ファイルを配列に入れる (ここの箇所で条件をファイル名のxxなどにする事などが出来ます
' If TrgFile.DateLastModified > DateAdd("d", -3, Now) Then
If IsNumeric(Mid(fileName, 3, 4)) Then
If Int(Mid(fileName, 3, 4)) >= Int(Format(Now() - 3, "mmdd")) Then
ReDim Preserve Array_file(i)
Array_file(i) = TrgFile.path
i = i + 1
End If
End If
fileName = Dir()
Loop

のように書き換えると
試してないので少し自信はないのですが、
ファイル名の3文字目から7文字目に対応できると思います。
コード内の不要なコメント行は、消してください。
    • good
    • 0
この回答へのお礼

返事が遅くなり申し訳ありません。
正常に動作しましたのでベストアンサーに選ばせていただきました。
動作確認は済んだので、内容の理解と、追加コードは自分で記述していこうと思います。
今回のマクロを組むうえで、最難関と感じていたのが今回の箇所でしたので、迅速かつ正確なコードをご提示いただき大変助かりました。

その他の皆さんも回答して頂きありがとうございました。

お礼日時:2021/04/19 14:47

>Dim d1 As Date, d2 As Date, d3 As Date, dd As Date



宣言する型は日付型ではなく文字列型(As String)ではないでしょうか?
    • good
    • 0

コピペでうっかり見逃していたのですが、、


Const FolderPath As String = "C:TestFolder"

Const FolderPath As String = "C:\TestFolder"
ですね。
    • good
    • 0

初級者ジジィなので的外れも良い所かもですけど。


別の言語で該当するCSVファイルを1つに纏め、そのファイルからエクセルに取り込めば宜しいのでは?
と希望内容を見ているとそう感じます。

とは言え他言語なんて『?』なジジィですので、カテゴリーを絞り込み過ぎない程度で質問をしてみるとか?
    • good
    • 0

#2#3です


Array_file配列には該当ファイルのフルパスが入るので
' 配列内のデータを取り出す(ここでファイルを開く処理)
の下部分から、、最後まではこんな感じで良いかと


Dim n As Long
Dim wS As Worksheet
Set wS = ActiveWorkbook.ActiveSheet

For i = 0 To UBound(Array_file)
n = wS.Cells(Rows.Count, "A").End(xlUp).Row + 1
Application.ScreenUpdating = False
With Workbooks.Open(Array_file(i))
With ActiveSheet
wS.Range(wS.Cells(n, 1), wS.Cells(n, 17)).Value = .Range(.Cells(1, 1), .Cells(1, 17)).Value
End With
.Close Savechanges:=False
End With
Application.ScreenUpdating = True
' Msg = Msg & Array_file(i) & vbCr
Next
' 配列内のデータを取り出す--終わり
Exit Sub
NothingFile: '以降、該当ファイルが無い場合の処理
MsgBox ("該当ファイルはありません")
End Sub


調べても分からない点がありましたら、補足かお礼で
    • good
    • 0

No1です。



>一つずつ開いてするのは非効率
どうなさりたいのでしょうか?
どうするのが効率的とお考えなのでしょうか?

ご質問文にご提示のコードでは、フィルタもかけずに全部のファイルを開いてコピペしていますけれど、そこに関しては何のコメントも無いようです。
仮に、フィルタをかけるとして、それからどうしたいのでしょうか?

まぁ、CSVを全部読み込まずに、テキストとして最初の1行だけ読み込むという方法もあるとは思いますけれど、対象のCSVがどのような内容のものなのかにもよるでしょうし、そもそものご提示のコードがそのような方法はとっていませんでしたので・・・
いずれにしろ、ファイルを開いて読み込むことには変わりないはずです。
例えば、ScreenUpdatingを停止しておくことで、それなりに早くはなると思いますけれど・・・?


>上記のコード追加して実行しましたが、延々ループとなってしまいました。
No1で提示した処理は、ループには直接関係がないものです。

ループを繰り返すのは、(多分)どこかループに関係のある制御を誤って変えてしまったものと想像されます。
例えば、
 Filename = Dir()
の1行を削除してしまったとか・・・?
    • good
    • 0

つけ忘れ テストプロシージャ


Sub TestSample()
Const FolderPath As String = "C:TestFolder"
Dim FileName As String, Extension As String
Dim Array_file() As String
Dim fso As Object, TrgFile As Object
Dim Msg As Variant
Dim i As Long
Extension = ".csv" '対象拡張子
Set fso = CreateObject("Scripting.FileSystemObject")
FileName = Dir(FolderPath & "\*" & Extension)
Do While FileName <> ""
Set TrgFile = fso.GetFile(FolderPath & "\" & FileName)
'該当ファイルを配列に入れる
'(ここの箇所で条件をファイル名のxxなどにする事などが出来ます
If TrgFile.DateLastModified > DateAdd("d", -3, Now) Then
ReDim Preserve Array_file(i)
Array_file(i) = TrgFile.Path
i = i + 1
End If
FileName = Dir()
Loop
Set TrgFile = Nothing
'該当ファイルフルパスを配列に入れる--終わり

On Error GoTo NothingFile '配列空用エラー対策
' 配列内のデータを取り出す(ここでファイルを開く処理)
For i = 0 To UBound(Array_file)
Msg = Msg & Array_file(i) & vbCr
Next
' 配列内のデータを取り出す--終わり
MsgBox Msg
Exit Sub
NothingFile: '以降、該当ファイルが無い場合の処理
MsgBox ("該当ファイルはありません")

End Sub
    • good
    • 0
この回答へのお礼

更新日取得はできました。
取得したファイルの中身をA2~Q2より下へ順に貼付けするにはどうしたらよいでしょうか?

お礼日時:2021/04/14 16:39

こんにちは、


2のファイル名から判定する方法はすでに回答がありますので
1,の作成日の確認と更新日が3日以内のファイルを取得する方法です。
また、ご質問の背景は分かりませんが、ファイル名に日付以外の部分で
共通カテゴリー名などが付いていれば、更新日時から最新のファイルのみを抽出する事も可能と思います。
ファイルの作成日時や更新日時、アクセス日時を取得する方法は、
FileSystemObject(ファイルシステムオブジェクト)を使用します。
参考 http://officetanaka.net/excel/vba/filesystemobje …
作成日時の場合は、DateCreatedプロパティを取得します。
更新日時の場合は、DateLastModified
アクセス日時の場合は、DateLastAccessed

下記は、フォルダー内にあるcsvファイルの更新日が3日以内のファイルpathをを取得するプロシージャです。(時間も関係するので仮要件)
取得できたファイルpathは配列に入れています。
(データ(取得)作成、メイン処理、出力処理を分けた方が良いかなと)

3,については
CSVファイルの扱いは色々なやり方があります。
多分サンプルで、1行のみをコピぺしているようですが、
そのままExcelで開いて文字列、値など問題のないCSVファイルなのでしょうか?また、範囲は1行のみなのでしょうか?
取敢えず
更新日が3日以内のファイルを取得する方法(時間も関係するので仮要件)
    • good
    • 0

こんにちは



ファイルをコピペする前に、日付でフィルターをかければよいだけのように思います。

>このファイル名から判別できるとよりありがたいです
>作成日時だと意図しないものもコピーされる恐れがある
とのことですが、ファイル名の規則がイマイチはっきりしないので・・・
「ファイル名の3~6文字目がmmdd形式の日付となっている」ものと仮定できる場合の一例を以下にあげておきます。

まず、事前に対象日を文字列として作成しておきます。
 d1 = Format(Now(), "mmdd")
 d2 = Format(Now() - 1, "mmdd")
 d3 = Format(Now() - 2, "mmdd")
そのうえで、ループ内で

 dd = Mid(Filename, 3, 4)
 If dd = d1 Or dd = d2 Or dd = d3 Then
   ’ ここでファイルを開く処理
 End If
のようにすることで、対象のファイルだけを処理できるようになるでしょう。

※ ファイル名の規則が違うような場合は、判定方法をそれに合わせて変えればよいです。
この回答への補足あり
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
日付でフィルターは、同作成日で10個ほどファイルがあり、それを隔週で行うためあまり効率的ではないと思いました。
ファイル名の規則は、4文字目からmmdd形式の日付となっています。
上記のコード追加して実行しましたが、延々ループとなってしまいました。

Sub test()
Const FolderPath As String = "C:TestFolder"
Dim FileName As String
Dim Sh0 As Range, Sh As Worksheet
Dim c As Long
Dim d1 As Date, d2 As Date, d3 As Date, dd As Date

d1 = Format(Now(), "mmdd")
d2 = Format(Now() - 1, "mmdd")
d3 = Format(Now() - 2, "mmdd")

Set Sh0 = ActiveSheet.Range("A2:Q2")
FileName = Dir(FolderPath & "\*.csv")
Do Until FileName = ""
c = c + 1
dd = Mid(FileName, 4, 4)
If dd = d1 Or dd = d2 Or dd = d3 Then
Set Sh = Workbooks.Open(FolderPath & "\" & FileName).Sheets(1)
Sh.Range("A1:Q1").Copy Sh0.Range("A" & c & ":Q" & c)
Application.DisplayAlerts = False
Sh.Parent.Close
Application.DisplayAlerts = True
FileName = Dir()
End If
Loop
End Sub

お礼日時:2021/04/14 16:39

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!