スポンサーリンク

パス一覧をツリーに変換する。そしてzipファイルの項目をツリー表示する

libzipでファイル一覧を取得すると、元のディレクトリ構造が取得できるが、ツリーになっていない。これをツリーに変換する。

#include <iostream>

#include <vector>
#include <string>
#include <sstream>
#include <filesystem>

// SetConsoleOutputCP のために必要
#include <windows.h>

// libzip
#include <zip.h>

#pragma comment(lib,"zip.lib")
 
enum class FileType {
    Ignore,
    Directory,
    File
};

struct DirTree {
    std::string name;
    FileType type;
    std::vector<DirTree> children;
    DirTree(const std::string& name, const FileType type) : name(name), type(type){}
};

// 既に登録済みかどうかをチェックし、既にあるノードならイテレータを返す
std::vector<DirTree>::iterator getNodeIfAlreadyRegistered(DirTree& root, const std::string& name) {
    return 
        std::find_if(        
            root.children.begin(), 
            root.children.end(), 
            [&](const DirTree& child) {
                return child.name == name;
            }
        );
}

void AddPath(DirTree& root, const std::string& path) {

    namespace fs = std::filesystem;


    std::istringstream ss(path);
    std::string segment;
    DirTree* current = &root;


    // 次の'/'までのパスを取得
    while (std::getline(ss, segment, '/')) {

        // 過去にツリーに登録されたノードかどうかをチェック
        auto currentnode = getNodeIfAlreadyRegistered(*current, segment);

        // すでに登録済みなら次回以降のノードはそのノードより下に追加
        if (currentnode != current->children.end()) {
            current = &(*currentnode);
        }
        else {
            // 最後の要素以外はディレクトリであることは自明なので、ディレクトリとして登録
            current->children.push_back({ segment, FileType::Directory });
            current = &current->children.back();
        }
    }

    // 最後の要素はファイルの可能性があるので、pathに'/'があるかどうかで判別
    bool isDir = path.back() == '/';
    current->type = isDir ? FileType::Directory : FileType::File;
    
}

// ファイルリストをツリー構造に変換
DirTree BuildDirTree(const std::vector<std::string>& files) {
    DirTree root( "root", FileType::Ignore);
    for (const auto& file : files) {
        AddPath(root, file);
    }
    return root;
}

// ファイルツリーを表示
void printTree(const DirTree& tree, int depth = 0) { auto to_string = [](const FileType type) { switch (type) { case FileType::Ignore: return "*"; case FileType::Directory: return "[DIR]"; case FileType::File: return "[FILE]"; } return "Unknown"; }; std::string indent(depth * 2, ' '); std::cout << indent << to_string(tree.type) << tree.name << "\n"; for (const auto& child : tree.children) { printTree(child, depth + 1); } }
std::vector<std::string> FilesInZip(const char* pathname) {

    std::vector<std::string> files;

    // エラーコードを格納する変数
    int error = 0;
    // zipファイルを読み取り専用でオープン
    zip_t* zipArchive = zip_open(pathname, ZIP_RDONLY, &error);
    if (zipArchive == nullptr) {
        return std::vector<std::string>();
    }

    // zipファイル内のエントリ数を取得
    zip_int64_t numEntries = zip_get_num_entries(zipArchive, 0);

    // 各エントリの名前を取得して表示
    for (zip_uint64_t i = 0; i < static_cast<zip_uint64_t>(numEntries); ++i) {

        const char* entryName = zip_get_name(zipArchive, i, 0);

        files.emplace_back(entryName); // zipファイル内のファイル名を格納

    }

    // zipファイルをクローズ
    zip_close(zipArchive);

    return files;
}
      
int main()
{

    std::vector<std::string> files = FilesInZip((const char*)u8R"(C:\test\ConsoleApplication31.zip)");

    // windowsのコンソールでUTF-8を表示するために必要
    SetConsoleOutputCP(CP_UTF8);

    // ファイルのリストをツリー構造に変換
    DirTree root = BuildDirTree(files);
    printTree(root);


    for(auto& f : files) {
        std::cout << f << std::endl;
    }
}

実行例

まずfilesをそのまま表示すると以下のようになる。

.vs/
.vs/ConsoleApplication31/
.vs/ConsoleApplication31/copilot-chat/
.vs/ConsoleApplication31/copilot-chat/ff91ad84/
.vs/ConsoleApplication31/copilot-chat/ff91ad84/sessions/
.vs/ConsoleApplication31/FileContentIndex/
.vs/ConsoleApplication31/FileContentIndex/b5c23407-6b8a-446b-82cf-97b7abb15edd.vsidx

これをツリーにして、printTreeで出力すると以下になる。

*root
  [FILE]ConsoleApplication31.sln
  [DIR].vs
    [DIR]ConsoleApplication31
      [DIR]copilot-chat
        [DIR]ff91ad84
          [DIR]sessions
      [DIR]FileContentIndex
        [FILE]b5c23407-6b8a-446b-82cf-97b7abb15edd.vsidx
      [DIR]v17
        [FILE].suo
        [FILE]Browse.VC.db
        [FILE]DocumentLayout.json

コメントを残す

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

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: