ディレクトリ以下にあるファイルの総数を数える関数

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
shiro

ディレクトリ以下にあるファイルの総数を数える関数

#1

投稿記事 by shiro » 2年前

main.cの空欄であるfindFileByNameUnderDir関数の作り方がわかりません。教えていただけないでしょうか。
・main.c

コード:

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "directorytree.h"

DirNode* createSample() {
    DirNode* aDir = createDirNode("a");
    DirNode* bDir = createDirNode("b");
    DirNode* cDir = createDirNode("c");
    DirNode* dDir = createDirNode("d");

    FileNode* xFile = createFileNode("x.txt");
    FileNode* yFile = createFileNode("y.txt");
    FileNode* zFile = createFileNode("z.txt");
    FileNode* wFile = createFileNode("w.txt");

    addChildDir(aDir, bDir);
    addChildDir(aDir, cDir);
    addChildDir(cDir, dDir);

    addChildFile(aDir, xFile);
    addChildFile(bDir, yFile);
    addChildFile(bDir, zFile);
    addChildFile(bDir, wFile);

    return aDir;
}

/**
 * @desc    ファイルの表示
 * @param (fileNode) Fileへのポインタ
 * @param (indent) 表示インデント
 */
void printFileNode(FileNode* fileNode, size_t indent){
    assert(fileNode);
    for (int i = 0; i < indent; ++i) {
        // インデントを設定
        printf("  ");
    }

    printf("File: %s\n", fileNode->name);
}

/**
 * @desc    ディレクトリ構造の表示
 * @param (dirNode) ディレクトリへのポインタ
 * @param (indent) 表示インデント
 */
void printDirNode(DirNode* dirNode, size_t indent){
    assert(dirNode);
    for (int i = 0; i < indent; ++i) {
        // インデントを設定
        printf("  ");
    }

    printf("Dir: %s\n", dirNode->name);

    for (int i = 0; i < dirNode->childFileNum; ++i) {
        printFileNode(dirNode->fileChildren[i], indent+1);
    }

    for (int i = 0; i < dirNode->childDirNum; ++i) {
        printDirNode(dirNode->dirChildren[i], indent+1);
    }
}

/**
 * @desc ディレクトリ配下で指定した名前のファイルを検索する
 * @param (dirNode) ディレクトリ
 * @param (fileName) ファイル名
 * @return 見つかったらファイルノードのポインタを返す
 *         見つからなかったらNULLを返す
 */
FileNode* findFileByNameUnderDir(DirNode* dirNode, const char* fileName) {
/*ここ*/
}

/**
 * @desc ディレクトリ以下にあるファイルの総数を数える
 * @param (dirNode) ディレクトリ
 * @return ディレクトリ以下にあるファイルの総数
 */
size_t countFilesUnderDir(DirNode* dirNode) {
   size_t count=0;
    count+=dirNode->childFileNum;
    for(int i=0; i<dirNode->childDirNum; i++) {
        count+=countFilesUnderDir(dirNode->dirChildren[i]);
    }
    return count;
}

/**
 * 確認プログラム
 * assertに引っかからなければOK
 * 簡略のためエラー処理は省略しています
 */
int main(int argc, const char* argv[])
{
    DirNode* aDir = createSample();
    printDirNode(aDir, 0);

    DirNode* bDir = getChildDir(aDir, 0);
    DirNode* cDir = getChildDir(aDir, 1);

    FileNode* xFile = findFileByNameUnderDir(aDir, "x.txt");
    assert(xFile);
    assert(0 == strcmp(xFile->name, "x.txt"));

    FileNode* wFile = findFileByNameUnderDir(aDir, "w.txt");
    assert(wFile);
    assert(0 == strcmp(wFile->name, "w.txt"));

    FileNode* uFile = findFileByNameUnderDir(aDir, "u.txt");
    assert(!uFile);

    size_t a = countFilesUnderDir(aDir);
    assert(a == 4);

    size_t b = countFilesUnderDir(bDir);
    assert(b == 3);

    size_t c = countFilesUnderDir(cDir);
    assert(c == 0);

    deleteDirNode(aDir);
    return 0;
}
・directorytree.c

コード:

#define _CRT_SECURE_NO_WARNINGS
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include "directorytree.h"


/**
 * @desc    FileNodeの作成
 * @param (name) 名前 (NAME_MAX-1文字以内)
 * @return  FileNodeへのポインタ.メモリ確保失敗時はNULLを返す.
 * @detail  動的にメモリ確保しているため,
 *          不要になったらdeleteFileNodeを呼んで削除すること.
 */
FileNode* createFileNode(const char* name) {
    assert(name);
    FileNode* fileNode = (FileNode*)calloc(1, sizeof(FileNode));
    if (fileNode) {
        strncpy(fileNode->name, name, NAME_MAX);
        fileNode->name[NAME_MAX-1] = '\0';
    }
    return fileNode;
}

/**
 * @desc    FileNodeの削除
 * @param (fileNode) FileNodeへのポインタ
 * @detail  不要になったFileNodeをfreeで削除する.
 */
void deleteFileNode(FileNode* fileNode){
    assert(fileNode);
    free(fileNode);
}

/**
 * @desc    File名の取得
 * @param (fileNode) FileNodeへのポインタ
 * @return  FileNode名
 */
const char* getFileName(FileNode* fileNode){
    assert(fileNode);
    return fileNode->name;
}

/**
 * @desc    親ディレクトリの取得
 * @param (fileNode) FileNodeへのポインタ
 * @return  親DirNode
 */
DirNode* getParentDirOfFile(FileNode* fileNode){
    assert(fileNode);
    return fileNode->parent;
}

/**
 * @desc    DirNodeの作成
 * @param (name) 名前 (NAME_MAX-1文字以内)
 * @return  DirNodeへのポインタ.メモリ確保失敗時はNULLを返す.
 * @detail  動的にメモリ確保しているため,
 *          不要になったらdeleteDirNodeを呼んで削除すること.
 */
DirNode* createDirNode(const char* name){
    assert(name);
    DirNode* dirNode = (DirNode*)calloc(1, sizeof(DirNode));
    if (dirNode) {
        strncpy(dirNode->name, name, NAME_MAX);
        dirNode->name[NAME_MAX-1] = '\0';
    }
    return dirNode;
}

/**
 * @desc    DirNodeの削除
 * @param (dirNode) 削除するDirNode
 * @detail  不要になったDirNodeをfreeで削除する.
 *          登録されている子要素も削除する.
 */
void deleteDirNode(DirNode* dirNode){
    assert(dirNode);
    for (int i = 0; i < dirNode->childDirNum; ++i) {
        deleteDirNode(dirNode->dirChildren[i]);
    }
    free(dirNode->dirChildren);

    for (int i = 0; i < dirNode->childFileNum; ++i) {
        deleteFileNode(dirNode->fileChildren[i]);
    }
    free(dirNode->fileChildren);
    free(dirNode);
}


/**
 * @desc    ディレクトリ名の取得
 * @param (dirNode) DirNodeへのポインタ
 * @return  DirNode名
 */
const char* getDirName(DirNode* dirNode) {
    assert(dirNode);
    return dirNode->name;
}

/**
 * @desc    親ディレクトリの取得
 * @param (dirNode) DirNodeへのポインタ
 * @return  親DirNode
 */
DirNode* getParentDirOfDir(DirNode* dirNode){
    assert(dirNode);
    return dirNode->parent;
}


/**
 * @desc    子ディレクトリの個数の取得
 * @param (dirNode) DirNodeへのポインタ
 * @return  子ディレクトリの個数
 */
size_t getChildDirNum(DirNode* dirNode){
    assert(dirNode);
    return dirNode->childDirNum;
}

/**
 * @desc    子ディレクトリの取得
 * @param (dirNode) 親ディレクトリのポインタ
 * @param (i) 子ディレクトリのインデックス
 * @return  子ディレクトリのポインタ
 *          インデックス外であればNULLを返す
 */
DirNode* getChildDir(DirNode* dirNode, size_t i){
    assert(dirNode);
    if (dirNode->childDirNum <= i) {
        /* インデックス外 */
        return NULL;
    }
    return dirNode->dirChildren[i];
}

/**
 * @desc    子ディレクトリの追加
 * @param (parentDir) 親ディレクトリのポインタ
 * @param (childDir) 追加する子ディレクトリ
 * @return  成功したらNORMALLY_FINISHED,
 *          失敗したらそれ以外を返す.
 */
int addChildDir(DirNode* parentDir, DirNode* childDir){
    assert(parentDir);
    assert(childDir);

    if (parentDir->childDirNum >= parentDir->reservedDirNum) {
        size_t new_size = parentDir->reservedDirNum * 2;
        if (new_size == 0) {
            new_size = 1;
        }
        DirNode** p = (DirNode**)realloc(parentDir->dirChildren, sizeof(DirNode*) * new_size);
        if (!p) {
            return ALLOCATION_ERROR;
        }

        parentDir->dirChildren = p;
        parentDir->reservedDirNum = new_size;
    }

    parentDir->dirChildren[parentDir->childDirNum] = childDir;
    parentDir->childDirNum += 1;
    childDir->parent = parentDir;

    return NORMALLY_FINISHED;
}

/**
 * @desc    子ディレクトリの削除
 * @param (parentDir) 親ディレクトリのポインタ
 * @param (i) 削除する子ディレクトリのインデックス
 * @return  成功したらNORMALLY_FINISHED,
 *          失敗したらそれ以外を返す.
 */
int removeChildDir(DirNode* parentDir, size_t i){
    if (parentDir->childDirNum <= i) {
        return OUT_OF_RANGE_ERROR;
    }

    if (i < parentDir->childDirNum - 1) {
        deleteDirNode(parentDir->dirChildren[i]);
        memmove(parentDir->dirChildren + i,
                parentDir->dirChildren + i+1,
                (parentDir->childDirNum-i-1) * sizeof(DirNode*));
    }
    parentDir->childDirNum -= 1;

    return NORMALLY_FINISHED;
}


/**
 * @desc    子ファイルの個数の取得
 * @param (dirNode) DirNodeへのポインタ
 * @return  子ファイルの個数
 */
size_t getChildFileNum(DirNode* dirNode){
    assert(dirNode);
    return dirNode->childFileNum;
}

/**
 * @desc    子ファイルの取得
 * @param (dirNode) 親ディレクトリのポインタ
 * @param (i)) 子ファイルのインデックス
 * @return  子ファイルのポインタ
 *          インデックス外であればNULLを返す
 */
FileNode* getChildFile(DirNode* dirNode, size_t i){
    assert(dirNode);
    if (dirNode->childFileNum <= i) {
        /* インデックス外 */
        return NULL;
    }
    return dirNode->fileChildren[i];
}

/**
 * @desc    子ファイルの追加
 * @param (parentDir) 親ディレクトリのポインタ
 * @param (childFile) 追加する子ファイル
 * @return  成功したらNORMALLY_FINISHED,
 *          失敗したらそれ以外を返す.
 */
int addChildFile(DirNode* parentDir, FileNode* childFile){
    assert(parentDir);
    assert(childFile);

    if (parentDir->childFileNum >= parentDir->reservedFileNum) {
        size_t new_size = parentDir->reservedFileNum * 2;
        if (new_size == 0) {
            new_size = 1;
        }
        FileNode** p = (FileNode**)realloc(parentDir->fileChildren, sizeof(FileNode*) * new_size);
        if (!p) {
            return ALLOCATION_ERROR;
        }

        parentDir->fileChildren = p;
        parentDir->reservedFileNum = new_size;
    }

    parentDir->fileChildren[parentDir->childFileNum] = childFile;
    parentDir->childFileNum += 1;
    childFile->parent = parentDir;

    return NORMALLY_FINISHED;
}

/**
 * @desc    子ファイルの削除
 * @param (parentDir) 親ディレクトリのポインタ
 * @param (i) 削除する子ファイルのインデックス
 * @return  成功したらNORMALLY_FINISHED,
 *          失敗したらそれ以外を返す.
 */
int removeChildFile(DirNode* parentDir, size_t i){
    if (parentDir->childFileNum <= i) {
        return OUT_OF_RANGE_ERROR;
    }

    if (i < parentDir->childDirNum - 1) {
        deleteFileNode(parentDir->fileChildren[i]);
        memmove(parentDir->fileChildren + i,
                parentDir->fileChildren + i+1,
                (parentDir->childFileNum-i-1) * sizeof(FileNode*));
    }
    parentDir->childFileNum -= 1;

    return NORMALLY_FINISHED;
}


・directorytree.h

コード:

#pragma once

#define NAME_MAX 100

#define NORMALLY_FINISHED 0
#define ALLOCATION_ERROR 1001
#define OUT_OF_RANGE_ERROR 1002

struct _dir_node;

typedef struct _file_node {
    char name[NAME_MAX];            // ファイル名
    struct _dir_node* parent;       // 親ディレクトリ
} FileNode;

typedef struct _dir_node {
    char name[NAME_MAX];                /* ディレクトリ名 */
    struct _dir_node* parent;           /* 親ディレクトリ */
    struct _dir_node** dirChildren;     /* 子ディレクトリ(複数かも) */
    struct _file_node** fileChildren;   /* 子ファイル(複数かも) */
    int childDirNum;                    /* 子ディレクトリの数 */
    int reservedDirNum;                 /* 子ディレクトリの配列の長さ */
    int childFileNum;                   /* 子ファイルの数 */
    int reservedFileNum;                /* 子ファイルの配列の長さ */
} DirNode;

FileNode* createFileNode(const char* name);
void deleteFileNode(FileNode* fileNode);
const char* getFileName(FileNode* fileNode);
DirNode* getParentDirOfFile(FileNode* fileNode);

DirNode* createDirNode(const char* name);
void deleteDirNode(DirNode* dirNode);
const char* getDirName(DirNode* dirNode);
DirNode* getParentDirOfDir(DirNode* dirNode);
size_t getChildDirNum(DirNode* dirNode);
DirNode* getChildDir(DirNode* dirNode, size_t i);
int addChildDir(DirNode* parentDir, DirNode* childDir);
int removeChildDir(DirNode* parentDir, size_t i);
size_t getChildFileNum(DirNode* dirNode);
FileNode* getChildFile(DirNode* dirNode, size_t i);
int addChildFile(DirNode* parentDir, FileNode* childFile);
int removeChildFile(DirNode* parentDir, size_t i);


shiro

Re: ディレクトリ以下にあるファイルの総数を数える関数

#2

投稿記事 by shiro » 2年前

タイトル間違えました。
ディレクトリ配下で指定した名前のファイルを検索する関数を作りたいです。すみません。

返信

“C言語何でも質問掲示板” へ戻る