datetime
cppBuilder
fileIO
#migrated

C++ Builder XE4, 10.2 Tokyo > ファイル名から日付を取得 + 指定の日付以前のファイルを削除 > v0.1..v0.3

動作環境
C++ Builder XE4
RAD Studio 10.2 Tokyo Update 2 (追記: 2018/01/09)

ファイル名に日付が入っている状況で、指定日付以前のファイルを削除する処理。

対象ファイル

bash > Brace Expansionで日付のダミーファイルを作る | ファイル名失敗時: MinGW32でファイルを消す
にて作ったファイル。

v0.1, v0.2

code

Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <IOUtils.hpp>
#include <memory>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

/*
v0.2 2017/10/17
  - リストの対象ファイルを削除 (ゴミ箱には行かない)
  - isDateBefore()追加
  - getFileDateTime()追加
v0.1 2017/10/17
  - 対象フォルダにあるファイルリストを取得
*/


String kTargetFolder = L"D:\\WORK\\filedelete_171017";
TDateTime kLastDate = VarToDateTime("2017/01/15 00:00:00"); // Note: VarToDateTime()使用時はLマクロにしない

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------

static TDateTime getFileDate(String filePath)
{
    String filename = ExtractFileName(filePath);
    // filename:
    //   例:"X_20170131.csv" (2017 Jan. 31のファイル)

    String strdt = filename.SubString(3, 8); // 3: yyyyの開始インデックス

    // 12345678
    // yyyymmdd
    strdt.Insert("/", 7); // mmとddの間
    strdt.Insert("/", 5); // yyyyとmmの間

    OutputDebugString(filename.c_str());

    return VarToDateTime(strdt + L" 00:00:00");
}

static bool isDateBefore(String filepath, TDate lastDate)
{
    TDateTime trgt;
    try {
        trgt = getFileDate(filepath);
    } catch (...) {
        return false; // ファイル名が日付型でない場合
    }
    if (trgt > lastDate) {
        return false;
    }
    return true;
}

void __fastcall TForm1::dbgB_getListClick(TObject *Sender)
{
    String searchPattern = L"*.csv";
    TSearchOption option = TSearchOption::soAllDirectories;

    TStringDynArray fileList = TDirectory::GetFiles(kTargetFolder, searchPattern, option);
    int allcnt = fileList.Length;

    std::unique_ptr<TStringList> lst(new TStringList);

    TDateTime filedt;
    for(int idx = 0; idx < fileList.Length; idx++) {
        if (isDateBefore(fileList[idx], kLastDate) == false) {
            continue;
        }
        lst->Add(fileList[idx]);

        TFile::Delete(fileList[idx]); /***********************/
    }

    String msg = IntToStr(lst->Count) + L"/" + IntToStr(allcnt);
    OutputDebugString(msg.c_str());

    Memo1->Lines->Assign(lst.get());
}
//---------------------------------------------------------------------------

実行結果

2017/01/15までのファイルが削除される。

備考

TFile::Delete()の場合、ごみ箱に行かずに削除される
(Shift + Deleteと同じ)。

TFile::Move()でごみ箱に移動しようかと検討したが、ごみ箱のパスを取得する方法が見つかっていない。
関連: https://qiita.com/7of9/items/7bb5d9837c696754995d

v0.3

  • 最終日だけでなく、最終日と日数に変更
  • 処理を関数化
Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <IOUtils.hpp>
#include <DateUtils.hpp>
#include <memory>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

/*
v0.3 2017/10/17
    - change to range
        + isInRange() takes [days] arg
        + refactor > rename isDateBefore() to isInRange()
    - deletePastFiles()追加
v0.2 2017/10/17
    - リストの対象ファイルを削除 (ゴミ箱には行かない)
    - isDateBefore()追加
    - getFileDateTime()追加
v0.1 2017/10/17
    - 対象フォルダにあるファイルリストを取得
*/


String kTargetFolder = L"D:\\WORK\\filedelete_171017";
TDateTime kLastDate = VarToDateTime("2017/01/15 00:00:00"); // Note: VarToDateTime()使用時はLマクロにしない

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------

static TDateTime getFileDate(String filePath)
{
    String filename = ExtractFileName(filePath);
    // filename:
    //   例:"X_20170131.csv" (2017 Jan. 31のファイル)

    String strdt = filename.SubString(3, 8); // 3: yyyyの開始インデックス

    // 12345678
    // yyyymmdd
    strdt.Insert("/", 7); // mmとddの間
    strdt.Insert("/", 5); // yyyyとmmの間

    OutputDebugString(filename.c_str());

    return VarToDateTime(strdt + L" 00:00:00");
}

static bool isInRange(String filepath, TDate lastDate, int days)
{
    TDateTime trgt;
    TDateTime startdt = IncDay(lastDate, -(days - 1));

    try {
        trgt = getFileDate(filepath);
    } catch (...) {
        return false; // ファイル名が日付型でない場合
    }
    if (trgt < startdt) {
        return false;
    }
    if (trgt > lastDate) {
        return false;
    }
    return true;
}

void __fastcall TForm1::deletePastFiles(String filePattern, TDateTime lastDate, int days, String targetDir, TStringList *delList)
{
    TSearchOption option = TSearchOption::soAllDirectories;

    TStringDynArray fileList = TDirectory::GetFiles(kTargetFolder, filePattern, option);
    int allcnt = fileList.Length;

    for(int idx = 0; idx < fileList.Length; idx++) {
        if (isInRange(fileList[idx], lastDate, days) == false) {
            continue;
        }
        if (delList != NULL) {
            delList->Add(fileList[idx]);
        }

        TFile::Delete(fileList[idx]); // ごみ箱に行かずに消える
    }
}

void __fastcall TForm1::dbgB_getListClick(TObject *Sender)
{
    int days = 10; // テスト用
    std::unique_ptr<TStringList> lst(new TStringList);

    deletePastFiles(L"*.csv", kLastDate, /*days=*/days, /*targetDir=*/kTargetFolder, lst.get());
    Memo1->Lines->Assign(lst.get());
    String msg = IntToStr(lst->Count) + L" deleted";
    OutputDebugString(msg.c_str());
}
//---------------------------------------------------------------------------

1月6日から1月15日のファイルを消すようになった。