将源目录中的文件按照前缀分发到不同目录中的算法设计及C代码实现

一、需求描述
在Linux系统的某个源目录中有一批后缀相同的文件,编写程序将这些文件按照前缀分发到不同的目录中。

例如,源目录SourceDir中存放有三个后缀相同的文件File1_1.txt、File2_1.txt和File3_1.txt,按照前缀File1_、File2_和File3_将它们分别移动(分发)到目录FileDir1、FileDir2和FileDir3中。

二、算法设计
基于需求,可以采用如图1所示的程序流程:

图1 程序总体流程

三、特殊流程考虑
在编写程序的过程中,对于某些特殊流程的考虑如下:
1.如果扫描源目录出错,则直接停止程序的运行,而不用继续扫描下一个目录。

2.对于某些空文件(即文件的大小为0),直接在源目录中将其删除,而不用进行分发。

3.为了随时能够处理放到源目录中的文件,程序每隔一段时间(如一分钟)扫描一次源目录。也就是说,如果不人为操作,程序启动之后会不停地运行。

四、程序代码

/**********************************************************************
* 版权所有 (C)2016, Zhou Zhaoxiong。
*
* 文件名称:FileDistribute.c
* 文件标识:无
* 内容摘要:将某个目录中的文件按照前缀分发到对应的目录中
* 其它说明:无
* 当前版本:V1.0
* 作    者:Zhou Zhaoxiong
* 完成日期:20160517
*
**********************************************************************/
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <ftw.h>
#include <time.h>

// 重定义数据类型
typedef signed   int        INT32;
typedef unsigned int        UINT32;
typedef unsigned char       UINT8;

// 全局变量定义
UINT8  g_szSourceDir[256] = {0};     // 源文件的目录

// 函数声明
INT32 SelectFlies(struct dirent *pDir);
void ScanDirAndDistribute(void);
void Sleep(UINT32 iCountMs);

/****************************************************************
* 功能描述: 主函数
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 0-执行完成
* 其他说明: 无
* 修改日期       版本号        修改人        修改内容
* -------------------------------------------------------------
* 20160517        V1.0     Zhou Zhaoxiong     创建
****************************************************************/
INT32 main(void)
{
    // 源文件的目录
    snprintf(g_szSourceDir, sizeof(g_szSourceDir)-1, "%s/zhouzx/TestDir/SourceDir", getenv("HOME"));

    // 调用函数执行文件的分发
    while (1)
    {
        ScanDirAndDistribute();

        Sleep(60 * 1000);    // 每一分钟执行一次文件的分发
    }

    return 0;
}

/**********************************************************************
* 功能描述:根据后缀选择文件
* 输入参数:dir-目录
* 输出参数:无
* 返 回 值:0-失败   1-成功
* 其它说明:一个形如test.txt的文件要被扫描出来, 而形如test的文件不符合条件
* 修改日期         版本号      修改人          修改内容
* --------------------------------------------------------------------
* 20160517         V1.0    ZhouZhaoxiong        创建
***********************************************************************/
INT32 SelectFlies(struct dirent *pDir)
{
    if (pDir == NULL)
    {
        printf("SelectFlies:input parameter is NULL!\n");
        return 0;
    }

    // 根据.txt(后缀)选择文件
    if (strstr(pDir->d_name, ".txt") != NULL)
    {
        return 1;         // 找到了满足条件的文件
    }
    else
    {
        return 0;
    }
}

/**********************************************************************
* 功能描述:扫描目录并分发文件
* 输入参数:无
* 输出参数:无
* 返 回 值:无
* 其它说明:无
* 修改日期         版本号      修改人          修改内容
* --------------------------------------------------------------------
* 20160517         V1.0    ZhouZhaoxiong        创建
***********************************************************************/
void ScanDirAndDistribute(void)
{
    INT32  iScanDirRet           = 0;
    UINT32 iFileIdx              = 0;
    UINT32 iFileCount            = 0;
    UINT32 iFileSize             = 0;
    UINT8  szFileDir[256]        = {0};
    UINT8  szScanedFile[512]     = {0};
    UINT8  szCmdBuf[256]         = {0};
    FILE  *fp                    = NULL;
    struct dirent **ppDirEnt     = NULL;

    // 扫描源目录, 并分发文件
    iScanDirRet = scandir(g_szSourceDir, &ppDirEnt, SelectFlies, alphasort);
    if (iScanDirRet < 0)   // 扫描目录出错
    {
        printf("ScanDirAndDistribute:exec scandir failed, path=%s\n", g_szSourceDir);
        return;
    }
    else if (iScanDirRet == 0)   // 目录下无文件
    {
        printf("ScanDirAndDistribute:no satisfied file in directory %s\n", g_szSourceDir);
    }
    else          // 将满足条件的文件移动到对应的目录中
    {
        for (iFileIdx = 0; iFileIdx < iScanDirRet; iFileIdx ++)
        {
            // 先判断扫描到的文件是否为空文件, 是则直接删除, 不是才执行移动的操作
            memset(szScanedFile, 0x00, sizeof(szScanedFile));
            snprintf(szScanedFile, sizeof(szScanedFile) - 1, "%s/%s", g_szSourceDir, ppDirEnt[iFileIdx]->d_name);
            fp = fopen(szScanedFile, "r");
            if (fp == NULL)          // 打开文件失败, 直接返回
            {
                printf("ScanDirAndDistribute:open file %s failed, please check!\n", szScanedFile);
                return;
            }
            fseek(fp, 0, SEEK_END);
            iFileSize = ftell(fp);
            if (iFileSize == 0)     // 该文件为空文件
            {
                printf("ScanDirAndDistribute:%s is an empty file, so delete it directly!\n", szScanedFile);
                memset(szCmdBuf, 0x00, sizeof(szCmdBuf));
                snprintf(szCmdBuf, sizeof(szCmdBuf) - 1, "rm %s", szScanedFile);
                system(szCmdBuf);
            }
            else   // 根据前缀将文件移动(分发)到对应的目录中
            {
                if (strncmp(ppDirEnt[iFileIdx]->d_name, "File1_", strlen("File1_")) == 0)    // 移动到FileDir1
                {
                    memset(szFileDir, 0x00, sizeof(szFileDir));
                    snprintf(szFileDir, sizeof(szFileDir)-1, "%s/zhouzx/TestDir/FileDir1", getenv("HOME"));
                }
                else if (strncmp(ppDirEnt[iFileIdx]->d_name, "File2_", strlen("File2_")) == 0)    // 移动到FileDir2
                {
                    memset(szFileDir, 0x00, sizeof(szFileDir));
                    snprintf(szFileDir, sizeof(szFileDir)-1, "%s/zhouzx/TestDir/FileDir2", getenv("HOME"));
                }
                else if (strncmp(ppDirEnt[iFileIdx]->d_name, "File3_", strlen("File3_")) == 0)    // 移动到FileDir3
                {
                    memset(szFileDir, 0x00, sizeof(szFileDir));
                    snprintf(szFileDir, sizeof(szFileDir)-1, "%s/zhouzx/TestDir/FileDir3", getenv("HOME"));
                }
                else    // 前缀不满足, 直接将该文件删掉
                {
                    memset(szCmdBuf, 0x00, sizeof(szCmdBuf));
                    snprintf(szCmdBuf, sizeof(szCmdBuf) - 1, "rm %s", szScanedFile);
                    system(szCmdBuf);

                    printf("ScanDirAndDistribute:now, %s\n", szCmdBuf);

                    continue;  // 继续判断下一个
                }

                memset(szCmdBuf, 0x00, sizeof(szCmdBuf));
                snprintf(szCmdBuf, sizeof(szCmdBuf) - 1, "mv %s %s", szScanedFile, szFileDir);
                system(szCmdBuf);

                printf("ScanDirAndDistribute:now, %s\n", szCmdBuf);

                iFileCount ++;
            }
        }
    }

    printf("ScanDirAndDistribute:this time,totally moved %d file(s).\n", iFileCount);

    return;
}

/**********************************************************************
* 功能描述: 程序休眠
* 输入参数: iCountMs-休眠时间(单位:ms)
* 输出参数: 无
* 返 回 值: 无
* 其它说明: 无
* 修改日期      版本号       修改人        修改内容
* ------------------------------------------------------------------
* 20160517       V1.0     Zhou Zhaoxiong     创建
********************************************************************/
void Sleep(UINT32 iCountMs)
{
    struct timeval t_timeout = {0};

    if (iCountMs < 1000)
    {
        t_timeout.tv_sec  = 0;
        t_timeout.tv_usec = iCountMs * 1000;
    }
    else
    {
        t_timeout.tv_sec  = iCountMs / 1000;
        t_timeout.tv_usec = (iCountMs % 1000) * 1000;
    }
    select(0, NULL, NULL, NULL, &t_timeout);    // 调用select函数阻塞程序
}

五、程序测试
将编写好的程序“FileDistribute.c”上传到Linux机器,并使用“gcc -g -o FileDistribute FileDistribute.c”命令对该程序进行编译,生成“FileDistribute”文件。下面对程序进行详细的测试。

1.在启动程序之前,在源目录SourceDir中放入文件File1_1.txt、File2_1.txt和File3_1.txt,程序运行情况如下:

ScanDirAndDistribute:now, mv /home/zhou/zhouzx/TestDir/SourceDir/File1_1.txt /home/zhou/zhouzx/TestDir/FileDir1
ScanDirAndDistribute:now, mv /home/zhou/zhouzx/TestDir/SourceDir/File2_1.txt /home/zhou/zhouzx/TestDir/FileDir2
ScanDirAndDistribute:now, mv /home/zhou/zhouzx/TestDir/SourceDir/File3_1.txt /home/zhou/zhouzx/TestDir/FileDir3
ScanDirAndDistribute:this time,totally moved 3 file(s).

可以看到,源目录中的三个文件已经没有了,它们被分别移动到了结果目录FileDir1、FileDir2和FileDir3中:

~/zhouzx/TestDir/SourceDir> ll
total 0

~/zhouzx/TestDir/FileDir1> ll
-rw-------  1 zhou users 12 2016-05-17 18:58 File1_1.txt

~/zhouzx/TestDir/FileDir2> ll
-rw-------  1 zhou users 12 2016-05-17 18:58 File2_1.txt

~/zhouzx/TestDir/FileDir3> ll
-rw-------  1 zhou users 12 2016-05-17 18:58 File3_1.txt

2.一段时间之后,在源目录SourceDir中放入文件File4_1.txt,程序运行情况如下:

ScanDirAndDistribute:now, rm /home/zhou/zhouzx/TestDir/SourceDir/File4_1.txt
ScanDirAndDistribute:this time,totally moved 0 file(s).

可以看到,因为前缀不匹配,File4_1.txt文件直接被删除掉了。

~/zhouzx/TestDir/SourceDir> ll
total 0

3.一段时间之后,在源目录SourceDir中放入空文件File_7.txt、File_8.txt和File_9.txt,程序运行情况如下:

ScanDirAndDistribute:/home/zhou/zhouzx/TestDir/SourceDir/File_7.txt is an empty file, so delete it directly!
ScanDirAndDistribute:/home/zhou/zhouzx/TestDir/SourceDir/File_8.txt is an empty file, so delete it directly!
ScanDirAndDistribute:/home/zhou/zhouzx/TestDir/SourceDir/File_9.txt is an empty file, so delete it directly!
ScanDirAndDistribute:this time,totally moved 0 file(s).

可以看到,源目录SourceDir中的空文件已经被全部删除掉了。

~/zhouzx/TestDir/SourceDir> ll
total 0

六、需求扩展
基于本文中的需求和程序,可考虑对需求进行以下扩展:
1.在移动(分发)文件之前,先查看相同文件名的文件在对应结果目录中是否存在,如果存在,则直接将该文件在源目录中删除掉;如果不存在,才将该文件移动到对应结果目录中。

2.为避免结果目录中的文件过多,可以在程序中添加清理机制,即将存放时间超过一定时长的文件删除掉。

3.为了体现程序的灵活性,可将部分文件信息(如文件前缀、后缀、存放目录、扫描间隔时长等)存放到配置文件中,程序在启动时读取相关的配置项的值来执行后续目录扫描和文件分发的操作。

时间: 2024-09-19 15:36:16

将源目录中的文件按照前缀分发到不同目录中的算法设计及C代码实现的相关文章

Linux下文件分发的算法设计及C代码实现

需求描述 在Linux系统的某个源目录中有一批后缀相同的文件,编写程序将这些文件按照前缀分发到不同的目录中. 例如,源目录SourceDir中存放有三个后缀相同的文件File1_1.txt.File2_1.txt和File3_1.txt,按照前缀File1_.File2_和File3_将它们分别移动(分发)到目录FileDir1.FileDir2和FileDir3中. 算法设计 基于需求,可以采用如图1所示的程序流程: 图1 程序总体流程 特殊流程考虑 在编写程序的过程中,对于某些特殊流程的考虑

vc++-VC++中如何实现office中通过文件菜单打开命令,在试图中显示文本内容并且可以编辑?

问题描述 VC++中如何实现office中通过文件菜单打开命令,在试图中显示文本内容并且可以编辑? VC++中如何实现office中通过文件菜单打开命令,在试图中显示文本内容并且可以编辑通过CDC的文本输出函数在视图上显示的文本不能编辑 解决方案 你的意思是你希望做一个类似文本编辑器的程序吧,你不能用手动绘图的方式去实现,MFC好像有类似的功能提供.你用多文档模式或者单文档模式,视图类继承CEditView就自动可以编辑了. 希望能够帮到你. 解决方案二: 是不是自己做一个mfc单文档程序,然后

将前缀和后缀相同的文件移动到同一个目录的算法设计及C代码实现

一.需求描述 在Linux系统的某几个目录下有一些前缀和后缀相同的文件,编写程序将它们移动到同一个目录下. 例如,有三个源目录FileDir1.FileDir2和FileDir3,里面分别存放有文件File_1.txt.File_2.txt和File_3.txt.由于它们有相同的前缀(File_)和后缀(txt),所以要将这三个文件移动到同一个结果目录(假设为GatherDir)中. 二.算法设计 基于需求,可以采用如图1所示的程序流程: 图1 程序总体流程 三.特殊流程考虑 在编写程序的过程中

限制程序中某类操作的执行次数的算法设计及C代码实现

需求描述 编写程序实现限制程序中某类操作的执行次数的需求.为了便于说明,要求程序每天创建一个与上一天不同的文件目录.如果欲创建的文件目录已存在,则不用再创建.文件目录的命名格式为:FileDir_YYYYMMDD,如:FileDir_20160830. 程序流程 对于此类需求,最关键的问题是要设定一个标识来限制操作的执行次数.也就是说,当程序执行完一次操作之后,要有机制来限制它执行第二次操作. 因为本需求要求每天执行一次操作,所有我们自然想到了用日期来限制程序的执行次数.我们可以用一个全局时间变

Linux基础命令:显示其他目录中的文件

上面都是显示当前工作目录中的文件,如果要显示其他目录中的文件,那么我们只要在"ls"后面加入所要显示的目录的路径.如下所示: [root@Linux ~]# ls /bin dev home lost+found misc net proc sbin srv tftpboot usrboot etc lib media mnt opt root selinux sys tmp var 这样显示的就是"/"目录下的文件.当然我们也可以加入一下参数,如下所示: [roo

eclipse中头文件无法识别??

问题描述 eclipse中头文件无法识别?? 解决方案 c++中头文件C++中头文件

如何在Web页面中集成文件上传功能

当前,个人主页制作非常流行.当用户开发好自己的页面时,需要将文件传输到服务器上,解决这个问题的方法之一是运行FTP服务器并将每个用户的FTP默认目录设为用户的Web主目录,这样用户就能运行FTP客户程序并上传文件到指定的 Web目录.由于Windows NT 和 Windows98均不提供直接的基于窗口形式的FTP客户程序,用户必须懂得如何使用基于命令行的FTP客户,或掌握一种新的基于窗口形式的FTP客户程序.因此,这种解决方案仅对熟悉FTP且富有经验的用户来说是可行的. 如果我们能把文件上传功

详细讲解Python中的文件I/O操作

  这篇文章主要介绍了Python中的文件I/O操作,是Python入门中的基础知识,需要的朋友可以参考下 本章将覆盖所有在Python中使用的基本I/O功能.有关更多函数,请参考标准Python文档. 打印到屏幕上: 产生输出最简单的方法是使用print语句,可以通过用逗号分隔的零个或多个表达式.该函数将传递到一个字符串表达式,并将结果写到标准输出,如下所示: ? 1 2 3 #!/usr/bin/python   print "Python is really a great languag

如何快速访问局域网中的文件夹

  每次访问局域网中的文件夹时,都需要通过"网上邻居",或者输入IP地址.主机名,才能访问,很麻烦. 快速访问保存在局域网中的文件夹,先在"网上邻居"中,找到局域网中需要经常访问的共享文件夹,在地址栏中将地址复制.然后右击桌面空白处,选择"新建""快捷方式",然后在"请键入项目的位置"选项中,将复制的共享文件夹地址粘贴.单击"下一步",然后给快捷方式起一个命名,设置完毕后,在桌面双击快捷