指定ディレクトリ内部をスキャンしてファイル名群を得る

C++17から導入されたstd::filesystemライブラリを使ってみようの1

ここに分かりやすい解説とサンプルソースがあるので、参考にすると大吉。

directory_iteratorの例

#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

int main() {
    // 走査対象のパスを指定(カレントディレクトリ ".")
    fs::path target_path = ".";

    try {
        // directory_iteratorを使用してディレクトリ内を走査
        for (const fs::directory_entry& entry : fs::directory_iterator(target_path)) {
            // entry.path() でフルパスを取得し、filename() でファイル名のみを抽出
            std::cout << entry.path().filename() << std::endl;
        }
    } catch (const fs::filesystem_error& e) {
        // ディレクトリが存在しない場合などのエラー処理
        std::cerr << "エラーが発生しました: " << e.what() << std::endl;
    }

    return 0;
}

動かして見よう。

ここで、何もないところで得意の右クリック

中程の”Open Git Bash here”を選択。

漢字コードを合わせておこう。上記のタイトルバーを右クリックして、

Options->Textを選んで以下のように、

“Apply”を選択。で”Save”。

$ bcc32c test1.cpp
Embarcadero C++ 7.70 for Win32 Copyright (c) 2012-2024 Embarcadero Technologies, Inc.
test1.cpp:
Turbo Incremental Link 6.99 Copyright (c) 1997-2024 Embarcadero Technologies, Inc.

jakeb@Orbit-11 MINGW64 ~/OneDrive/Documents/Embarcadero/Studio/Projects/directory_iterator_test
$ ./test1
directory1
recur.cpp
recur.exe
recur.tds
test1.cpp
test1.exe
test1.tds

動いてますね。

recursive_directory_iteratorの例

#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

int main() {
    fs::path p = ".";

    std::cout << "プロジェクト内の全ファイルをリストアップします:" << std::endl;

    // 再帰的なイテレータを使用
    for (const auto& entry : fs::recursive_directory_iterator(p)) {
        // 現在の階層(深さ)を取得
        auto depth = fs::recursive_directory_iterator(p).depth(); // 注意:これは別の方法で取得が必要
        
        // entry自体から深さを知るには、イテレータを明示的に定義する
    }

    // 正しい深さの取得方法を含むループ
    fs::recursive_directory_iterator iter(p);
    fs::recursive_directory_iterator end;

    while (iter != end) {
        // インデントで階層を表現
        for (int i = 0; i < iter.depth(); ++i) std::cout << "  ";
        
        std::cout << "-> " << iter->path().filename() << std::endl;
        
        // 次の要素へ
        ++iter;
    }

    return 0;
}
$ bcc32c recur.cpp
Embarcadero C++ 7.70 for Win32 Copyright (c) 2012-2024 Embarcadero Technologies, Inc.
recur.cpp:
Turbo Incremental Link 6.99 Copyright (c) 1997-2024 Embarcadero Technologies, Inc.

jakeb@Orbit-11 MINGW64 ~/OneDrive/Documents/Embarcadero/Studio/Projects/directory_iterator_test
$ ./recur
プロジェクト内の全ファイルをリストアップします:
-> directory1
  -> alt..txt
-> recur.cpp
-> recur.exe
-> recur.tds
-> test1.cpp
-> test1.exe
-> test1.tds

再帰的にスキャンできていることが確認できた。実は既出のscan projectプログラムで既に使っているテクニックである。基本的には、C++ Builder CEないしDelphi界隈のString(UnicodeString)std::stringの相互変換が必要になることに注意が必要だ。

WindowsのファイルエクスプローラーへのファイルないしフォルダーのDrag and Dropを処理するために、以前の記事の、

を使う。FMXのプログラムを新規作成し、フォームは、

とりあえず、TMemoだけおいて、Unit1.hは、

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include <FMX.Controls.Presentation.hpp>
#include <FMX.Memo.hpp>
#include <FMX.Memo.Types.hpp>
#include <FMX.ScrollBox.hpp>
#include <FMX.Types.hpp>
#include <FMX.StdCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TMemo *Memo1;
private:	// ユーザー宣言
public:		// ユーザー宣言
	__fastcall TForm1(TComponent* Owner);
	virtual void __fastcall DragDrop(const Fmx::Types::TDragObject &Data, const System::Types::TPointF &Point);
	virtual void __fastcall DragOver(const Fmx::Types::TDragObject &Data, const System::Types::TPointF &Point, Fmx::Types::TDragOperation &Operation);

};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Unit1.cppは、directory_iteratorを使って、

#include <fmx.h>
#pragma hdrstop
#include <System.SysUtils.hpp>
#include <filesystem>

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"

namespace fs = std::filesystem;
TForm1 *Form1;

__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{

	Memo1->Lines->Add("working....");

}

void DigDirectory(String path)
{
	fs::path target_path = path.c_str();
	try {
		// directory_iteratorを使用してディレクトリ内を走査
		for (const fs::directory_entry& entry : fs::directory_iterator(target_path)) {
			// entry.path() でフルパスを取得し、filename() でファイル名のみを抽出
			//std::cout << entry.path().filename() << std::endl;
			//Form1->Memo1->Lines->Add( path + "\\" + entry.path().filename().c_str());
            Form1->Memo1->Lines->Add(entry.path().c_str());
		}
	} catch (const fs::filesystem_error& e) {
		// ディレクトリが存在しない場合などのエラー処理
		//std::cerr << "エラーが発生しました: " << e.what() << std::endl;
		ShowMessage("error");
	}


}


void __fastcall TForm1::DragDrop(const Fmx::Types::TDragObject &Data, const System::Types::TPointF &Point)
{
	TForm::DragDrop(Data,Point);
	for( int i = 0 ; i < Data.Files.Length ; i ++ ){
		if(DirectoryExists(Data.Files[i]))
			DigDirectory(Data.Files[i]);
		else
			Memo1->Lines->Add(Data.Files[i]);
	}


}

void __fastcall TForm1::DragOver(const Fmx::Types::TDragObject &Data, const System::Types::TPointF &Point, Fmx::Types::TDragOperation &Operation)
{
	TForm::DragOver(Data,Point,Operation);
	Operation = TDragOperation::Copy;

}

//---------------------------------------------------------------------------

Drag and Dropしたものの中にDirectoryがあれば、その中もリストする。そこにさらにDirectoryが在っても名前だけ記録する。

さらに、

の場合、

をDrag and Dropすると、

となる。さて、実際の動作はタイムスタンプの修正を行うのであるが、それは次回以降で。

コメント