站内搜索

C语言中deltree程序的实现

原帖及讨论:http://bbs.bccn.net/thread-121244-1-1.html

     我是出生在dos流行的年代,所以对于以前dos中提供的一些软件很怀念,想必用过dos的朋友都知道deltree这个程序吧,这个程序提供了用户快速删除指定目录及其子目录中的所有文件快捷功能。因为用惯了dos的缘故,有时候总觉得这样的删除文件方式比起windows中删除文件夹的方法方便的多,但是现在安装完的windows都已经没有这些程序了,我想一些经典的程序还是应该留下吧,特此编写了一个类似功能的程序,当然论功能的话可能没有真正dos中提供的deltree强大,只是作为一个数据结构的应用吧,希望大家共同学习讨论。

代码导读:
我程序编写得顺序是这样的,首先实现deltree.h
1)编写数据结构
2)编写DrawPhy2LogTree()函数
3)编写DisplayTree()函数,为了进行测试
4)添加调试宏__DEBUG
5)添加最大栈容量宏MAX_STACK_SIZE
6)编写DelTree()函数
编写deltree.cpp和deltree.h其实是同步进行的,当写完DrawPhy2LogTree和DisplayTree时就进行main()函数编写,以便调试,以后就是每写一个函数进行测试,最后将__DEBUG注释掉,真正实现删除功能(在调试期间不对文件进行删除操作也是为了安全考虑)
刚完成时的作品DisplayTree使用递归方法来打印树的,后来发现若文件夹层次太深的话,会递归算法会导致栈满而溢出,就改进成为使用栈的方法进行遍历。
若大家有兴趣的话,可以根据我上面的流程进行代码导读,若能发现问题或是对算法的改进有更好的思路,请及时回复指教,不胜感激,谢谢。

在这里祝大家新年快乐,身体健康,学习进步,工作顺利

早上用了下这个程序发现搜索过程中若发现有特殊属性的文件会导致软件崩溃,特此做了个新版deltree,因为使用VC++做的,而且调用了windows中的一些函数,故将其版本称之为32位deltree,即命名为deltree32

原理还是一样,更新如下
* 添加错误处理
* 废除固定长度的栈,使用动态长度的栈
* 减少数据结构操作时的代码冗余(16位版又在创建树的节点和删除节点时存在冗余),现在将这两个操作封装到函数中。
* 废除main()函数中的路径缩紧算法(这个算法主要针对在dos下文件名或文件夹名不能超过8个字符的限制),添加了长路径合并算法(也就是说从参数1一直到argc-1都可以用作路径,中间的空格被自动合并到长路径中)

点击下面附件,下载源代码。
16位版下载(TC3.0下编译)
点击下载该文件

32位版下载(Visual Studio 2005的工程)
点击下载该文件

这里我也把源代码贴一下,方便大家浏览
/* deltree.h */
#ifndef __DELTREE_H
#define __DELTREE_H

// 调试宏
//#define __DEBUG

#define MAX_STACK_SIZE 1024

typedef enum { tpFile, tpDir } ATTRIB_T;
typedef enum { False = 0, True } BOOL_T;

typedef struct tagFileNode {
    
    ATTRIB_T oFSAttr;                        // 节点类型(tpFile = 文件, tpDir = 目录)
    char *pFName;                            // 文件名(当tpDir时,为目录名)

    struct tagFileNode *pParent;            // 父节点
    
    struct tagFileNode *pNext;                // 子节点链表
    struct tagFileNode *pPrev;
    
    struct tagFileNode *pDesecentHead;        // 下一层节点
    struct tagFileNode *pDesecentTail;

} ATTR_FS_TREE_NODE;

// 将物理路径(就是硬文件系统)映射到内存路径树(对应该软件的数据结构)
ATTR_FS_TREE_NODE *DrawPhy2LogTree( char *path ) {
    
    int done;
    int len;
    int top = (int)-1;
    struct ffblk ffblk;
    
    // 临时字符串,为了创建查找使用串而设立
    char *pTempStr;

    // 最大文件夹数
    ATTR_FS_TREE_NODE *pStack[MAX_STACK_SIZE];
    // 临时节点指针
    ATTR_FS_TREE_NODE *pTemp;
    ATTR_FS_TREE_NODE *p;

    // 路径根
    ATTR_FS_TREE_NODE *pRoot = (ATTR_FS_TREE_NODE *)malloc(sizeof(ATTR_FS_TREE_NODE));
    assert( pRoot );

    if( path == (char *)0 )
        return (ATTR_FS_TREE_NODE *)0;
    
    // 创建根
    pRoot->pFName = new char[strlen(path)+1];
    strcpy( pRoot->pFName, path );
    
    pRoot->oFSAttr = tpDir;

    // 初始化根节点
    pRoot->pDesecentHead = (ATTR_FS_TREE_NODE *)0;
    pRoot->pDesecentTail = (ATTR_FS_TREE_NODE *)0;
    pRoot->pNext = (ATTR_FS_TREE_NODE *)0;
    pRoot->pPrev = (ATTR_FS_TREE_NODE *)0;
    pRoot->pParent = (ATTR_FS_TREE_NODE *)0;

    // 压栈处理(这里为了效率不用递归遍历路径)
    pStack[++top] = pRoot;

    while( top >= (int)0 ) {
        // 取出需要处理的路径
        pTemp = pStack[top--];
        
        // 构造查找串,这里我们查找所有文件或目录,在结尾添加"/*.*"即可
        len = strlen(pTemp->pFName);
        pTempStr = new char[len + 5];
        strcpy( pTempStr, pTemp->pFName );
        strcat( pTempStr, "//*.*" );

        // 进行文件夹与文件的搜索(包含隐藏文件、只读文件,但不包含系统文件)
        done = findfirst( pTempStr, &ffblk, FA_NORMAL | FA_DIREC | FA_RDONLY | FA_HIDDEN );
        while( !done ) {
            // 测试当前获取的路径或文件名是否有效
            // "." 或 ".."都不是我们需要的路径
            if( ffblk.ff_name[0] == '.' ) {
                done = findnext( &ffblk );
                continue;
            }
        
            // 保存文件夹到当前正在处理的节点
            // 当前节点没有子节点
            if( pTemp->pDesecentHead == (ATTR_FS_TREE_NODE *)0 ) {
                pTemp->pDesecentHead = (ATTR_FS_TREE_NODE *)malloc(sizeof(ATTR_FS_TREE_NODE));
                assert( pTemp->pDesecentHead );
                p = pTemp->pDesecentHead;

                // 填充节点内容
                p->pFName = (char *)malloc(sizeof(char) * (len + strlen(ffblk.ff_name) + 2));
                assert(p->pFName);
                strcpy( p->pFName, pTemp->pFName ); // len个字节
                strcat( p->pFName, "//" );            // 1个字节
                strcat( p->pFName, ffblk.ff_name ); // strlen(ffblk.ff_name) + 1个字节
                
                // 判断是否为文件夹
                if( ffblk.ff_attrib != FA_DIREC )
                    p->oFSAttr = tpFile;
                else {
                    // 将新添加的目录压栈
                    pStack[++top] = p;
                    p->oFSAttr = tpDir;
                }

                p->pDesecentHead = (ATTR_FS_TREE_NODE *)0;
                p->pDesecentTail = (ATTR_FS_TREE_NODE *)0;
                p->pNext = (ATTR_FS_TREE_NODE *)0;
                p->pPrev = (ATTR_FS_TREE_NODE *)0;
                p->pParent = pTemp;
                
                pTemp->pDesecentTail = p;
            }
            // 当前节点有子节点
            else {
                pTemp->pDesecentTail->pNext = (ATTR_FS_TREE_NODE *)malloc(sizeof(ATTR_FS_TREE_NODE));
                p = pTemp->pDesecentTail->pNext;
                assert(p);

                p->pFName = (char *)malloc(sizeof(char) * (len + strlen(ffblk.ff_name) + 2));
                assert(p->pFName);
                strcpy( p->pFName, pTemp->pFName );
                strcat( p->pFName, "//" );
                strcat( p->pFName, ffblk.ff_name );

                if( ffblk.ff_attrib != FA_DIREC )
                    p->oFSAttr = tpFile;
                else {
                    pStack[++top] = p;
                    p->oFSAttr = tpDir;
                }

                p->pDesecentHead = (ATTR_FS_TREE_NODE *)0;
                p->pDesecentTail = (ATTR_FS_TREE_NODE *)0;
                p->pNext = (ATTR_FS_TREE_NODE *)0;
                p->pPrev = pTemp->pDesecentTail;
                pTemp->pDesecentTail->pNext = p;
                p->pParent = pTemp;

                pTemp->pDesecentTail = p;
            }
            // 继续往下搜索
            done = findnext( &ffblk );
        }
        delete []pTempStr;
        pTempStr = (char *)0;    
    }
    // 完成后返回根路进
    return pRoot;
}

// 删除指定目录树
void DelTree( ATTR_FS_TREE_NODE *pRoot ) {
    int top = (int)-1;
    ATTR_FS_TREE_NODE *pStack[MAX_STACK_SIZE];
    ATTR_FS_TREE_NODE *pTemp, *p;

    BOOL_T flag; // 鉴定指定层是否有下一级目录

    pStack[++top] = pRoot;
    while( top >= (int)0 ) {
        flag = False; // 假设该层没有下一级目录
        pTemp = pStack[top--];
        // 消除该层文件,并将该层的子目录进栈
        p = pTemp->pDesecentHead;
        while( p != (ATTR_FS_TREE_NODE *)0 ) {
            if( p->oFSAttr == tpDir ) { //若是目录则进栈
                if( flag != True ) {    // 该操作必须在子目录压栈前操作
                    flag = True;
                    pStack[++top] = pTemp; // 重新将带有子目录的根目录压栈为了以后的目录删除操作
                }
                pStack[++top] = p;
                p = p->pNext;
            }
            else { //若是文件删除
                // 调试状态下不进行删除操作,为了数据安全
#ifndef __DEBUG
                unlink(p->pFName);
#endif
                printf("%s has been deleted!/n", p->pFName);
                // 删除该节点
                if( p->pPrev != (ATTR_FS_TREE_NODE *)0 )
                    p->pPrev->pNext = p->pNext;
                if( p->pNext != (ATTR_FS_TREE_NODE *)0 )
                    p->pNext->pPrev = p->pPrev;
                if( p == pTemp->pDesecentHead )
                    pTemp->pDesecentHead = p->pNext;
                else if( p == pTemp->pDesecentTail ) {
                    if( p->pPrev != (ATTR_FS_TREE_NODE *)0 )
                        p->pPrev->pNext = (ATTR_FS_TREE_NODE *)0;
                    pTemp->pDesecentTail = p->pPrev;
                }
                // 暂时将p->pNext压栈进行删除操作
                pStack[++top] = p->pNext;
                // 删除名称项
                free(p->pFName);
                free(p);
                p = pStack[top--];    
            }
        }
        // 说明该目录没有下一层子目录,直接删除该目录
        if( flag == False ) {
#ifndef __DEBUG
            rmdir( pTemp->pFName );
#endif
            printf("[%s] has been removed!/n", pTemp->pFName);
            p = pTemp->pParent;
            
            if( pTemp->pPrev != (ATTR_FS_TREE_NODE *)0 )
                pTemp->pPrev->pNext = pTemp->pNext;
            if( pTemp->pNext != (ATTR_FS_TREE_NODE *)0 )
                pTemp->pNext->pPrev = pTemp->pPrev;
            
            if( p != (ATTR_FS_TREE_NODE *)0 ) {
                if( pTemp == p->pDesecentHead )
                    p->pDesecentHead = pTemp->pNext;
                else if( pTemp == p->pDesecentTail ) {
                    if( pTemp->pPrev != (ATTR_FS_TREE_NODE *)0 )
                        pTemp->pPrev->pNext = (ATTR_FS_TREE_NODE *)0;
                    p->pDesecentTail = pTemp->pPrev;
                }
            }
            free(pTemp->pFName);
            free(pTemp);
        }
    }
}

#ifdef __DEBUG
// 先序遍历文件树
void DisplayTree( ATTR_FS_TREE_NODE *pRoot ) {
    ATTR_FS_TREE_NODE *p;
    ATTR_FS_TREE_NODE *pStack[MAX_STACK_SIZE];
    
    int top = (int)-1;
    pStack[++top] = pRoot;

    while( top >= (int)0 ) {
        p = pStack[top--];
        printf("[%s]/n",p->pFName);

        p = p->pDesecentHead;
        while( p != (ATTR_FS_TREE_NODE *)0 ) {
            if( p->oFSAttr == tpDir )
                //DisplayTree( p );
                pStack[++top] = p;
            else
                printf("%s/n", p->pFName);
            p = p->pNext;
        }
    }
}
#endif

#endif

/* deltree.cpp */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <dir.h>
#include <conio.h>

#include "deltree.h"

int main(int argc, char *argv[]) {
    ATTR_FS_TREE_NODE *pRoot;
    
    int i, j;
    int len, done;
    struct ffblk ffblk;

    char c;

    if( argc != (int)2 ) {
        printf("Deltree simple version/n");
        printf("Usage: %s <directory>/n/n", argv[0]);
        printf("eg. %s d://testdir/n", argv[0]);
        printf("[NOTICE] Delete any logical driver root is forbidden!/n");
    }
    else {
        // 判断是否为逻辑盘根
        if( strlen(argv[1]) == (int)2 && argv[1][1] == ':' ) {
            printf("Delete any logical driver root is forbidden!/n");
        }
        else {
            // 收集路径
            len = i = strlen(argv[1]) - 1;
            while( argv[1][i--] != '//' && i >= 0 );
            // 若路径长度大于8则自动缩进
            if( (j = (len - i - 1)) > 8 ) {
                argv[1][ (j =  (i + 1 + (j - 8) + 6)) ] = '~';
                argv[1][++j] = '1';
                argv[1][++j] = '/0';
            }
            // 确认是否要删除,为了安全考虑
            do {
                printf("Do you really want to REMOVE [%s] and its sub-directories within all files? (Y/N) ", argv[1]);
                c = getchar();
            } while( c != 'Y' && c != 'y' && c != 'N' && c != 'n' );

            if( c == 'N' || c == 'n' )
                return (int)0;

            // 查看指定路径是否存在
            done = findfirst( argv[1], &ffblk, FA_DIREC );
            if(!done) { //指定路径存在
                pRoot = DrawPhy2LogTree( argv[1] );
                DelTree( pRoot );
                pRoot = (ATTR_FS_TREE_NODE *)0;
                printf("/nAll done!/n");
            }
            else
                printf("Path not found!/n");
        }
    }
    return 0;
}

这里贴上32位的deltree代码
/* deltree32.h */
#ifndef __DELTREE32_H
#define __DELTREE32_H

//#define __DEBUG

// 错误定义
#define ERR_OK                            0x0000
#define ERR_UNEXPECT_POINTER            0x0001
#define ERR_NODE_REMOVE_FAILED            0x0002
#define ERR_INVAILD_POINTER                0x0003
#define ERR_DS_EMPTY                    0x0004
#define ERR_FS_TREE_EMPTY                0x0005
#define ERR_DS_PUSH_FAILED                0x0006
#define ERR_DS_POP_FAILED                0x0007
#define ERR_UNKNOWN                        0xffff

typedef enum { tpFile, tpDir } ATTRIB_T;

typedef struct tagFSNodeInfo {
    WORD wDirCnt;            // 文件夹数
    WORD wFileCnt;            // 文件数
} ATTR_FS_NODE_INFO;

typedef struct tagFSTreeNode {
    ATTRIB_T oFSNodeType;                        // 节点类型(目录还是文件)
    ATTR_FS_NODE_INFO oInfo;                    // 节点信息

    char *pFName;                                // 文件名(oFSNodeType = tpDir时表示目录名)

    struct tagFSTreeNode *pParent;                // 父节点
    struct tagFSTreeNode *pPrev;                // 该层的前一个节点
    struct tagFSTreeNode *pNext;                // 该层的下一个节点

    struct tagFSTreeNode *pDesecentHead;        // 下一层节点链表表头
    struct tagFSTreeNode *pDesecentTail;        // 下一层节点链表表尾
} ATTR_FS_TREE_NODE;

typedef struct tagDymStackNode {
    ATTR_FS_TREE_NODE *pFSTreeNode;                // 动态栈的每个单元所容纳的是ATTR_FS_TREE_NODE类型的变量
    struct tagDymStackNode *pNext;
    struct tagDymStackNode *pPrev;
} ATTR_DYM_STACK_NODE;

// 错误报告函数
void ErrReport( WORD wErrId ) {
    switch( wErrId ) {
        case 0x0001:
            printf("Unexpected pointer!/n");
            break;
        case 0x0002:
            printf("Specified logical tree node cannot be removed due to it is not empty!/n");
            break;
        case 0x0003:
            printf("Invailed pointer reference!/n");
            break;
        case 0x0004:
            printf("Specified dynamic stack is empty!/n");
            break;
        case 0x0005:
            printf("Specified logical tree is empty!/n");
            break;
        case 0x0006:
            printf("Push stack failed!/n");
            break;
        case 0x0007:
            printf("Pop stack failed!/n");
            break;
        case 0xffff:
            printf("Unexpected error!/n");
            break;
    }
}

// 创建一个节点
ATTR_FS_TREE_NODE *CreateFSTreeNode( ATTRIB_T oFSNodeType, const char *pFName ) {
    ATTR_FS_TREE_NODE *pNode = new ATTR_FS_TREE_NODE;
    assert( pNode );

    pNode->oFSNodeType = oFSNodeType;
    pNode->pFName = new char[strlen(pFName) + 1];
    assert( pNode->pFName );
    strcpy( pNode->pFName, pFName );

    pNode->oInfo.wDirCnt = (WORD)0;
    pNode->oInfo.wFileCnt = (WORD)0;
    
    pNode->pParent = (ATTR_FS_TREE_NODE *)0;
    pNode->pNext   = (ATTR_FS_TREE_NODE *)0;
    pNode->pPrev   = (ATTR_FS_TREE_NODE *)0;

    pNode->pDesecentHead = (ATTR_FS_TREE_NODE *)0;
    pNode->pDesecentTail = (ATTR_FS_TREE_NODE *)0;

    return pNode;
}

// 指定节点中添加一个字节点
WORD AddFSTreeNode( ATTR_FS_TREE_NODE *pNode, ATTR_FS_TREE_NODE *pSubNode ) {
    if( pNode == (ATTR_FS_TREE_NODE *)0 || pSubNode == (ATTR_FS_TREE_NODE *)0 )
        return (WORD)ERR_UNEXPECT_POINTER;
    
    // 该节点没有子节点
    if( pNode->pDesecentHead == (ATTR_FS_TREE_NODE *)0 ) {
        pNode->pDesecentHead = pSubNode;
        pNode->pDesecentTail = pSubNode;
        pSubNode->pParent = pNode;
        // 更新节点信息
        if( pSubNode->oFSNodeType == tpFile )
            pNode->oInfo.wFileCnt++;
        else
            pNode->oInfo.wDirCnt++;
    }
    else {
        pNode->pDesecentTail->pNext = pSubNode;
        pSubNode->pPrev = pNode->pDesecentTail;
        pSubNode->pParent = pNode;
        pNode->pDesecentTail = pSubNode;
        if( pSubNode->oFSNodeType == tpFile )
            pNode->oInfo.wFileCnt++;
        else
            pNode->oInfo.wDirCnt++;
    }
    return (WORD)ERR_OK;
}

// 删除指定节点
WORD DelFSTreeNode( ATTR_FS_TREE_NODE **dpNode ) {
    ATTR_FS_TREE_NODE *pNode;
    ATTR_FS_TREE_NODE *pParent;

    if( dpNode == (ATTR_FS_TREE_NODE **)0 )
        return (WORD)ERR_INVAILD_POINTER;

    if( (pNode = (*dpNode)) == (ATTR_FS_TREE_NODE *)0 )
        return (WORD)ERR_UNEXPECT_POINTER;
    
    // 获取欲删除节点的父节点
    pParent = pNode->pParent;
    // 若删除的节点是目录节点,但目录不为空,则删除失败
    if( pNode->oFSNodeType == tpDir && ( pNode->oInfo.wDirCnt + pNode->oInfo.wFileCnt ) != (WORD)0 )
        return (WORD)ERR_NODE_REMOVE_FAILED;

    if( pNode->pPrev != (ATTR_FS_TREE_NODE *)0 )
        pNode->pPrev->pNext = pNode->pNext;
    if( pNode->pNext != (ATTR_FS_TREE_NODE *)0 )
        pNode->pNext->pPrev = pNode->pPrev;

    if( pParent != (ATTR_FS_TREE_NODE *)0 ) {
        // 若欲删除的节点是该层的首节点
        if( pNode == pParent->pDesecentHead ) {
            pParent->pDesecentHead = pNode->pNext;
            if( pParent->pDesecentHead != (ATTR_FS_TREE_NODE *)0 )
                pParent->pDesecentHead->pPrev = (ATTR_FS_TREE_NODE *)0;
        }
        // 反之欲删除的节点是该层的尾节点
        else if( pNode == pParent->pDesecentTail ) {
            pParent->pDesecentTail = pNode->pPrev;
            if( pParent->pDesecentTail != (ATTR_FS_TREE_NODE *)0 )
                pParent->pDesecentTail->pNext = (ATTR_FS_TREE_NODE *)0;
        }
        // 更新父节点信息
        if( pNode->oFSNodeType == tpFile )
            pParent->oInfo.wFileCnt--;
        else
            pParent->oInfo.wDirCnt--;
    }
    // 删除节点
    delete []pNode->pFName;
    delete pNode;
    *dpNode = (ATTR_FS_TREE_NODE *)0;
    return (WORD)ERR_OK;
}

// 将节点压入动态栈
WORD DSPush( ATTR_DYM_STACK_NODE **dpStackTop, ATTR_FS_TREE_NODE *pNode ) {
    ATTR_DYM_STACK_NODE *pStackTop;
    if( dpStackTop == (ATTR_DYM_STACK_NODE **)0 )
        return (WORD)ERR_INVAILD_POINTER;
    pStackTop = *dpStackTop;
    // 栈为空
    if( pStackTop == (ATTR_DYM_STACK_NODE *)0 ) {
        pStackTop = *dpStackTop = new ATTR_DYM_STACK_NODE;
        pStackTop->pFSTreeNode = pNode;
        pStackTop->pNext = (ATTR_DYM_STACK_NODE *)0;
        pStackTop->pPrev = (ATTR_DYM_STACK_NODE *)0;
    }
    // 栈非空则进行尾部压栈操作
    else {
        pStackTop->pNext = new ATTR_DYM_STACK_NODE;
        pStackTop->pNext->pPrev = pStackTop;
        pStackTop = pStackTop->pNext;
        pStackTop->pNext = (ATTR_DYM_STACK_NODE *)0;
        pStackTop->pFSTreeNode = pNode;
        *dpStackTop = pStackTop;
    }
    return (WORD)ERR_OK;
}

// 将节点从动态栈中弹出
WORD DSPop( ATTR_DYM_STACK_NODE **dpStackTop, ATTR_FS_TREE_NODE **pNode ) {
    ATTR_DYM_STACK_NODE *pStackTop;

    if( dpStackTop == (ATTR_DYM_STACK_NODE **)0 || pNode == (ATTR_FS_TREE_NODE **)0 )
        return (WORD)ERR_INVAILD_POINTER;
    pStackTop = *dpStackTop;
    // 栈为空
    if( pStackTop == (ATTR_DYM_STACK_NODE *)0 )
        return (WORD)ERR_DS_EMPTY;

    (*pNode) = pStackTop->pFSTreeNode;
    (*dpStackTop) = pStackTop->pPrev;
    if( (*dpStackTop) != (ATTR_DYM_STACK_NODE *)0 )
        (*dpStackTop)->pNext = (ATTR_DYM_STACK_NODE *)0;

    delete pStackTop;
    return (WORD)ERR_OK;
}

// 删除逻辑树(仅当发生错误时使用)
WORD DestoryFSTree( ATTR_FS_TREE_NODE **dpRoot ) {
    ATTR_FS_TREE_NODE *pNode;
    ATTR_FS_TREE_NODE *pNodeTmp;
    ATTR_FS_TREE_NODE **dpNode;

    ATTR_DYM_STACK_NODE **dpStackTop;

    if( dpRoot == (ATTR_FS_TREE_NODE **)0 )
        return (WORD)ERR_INVAILD_POINTER;
    if( *dpRoot == (ATTR_FS_TREE_NODE *)0 )
        return (WORD)ERR_FS_TREE_EMPTY;
    
    // 初始化栈
    dpStackTop = new (ATTR_DYM_STACK_NODE *);
    assert(dpStackTop);
    *dpStackTop = (ATTR_DYM_STACK_NODE *)0;
    
    // 初始化临时节点
    dpNode = new (ATTR_FS_TREE_NODE *);
    assert(dpNode);
    *dpNode = (ATTR_FS_TREE_NODE *)0;

    if( DSPush( dpStackTop, *dpRoot ) != (WORD)ERR_OK ) {
        delete dpStackTop;
        delete dpNode;
        return (WORD)ERR_DS_PUSH_FAILED;
    }

    while( (*dpStackTop) != (ATTR_DYM_STACK_NODE *)0 ) {
        if( DSPop( dpStackTop, dpNode ) != (WORD)ERR_OK ) {
            delete dpStackTop;
            delete dpNode;
            return (WORD)ERR_DS_POP_FAILED;
        }
        pNode = (*dpNode)->pDesecentHead;
        while( pNode != (ATTR_FS_TREE_NODE *)0 ) {
            // 若是目录则压栈
            if( pNode->oFSNodeType == tpDir ) {
                if( DSPush( dpStackTop, pNode ) != ERR_OK ) {
                    delete dpStackTop;
                    delete dpNode;
                    return (WORD)ERR_DS_PUSH_FAILED;
                }
                pNode = pNode->pNext;
            }
            // 若是文件则直接删除该节点
            else {
                pNodeTmp = pNode->pNext;
                delete []pNode->pFName;
                delete pNode;
                pNode = pNodeTmp;
            }
        }
        // 该层所有节点处理完之后删除当前节点
        delete []((*dpNode)->pFName);
        delete (*dpNode);
    }
    // 删除完成后处理临时变量
    delete dpStackTop;
    delete dpNode;
    *dpRoot = (ATTR_FS_TREE_NODE *)0;
    return (WORD)ERR_OK;
}

// 将物理路径(就是硬文件系统)映射到内存路径树(对应该软件的数据结构)
ATTR_FS_TREE_NODE *DrawPhy2LogTree( const char *path ) {
    LPWIN32_FIND_DATAA pFd;
    
    ATTR_FS_TREE_NODE *p;
    ATTR_FS_TREE_NODE *pRoot;
    ATTR_FS_TREE_NODE **dpNode;
    
    ATTR_DYM_STACK_NODE **dpStackTop;        // 动态栈
    ATTR_DYM_STACK_NODE *pStackTop;            // 错误处理时使用

    HANDLE hFind;                            // 搜索使用句柄

    char *pTempStr;                            // 临时字符串
    char *pImm;                                // 这个也是
    int len;
    bool isDone;                            // 搜索任务是否完成(默认没有完成)

    if( path == (const char *)0 )
        return (ATTR_FS_TREE_NODE *)0;

    // 初始化动态栈
    dpStackTop = new (ATTR_DYM_STACK_NODE *);
    assert(dpStackTop);
    (*dpStackTop) = (ATTR_DYM_STACK_NODE *)0;

    // 初始化临时节点
    dpNode = new (ATTR_FS_TREE_NODE *);
    assert(dpNode);
    (*dpNode) = (ATTR_FS_TREE_NODE *)0;

    // 初始化pFd
    pFd = new WIN32_FIND_DATAA;
    assert(pFd);

    // 创建根节点
    pRoot = CreateFSTreeNode( tpDir, path );
    // 根压栈
    if( DSPush( dpStackTop, pRoot ) != (WORD)ERR_OK ) {
        ErrReport( (WORD)ERR_DS_PUSH_FAILED );
        DestoryFSTree( &pRoot );
        
        delete pFd;
        delete dpStackTop;
        delete dpNode;
        return (ATTR_FS_TREE_NODE *)0;
    }

    // 栈不为空时进行循环搜索
    while( (*dpStackTop) != (ATTR_DYM_STACK_NODE *)0 ) {
        if( DSPop( dpStackTop, dpNode ) != (WORD)ERR_OK ) {
            ErrReport( (WORD)ERR_DS_POP_FAILED );
            DestoryFSTree( &pRoot );
            
            delete pFd;
            delete dpStackTop;
            delete dpNode;
            return (ATTR_FS_TREE_NODE *)0;
        }
        isDone = false;

        // 创建查找串
        len = (int)strlen( (*dpNode)->pFName );
        pTempStr = new char[len + 5];
        strcpy(pTempStr, (*dpNode)->pFName);
        strcat(pTempStr,"//*.*");

        // 搜索文件及文件夹
        hFind = FindFirstFileA( pTempStr, pFd );
        while( isDone != true ) {
            // '.'或'..'不是我们所要的目录或文件
            if( pFd->cFileName[0] != '.' ) {
                pImm = new char[len + strlen( (const char *)pFd->cFileName ) + 2];
                strcpy(pImm, (*dpNode)->pFName);
                strcat(pImm, "//");
                strcat(pImm, (const char *)pFd->cFileName);

                // 当前查找到的对象是文件夹
                if( pFd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
                    // 添加到当前节点中作为子节点
                    p = CreateFSTreeNode( tpDir, pImm );
                    delete []pImm;
                    AddFSTreeNode( *dpNode, p );
                    // 将目录压栈
                    if( DSPush( dpStackTop, p ) != (WORD)ERR_OK ) {
                        ErrReport( (WORD)ERR_DS_PUSH_FAILED );
                        DestoryFSTree( &pRoot );

                        delete pFd;
                        delete dpStackTop;
                        delete dpNode;
                        return (ATTR_FS_TREE_NODE *)0;
                    }
                }
                // 当前查找到的对象是文件
                else {
                    p = CreateFSTreeNode( tpFile, pImm );
                    delete []pImm;
                    AddFSTreeNode( *dpNode, p );
                }
            }
            // 查找下一个对象
            if( !FindNextFileA( hFind, pFd ) ) {
                // 查找结束
                if( GetLastError() == ERROR_NO_MORE_FILES )
                    isDone = true;
                else {
                    // 发生不可预料的错误
                    // 这里进行错误处理
                    ErrReport( (WORD)ERR_UNKNOWN );
                    // 清空栈
                    while( *dpStackTop != (ATTR_DYM_STACK_NODE *)0 ) {
                        pStackTop = (*dpStackTop)->pPrev;
                        delete (*dpStackTop);
                        *dpStackTop = pStackTop;
                    }

                    // 删除树(对此函数不进行错误处理)
                    DestoryFSTree( &pRoot );

                    delete pFd;
                    delete dpStackTop;
                    delete dpNode;
                    return (ATTR_FS_TREE_NODE *)0;
                }
            }
        }
        // 完成搜索后关闭句柄以便下次使用
        FindClose(hFind);
        // 删除搜索字串
        delete []pTempStr;
    }
    // 收尾工作
    delete pFd;
    delete dpStackTop;
    delete dpNode;
    return pRoot;
}

// 删除指定目录树
WORD DelTree32( ATTR_FS_TREE_NODE **dpRoot ) {
    ATTR_FS_TREE_NODE *pNode;
    ATTR_FS_TREE_NODE *pNodeTmp;
    ATTR_FS_TREE_NODE **dpNode;

    ATTR_DYM_STACK_NODE **dpStackTop;

    bool flag; // 判断是否有子目录

    if( dpRoot == (ATTR_FS_TREE_NODE **)0 )
        return (WORD)ERR_INVAILD_POINTER;
    if( (*dpRoot) == (ATTR_FS_TREE_NODE *)0 )
        return (WORD)ERR_FS_TREE_EMPTY;

    dpStackTop = new (ATTR_DYM_STACK_NODE *);
    assert(dpStackTop);
    *dpStackTop = (ATTR_DYM_STACK_NODE *)0;

    dpNode = new (ATTR_FS_TREE_NODE *);
    assert(dpNode);
    *dpNode = (ATTR_FS_TREE_NODE *)0;

    if( DSPush( dpStackTop, *dpRoot ) != (WORD)ERR_OK ) {
        delete dpStackTop;
        delete dpNode;
        return (WORD)ERR_DS_PUSH_FAILED;
    }
    
    while( (*dpStackTop) != (ATTR_DYM_STACK_NODE *)0 ) {
        if( DSPop( dpStackTop, dpNode ) != (WORD)ERR_OK ) {
            delete dpStackTop;
            delete dpNode;
            return (WORD)ERR_DS_POP_FAILED;
        }
        flag = false;
        pNode = (*dpNode)->pDesecentHead;
        while( pNode != (ATTR_FS_TREE_NODE *)0 ) {
            // 是目录则压栈
            if( pNode->oFSNodeType == tpDir ) {
                if( flag != true ) {
                    // 若有子目则要将当前层压入栈,以便以后处理
                    if( DSPush( dpStackTop, *dpNode ) != (WORD)ERR_OK ) {
                        delete dpStackTop;
                        delete dpNode;
                        return (WORD)ERR_DS_PUSH_FAILED;
                    }
                    flag = true;
                }
                // 将子目录压栈
                if( DSPush( dpStackTop, pNode ) != (WORD)ERR_OK ) {
                    delete dpStackTop;
                    delete dpNode;
                    return (WORD)ERR_DS_PUSH_FAILED;
                }
                pNode = pNode->pNext;
            }
            // 是文件则删除之
            else {
#ifndef __DEBUG
                DeleteFileA( pNode->pFName );
#endif
                printf("Deleted file - %s/n", pNode->pFName);
                // 删除逻辑节点
                pNodeTmp = pNode->pNext;
                DelFSTreeNode( &pNode );
                pNode = pNodeTmp;
            }
        }
        // 若没有该目录下没有文件和子目录,则删除之
        if( flag == false ) {
#ifndef __DEBUG
            RemoveDirectoryA( (*dpNode)->pFName );
#endif
            printf("Delete directory - %s/n", (*dpNode)->pFName);
            // 删除逻辑节点
            DelFSTreeNode( dpNode );
        }
    }
    delete dpStackTop;
    delete dpNode;
    return (WORD)ERR_OK;
}

#endif

/* main.cpp */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <windows.h>

#include "deltree32.h"

int main(int argc, char *argv[]) {
    WORD wRes;
    ATTR_FS_TREE_NODE *pRoot;
    WIN32_FIND_DATAA oFd;
    HANDLE hFind;

    char *pPath;
    char c;

    int len, i;

    if( argc < 2 ) {
        printf("Deltree32 simple version/n");
        printf("Usage: %s <directory>/n", argv[0]);
        printf("eg. %s d://testdir - to delete a directory in specified logical driver/n", argv[0]);
        printf("eg. %s testdir - to delete a directory in current driver/n", argv[0]);
        return (int)1;
    }
    else {
        // 首先合并路径
        for( len = (int)strlen(argv[1]), i = 2; i < argc; len += (int)strlen(argv[i++]) );
        pPath = new char[len + argc + 1];

        for(strcpy(pPath, argv[1]), i = 2; i < argc; ++i ) {
            strcat(pPath,"/x20/0");
            strcat(pPath,argv[i]);
        }

        // 修正
        if( pPath[len - 1] == '//' )
            pPath[len - 1] = '/0';

        // 判断是否为根目录
        if( strlen(pPath) == 2 && pPath[1] == ':' ) {
            printf("Remove the root of a logical driver is forbidden!/n");
            delete []pPath;
            return (int)1;
        }

        // 验证输入目录是否存在    
        hFind = FindFirstFileA( "D://winhex", &oFd );
        if( hFind == INVALID_HANDLE_VALUE ) {
            delete []pPath;
            printf("Path not found!/n");
            return (int)1;
        }
        FindClose( hFind );

        do {
            printf("Do you really want to remove directory %s within all files? (Y/N) ", pPath);
            c = getchar();
        } while( c != 'Y' && c != 'y' && c != 'N' && c != 'n' );

        if( c == 'N' || c == 'n' )
            return (int)1;

        // 收集目录树
        pRoot = DrawPhy2LogTree( pPath );
        if( pRoot == (ATTR_FS_TREE_NODE *)0 )
            return (int)1;
        if( (wRes = DelTree32( &pRoot )) != (WORD)ERR_OK ) {
            // 报告错误
            ErrReport( wRes );
            delete []pPath;
            return (int)1;
        }
        delete []pPath;
        printf("All done!/n");
    }

    return (int)0;
}

  • 上一篇:用C语言编写管理联络方式的小系统
  • 下一篇:C语言制作坦克游戏方法总结适合新手