文件合并程序

文件合并程序
程序的功能
将一个目录中的指定的文件进行合并或者拆分。
处理规则是:将指定目录中的指定的文件形成一个文件列表,对该列表中的每一个文件进行读取,一条一条地将记录写入目的文件,当目的文件达到指定的数量的时候,关闭旧的目的文件,打开新的目的文件,继续处理原始的记录。最终的后果就是,如果原始文件的记录较少,该程序实现了文件合并,如果原始文件的记录数量较多,该程序实现了文件的拆分。
使用到的系统函数有:
获取文件目录中文件列表的办法;
取得当前程序进程号;
获取时间的办法;
C++中读写文件的办法;

一些宏的使用;

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <time.h>

#include <vector>
#include <string>
#include <fstream>

using namespace std;

/*
编译方法
AIX:xlC_r -g -w -q64 -qwarn64 -brtl -bhalt:5 -o mergeCdr mergeCdr.cpp
	发布的时候,去掉“-g”
*/

/*
版本号定义规则
1 主版本号,用于较大的程序改动
0 次版本号,用于较小的需求改动
0 每次的修改的bug 更改次数
1 总的发布次数
第一次版本的发布信息为: Ver 1.0.0.1
*/
/*
版本修改历史:
Ver 1.0.0.1 功能点:
支持程序将指定目录中的指定的文件,复制并备份到指定的目录

Ver 1.1.0.2 功能点:
支持将目的文件设定最大行数

*/
#define __VER__ "Ver 1.1.0.2"

const int FILE_NAME_LEN  = 256;	//文件名的最大长度
const int BUFFER_LEN = 4096;	//清单中的一条记录的最大长度

vector<string> vec_file;		//用于存放需要处理的文件名称
int nFileRows = 0;		//合并后的文件的当前记录数量
int nMaxFileRows = 0;			//合并后的文件的最大记录数量
char chFileMask[50] = { 0 };	//命令行参数中传进来的输出文件名称的前缀

int GetFile(char * src_dir, char *src_file_name);
void usage(char *process_name);
int DealOneFile(char *srcFileNameWithPath, char*bakFileNameWithPath,char * destFilePath, char * destFileName);
int GetMMHHSS(char * mmhhss);
int GetYYYYMMDD(char * yymmdd);
int GetMMDD(char * mmdd);

/*
程序的参数:
process_name sleep_time src_dir src_file_mask src_bak_dir dest_dir desc_file_mask file_rows
process_name 程序名字本身
sleep_time 程序休眠的时间
src_dir 原来的目录路径
src_file_mask 原始文件的掩码
src_bak_dir 备份文件的路径
dest_dir 新的目录路径
desc_file_mask 新的文件名称掩码
file_rows 合并后的文件达到file_rows的记录后,重新建立一个文件

启动方式举例:
./mergeCdr 60 /hnibm/henan/mergeCdr A /hnibm/henan/mergeCdr/bak /hnibm/henan/mergeCdr A 3
*/
int main(int argc, char ** argv)
{
	printf("==============process [%s] begin...==============\n", argv[0]);

    //参数校验
	if(	argc == 2 &&
		( strcmp(argv[1],"-v") == 0 || strcmp(argv[1],"-V") == 0 ))
	{
		printf("current version is [%s]\nbulid time is [%s %s]\n",__VER__, __DATE__,__TIME__);

        return 0;
	}
	else if( argc != 8)
	{
		printf("process need 7 parameters!\n");

		usage(argv[0]);

		return 2;
	}

	sprintf(chFileMask, "%s", argv[6]);
	nMaxFileRows = atol(argv[7]);

    //主要业务的处理
	while(true)
	{
		//取得当前的日期和时间,用于生成目标文件名称
        char szyyyymmdd[15] = {0};
        GetYYYYMMDD(szyyyymmdd);
        char szhhmiss[15] = {0};
        GetMMHHSS(szhhmiss);
        char szmmdd[10] = {0};
        GetMMDD(szmmdd);
        printf("current date and time is [%s %s]!\n",szyyyymmdd,szhhmiss);

        //取得需要处理的文件列表
        int ret = GetFile(argv[2],argv[3]);
        if(ret != 0)
        {
            return ret;
        }

        if(vec_file.size() == 0)
        {
            printf("no files to be need\n");
        }
        else
        {
            printf("there are [%d] files need to deal\n",vec_file.size());

            //规整输入的文件名称
            char szSrcFilePath[FILE_NAME_LEN] = {0};

            if(argv[2][strlen(argv[2])-1] != '/')
            {
                sprintf(szSrcFilePath,"%s%s",argv[2],"/");
            }

            printf("src file path is [%s]\n",szSrcFilePath);

            //规整备份文件的路径名称
            char szBakFilePath[FILE_NAME_LEN] = {0};

            if(argv[4][strlen(argv[4])-1] != '/')
            {
                sprintf(szBakFilePath,"%s%s",argv[4],"/" );
            }

            printf("backup file path is [%s]\n",szBakFilePath);

            //规整输出的路径名称
			char szDestFilePath[FILE_NAME_LEN] = { 0 };
            if(argv[5][strlen(argv[5])-1] != '/')
            {
                sprintf(szDestFilePath,"%s%s",argv[5],"/" );
            }

			char szDestFileNameTemp[FILE_NAME_LEN / 2] = { 0 };
			sprintf(szDestFileNameTemp, "%s_0%s%s_%s.r.XswapX", chFileMask, szmmdd, szhhmiss, szyyyymmdd);

            char szSrcFileNameWithPath[FILE_NAME_LEN] = {0};
            char szBakFileNameWithPath[FILE_NAME_LEN] = {0};

            for(vector<string>::iterator itr = vec_file.begin(); itr != vec_file.end(); itr ++)
            {
                memset(szSrcFileNameWithPath,0x00,FILE_NAME_LEN);
                memset(szBakFileNameWithPath,0x00,FILE_NAME_LEN);

                sprintf(szSrcFileNameWithPath,"%s%s",szSrcFilePath,itr->c_str());
                sprintf(szBakFileNameWithPath,"%s%s",szBakFilePath,itr->c_str());

                printf("begin to deal file [%s]\n",szSrcFileNameWithPath);

                //处理一个文件
				//特别需要注意参数 szDescFileNameTemp,当一个合并文件写满时,它的变量值在处理过程中会发生改变。
				ret = DealOneFile(szSrcFileNameWithPath, szBakFileNameWithPath, szDestFilePath, szDestFileNameTemp);
                if(ret)
                {
                    //return ret;
                    continue;
                }
            }

            //将目标文件的名称进行调整
            char szCmd[1024] = {0};
			string strDestFileNameTemp(szDestFileNameTemp);
			sprintf(szCmd, "mv %s%s %s%s ", szDestFilePath, szDestFileNameTemp, szDestFilePath, strDestFileNameTemp.substr(0, strDestFileNameTemp.rfind(".")).c_str());
            printf("final dest file: [%s]\n", szCmd);
            system(szCmd);
        }

        printf("==============sleep(%d)==============\n", atoi(argv[1]));
        sleep(atoi(argv[1]));
	}

	return 0;
}

void usage(char *process_name)
{
	printf("USAGE:\n");
	printf("\t[%s -v]\n",process_name);
	printf("\t[%s -V]\n",process_name);
	printf("\t[%s sleep_time src_dir src_file_name_mask src_bak_dir dest_dir dest_file_name_mask file_rows]\n",process_name);
}

int GetFile(char * src_dir, char *src_file_name)
{
    printf("begin to get files in dir [%s], file name like [%s]\n", src_dir, src_file_name );

    DIR *dp;
    struct dirent *dirp;

    if ((dp = opendir(src_dir)) == NULL)
    {
        printf("can't open [%s]\n", src_dir);
        return 3;
    }

    vec_file.clear();
    int iSrcFileNameLen = strlen(src_file_name);
    while ((dirp = readdir(dp)) != NULL)
    {
        if(strcmp(dirp->d_name,".") == 0 || (strcmp(dirp->d_name,"..") == 0))
        {
            continue;
        }

        if(strncmp(dirp->d_name,src_file_name,iSrcFileNameLen) != 0)
        {
            printf("file name is [%s], skip!\n", dirp->d_name);

            continue;
        }

		int nFileNameLen = strlen(dirp->d_name);
		if (! (dirp->d_name[nFileNameLen - 2] == '.' && dirp->d_name[nFileNameLen - 1] == 'r') )
		{
			printf("file name is [%s], skip!\n", dirp->d_name);

			continue;
		}

        vec_file.push_back(dirp->d_name);
    }

    closedir(dp);

    return 0;
}

int DealOneFile(char *srcFileNameWithPath, char*bakFileNameWithPath, char * destFilePath, char * destFileName)
{
    ifstream src_file(srcFileNameWithPath);
	char szDestFileNameWithPath[FILE_NAME_LEN] = { 0 };
	sprintf(szDestFileNameWithPath, "%s%s", destFilePath, destFileName);
	printf("dest file name with path is [%s]\n", szDestFileNameWithPath);
	ofstream dest_file(szDestFileNameWithPath, ofstream::app);

    if(!src_file.is_open())
    {
        printf("open src file [%s] Error\n",srcFileNameWithPath);

        return 4;
    }

    if(!dest_file.is_open())
    {
		printf("open dest file [%s] Error\n", szDestFileNameWithPath);

        return 5;
    }

    char szBuffer[BUFFER_LEN] = {0};

    //复制文件
    while (! src_file.eof() )
    {
        memset(szBuffer,0x00,BUFFER_LEN);
        /*
		//read 函数是读取一块数据,会有多行,不能使用此函数
        src_file.read(szBuffer,BUFFER_LEN);
        dest_file << szBuffer;
        */
        src_file.getline(szBuffer,BUFFER_LEN);

        if(strlen(szBuffer) == 0)
        {
            printf("empty line, skip\n" );
            continue;
        }

        dest_file << szBuffer <<endl;

        nFileRows ++;

        //如果一个文件“被写满”,写下一个文件
        if( nFileRows == nMaxFileRows)
        {
            printf("file is full, use next file\n");
            nFileRows = 0;
			dest_file.close();

			//将目标文件的名称进行调整
			string strDestFileName(destFileName);
			char szCmd[1024] = { 0 };
			sprintf(szCmd, "mv %s %s%s", szDestFileNameWithPath, destFilePath, strDestFileName.substr(0, strDestFileName.rfind(".")).c_str());
			printf("final dest file: [%s]\n", szCmd);
			system(szCmd);

			//为了防止新的目标文件名与上一次产生的文件名重复
			sleep(1);

			char szyyyymmdd[15] = { 0 };
			GetYYYYMMDD(szyyyymmdd);
			char szhhmiss[15] = { 0 };
			GetMMHHSS(szhhmiss);
			char szmmdd[10] = { 0 };
			GetMMDD(szmmdd);
			//此处需要修改函数的入参,好让此文件名供后续的其他需要处理的源文件使用。
			sprintf(destFileName, "%s_0%s%s_%s.r.XswapX", chFileMask, szmmdd, szhhmiss, szyyyymmdd);
			sprintf(szDestFileNameWithPath, "%s%s", destFilePath, destFileName);
			printf("new dest file name with path is [%s]\n", szDestFileNameWithPath);

			dest_file.open(szDestFileNameWithPath, ofstream::app);
        }
    }

    //dest_file<<endl;

    dest_file.close();
    src_file.close();

    //将原始文件进行备份
    char szCmd[1024] = {0};
    sprintf(szCmd,"mv %s %s",srcFileNameWithPath,bakFileNameWithPath );

    printf("backup file: [%s]\n", szCmd);

    system(szCmd);

    return 0;
}

int GetMMHHSS(char * mmhhss)
{
    time_t current_time = time(0);
    struct tm *mStLocalTime = localtime(¤t_time);
    sprintf(mmhhss,"%02d%02d%02d",mStLocalTime->tm_hour,mStLocalTime->tm_min,mStLocalTime->tm_sec);

    return 0;
}

int GetYYYYMMDD(char * yymmdd)
{
    time_t current_time = time(0);
    struct tm *mStLocalTime = localtime(¤t_time);
    sprintf(yymmdd,"%04d%02d%02d",mStLocalTime->tm_year+1900,mStLocalTime->tm_mon + 1,mStLocalTime->tm_mday);

    return 0;
}

int GetMMDD(char * mmdd)
{
    time_t current_time = time(0);
    struct tm *mStLocalTime = localtime(¤t_time);
    sprintf(mmdd,"%02d%02d",mStLocalTime->tm_mon + 1,mStLocalTime->tm_mday);

    return 0;
}


测试命令

测试命令:./mergeCdr 60 /hnibm/henan/mergeCdr A /hnibm/henan/mergeCdr/bak /hnibm/henan/mergeCdr A 1000
命令说明
./mergeCdr 程序本身的名称;
60 程序循环变量指定的原始文件目录时,所休眠的时间,以秒为单位;
/hnibm/henan/mergeCdr 程序需要处理的原始文件目录;
A 程序需要处理的原始文件目录中的以字符'A' 开头的文件名称;
/hnibm/henan/mergeCdr/bak 程序需要处理的原始文件在处理后的备份的路径;
/hnibm/henan/mergeCdr 程序需要存放的合并后的文件的路径;
A 合并后的文件的名称前缀,最终的文件名为“A_0mmddhhmiss_yyyymmdd.r”;
1000 合并后的文件的记录数量的最大值,当文件的记录数量达到此值后,系统会创建一个新的记录文件;


备注:
我测试的时候,原始文件的路径和合并后的文件存放的路径是一致的,原始文件的名称匹配字符和合并后的文件的名称前缀也是一致的,这种源和目的都一样的情况,会导致数据文件在下一个循环中进行重复处理,虽然不会导致话单错误,但是也是多此一举。所以,在实际生产中,不建议用这种方式进行配置。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值