梦幻文件分割器 V1.0

-------------------------------------------

/*梦幻文件分割器 V1.0-----By alxen(小雨)
 *                           2007-04-07
 *功能:分割一个大文件为几个较小的文件。软件运行在命令行下,分割文件时可以指定新文件的扩展名。
 *软件的最小分割单位为1KB,没有考虑源文件小于1KB的情况。不是我偷懒,感觉做出来也不使用。
 *因为没有几个人想要分割小于1KB的文件吧?(^_^)
 *本软件的运行速度极快,分割一个几百M的文件不到一分钟搞定。
 
 *使用方法:命令行下使用。命令格式如下:
 *st <源文件> <分割大小(KB)>  <.指定分割文件的扩展名(可选)>  

*其中分割大小为整数,单位为KB。另外软件可以指定分割后的文件的扩展名,当然这只是强制改扩展名,不是格式转换,以满足具体的使用要求。
*软件原理:根据输入的分割大小,依次从源文件copy数据到一个新文件中,以实现分割。
  当然分割前要有纠错处理,比如源文件不存在、分割大小大于源文件大小、参数不够等等。
 */

#include<iostream>
#include<iomanip>
#include<conio.h>
#include<cstdio>
#include<windows.h>
#include<io.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<share.h>
#include<cstdlib>

 

using namespace std;

 

void head();      //显示logo
void help(void);  //输出软件使用说明
int argument_check(int argc,char *argv[]);    //检测命令行参数,并检测是否指定了扩展名
void file_check(char *argv);     //文件名检测
unsigned long size_detect(char *argv);  //获得源文件的大小
unsigned long size_detect(unsigned long file_size,char *argv1,char *argv); //转换并判断输入的分割大小是否正确
int getfilename(char *argv,char *file_serial,char *expand_name);          //获取源文件名函数
void cut(int file_name,char *file_serial,char *expand_name,char *s,FILE *fp1,unsigned long size);  //主分割函数
void file_cut(char *argv,unsigned long file_size,unsigned long cut_size);  //分割函数


void head()                //显示软件logo
{
 system("cls");
 system("title 梦幻文件分割器 V1.0-----By alxen");
 system("color 0b");
 char *p[]={
          "/t/t☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆/n",
          "/t/t☆☆☆  梦幻文件分割器--ST(Super cuT) V1.0  ☆☆☆/n",
          "/t/t☆☆☆       By  小雨(alxen) 2007.04.06     ☆☆☆/n",
          "/t/t☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆/n"
           };
 for(int i=0;i!=4;++i)
 {
  cout<<p[i];
  Sleep(100);
 }
 cout<<endl;
}


void help(void)     //输出软件使用说明
{
 cout<<"/n/t/t/t梦幻文件分割器--ST(Super cuT) V1.0/n/
     /n请在命令行中按以下格式输入/
     /nst <源文件> <分割大小(KB)>  <.指定分割文件的扩展名(可选)>/
     /n例如/nst data.db 1024        或       st data.db 1024 .txt/
     /n若文件不在当前目录下,则文件路径两边应加上/"/"/
     /n例如/nst /"D://Programe Files//test//test.bak/" 2048"<<endl;
}

 

int argument_check(int argc,char *argv[])   //检测命令行参数,并检测是否指定了扩展名
{
 //argv[1]是源文件名,argv[2]是分割大小,argv[3]是指定的扩展名
 if(argc>4||argc<2)    
    {
  if(argc>4)
   cerr<<"/n参数过多!"<<endl;
  help();
  /*if(argc==1)     //只输入了软件名st,很可能是直接双击打开。则输出提示信息后按任意键进入cmd转到当前目录下          
  {
   cout<<"按任意键回到命令行下..."<<endl;
   _getch();
   system("cmd /c start /i"); //start /i用于在新cmd窗口中打开当前目录
   exit(1);                   //一定要加cmd /c,执行后中断当前窗口。不然当前窗口不会关闭。st程序也不会退出。
  }*/
  _getch();
  exit(1);
 }  
 if(argc==4)
  if(argv[3][0]!='.') //如果指定了扩展名则检查是否正确
  {
   cerr<<"你指定的扩展名/""<<argv[3]<<"/"有误。请重新指定。"<<endl;
   exit(1);
  }
  else
   return 1;//扩展名正确
 return 0;

}

 

void file_check(char *argv)    //文件路径及文件名检测
{
 int n=_access(argv,0);
 if(n!=0)                   //检测要分割的文件是否存在
 {
  cerr<<"文件 "<<argv<<" 不存在!/n请检查文件路径。"<<endl;
  _getch();
  exit(1);
 }
}

 

unsigned long size_detect(char *argv)    //获得源文件的大小
{
 int fh;
 long file_length;
    _sopen_s( &fh, argv, _O_RDWR | _O_CREAT,_SH_DENYRD,_S_IREAD); //打开指定的文件
 file_length=_filelength(fh);        //获得源文件大小,单位byte
 _close(fh);
 return file_length;
}

 

unsigned long  size_detect(unsigned long file_size,char *argv[]) //转换并判断输入的分割大小是否正确
{
 double size=(double)file_size;       //把源文件大小转换为double用于精确显示源文件大小
 for(int i=0;argv[2][i];i++)
  if(!isdigit(argv[2][i]))           //如果输入了字母则提示出错
  {
   cerr<<"指定的文件分割大小/""<<argv[2]<<"/"不正确!/n源文件 "<<argv[1]<<" 大小为 "
    <<fixed<<setprecision(2)<<size/1024.0<<" KB。请重新输入分割大小。"<<endl;
   exit(1);
  }
 unsigned long length=atoi(argv[2]);            //把输入的分割大小(字符数组)转换为数字赋给length(单位KB) 
 length*=1024;             //把分割单位转换为byte
 if(length>file_size||length<1)    //如果输入的分割大小大于源文件的大小则提示出错
 {
  cerr<<"指定的文件分割大小/""<<argv[2]<<"/"不正确!/n源文件 "<<argv[1]<<" 大小为 "
   <<fixed<<setprecision(2)<<size/1024.0<<" KB。请重新输入分割大小。"<<endl;
  exit(1);
 }
 return length;   //如果输入正确则返回转换后的分割大小
}

 

int getfilename(char *argv[],char *file_serial,char *expand_name,int expandname_check) //获取文件名函数
{
 int i=0;   //引用数组下标
 for(int j=0;argv[1][j];++j)
  if(argv[1][j]=='//')   /*判断输入的文件名是否包含路径,若包含路径,则把j定位到最后一个/上,以获得
         该/后面的文件名*/
    i=j+1;        /*如果输入的只是文件名,则i还是0,可以直接从数组argv[1]获取文件名*/
 int d=0;               //保存最后一个小数点的位置
 for(int j=0;argv[1][j];++j)
  if(argv[1][j]=='.') //如果文件名本身包含有小数点'.',则要定位最后一个'.',扩展名要取最后一个小数点后面的字符
   d=j;
 int t=0;
 for(;i!=d;++i,++t)
  file_serial[t]=argv[1][i];   //获得文件名(不包括扩展名,因为分割后的文件名后面要加序号)
 file_serial[t]='-';   //在文件名和序号之间加'-'
 file_serial[t+1]='/0';  //数组尾部置空 if(expandname_check==1)
  for(int j=0;argv[3][j]!='/0';++j)
   expand_name[j]=argv[3][j];   //如果指定了扩展名则把扩展名放在expand_name数组中
 else
  for(int j=0;argv[1][i]!='/0';++j,++i)
   expand_name[j]=argv[1][i];             //源文件的扩展名存放在expand_name数组中
 return t+1;    //返回文件名数组中字符'-'的下一个位置
 
}

 

void cut(int file_name,char *file_serial,char *expand_name,char *s,FILE *fp1,unsigned long cut_size,unsigned long size_s)  //主分割函数
{

 char serial[30];        //仅存放文件序号(如1、2、3...)
 _itoa_s(file_name,serial,30,10);  //把file_name转换成字符串(就是文件序号)存放在serial字符数组中
 strcat_s(file_serial,200,serial);  //把file_serial中的文件名和文件序号链接起来组成分割后的文件全名 
 strcat_s(file_serial,200,expand_name);  //把file_serial中的文件名和扩展名链接起来组成分割后的文件全名
 FILE *fp2;       //fp2是打开分割的文件的指针
 fopen_s(&fp2,file_serial,"wb"); //以写方式打开最后一个分割的文件
 cout<<"正在分割 "<<file_serial<<" ...";
 if(cut_size>=size_s)            //如果每个分割的文件大于数组大小,则要分多次从源文件取数据
 {
  unsigned long  temp=cut_size/(size_s-1); //注意cut_size/(size_s-1)不一定整除,s数组最多能装size_s-1多数据    
  for(int i=1;i<=int(temp);i++) //这里同样要考虑最后一次从源文件取的数据块大小
  {
   fread(s,1,size_s-1,fp1);  /*在第1次到第temp次从源文件取数据时都可以把数组s装满,即取够装满s数组
                                  大小的数据块,亦即 size_s-1 bytes */
    s[size_s-1]='/0';     //数组最后一定加结束符'/0'   
   fwrite(s,1,size_s-1,fp2);
   s[0]='/0';          //复制完一块数据后把数组s清空,继续复制
     }
  if(cut_size%(size_s-1)!=0)   /*特别注意,如果cut_size/(size_s-1)不能整除,则最后一次从源文件取的数据块
                   要重新计算。计算公式为 每个分割的文件大小-已经从源文件copy的数据*/
  {
   fread(s,1,(cut_size%(size_s-1)),fp1);
   s[cut_size%(size_s-1)]='/0';
   fwrite(s,1,(cut_size%(size_s-1)),fp2);
   s[0]='/0'; //清空数组s
  }
    
 }    
 else   //这种情况就是每个分割的文件大小 < 999999 bytes(即小于976KB),这个一次就可以用数组中转完
 {
  fread(s,1,cut_size,fp1);
  s[cut_size]='/0';  //数组尾部置空
  fwrite(s,1,cut_size,fp2);
  s[0]='/0';
    }
 fclose(fp2);
}

 

void file_cut(char *argv[],unsigned long file_size,unsigned long cut_size,int expandname_check)  //分割函数
{
 FILE *fp1;
 if((fopen_s(&fp1,argv[1],"rb"))!=NULL)       //分割前再次判断要分割的源文件是否能打开
 {
  cerr<<"文件 "<<argv[1]<<" 打开错误/n"/
   <<"请检查文件路径"<<endl;
  exit(1);
 }
 else
 {
  int file_name=1;                 //分割后的文件名序号。从1开始
  char file_serial[200];           //存放完整的文件名(文件名加序号)
  char expand_name[10];            //存放源文件的扩展名
  static char s[999999];         //源文件中转的数组,可存放976KB数据。该数组只能定义这么大了
  unsigned long size_s=sizeof(s);   //size_s是s数组的大小,即999999
  int t=getfilename(argv,file_serial,expand_name,expandname_check);  //获得文件名数组中字符'-'的下一个位置
  int file_num=file_size%cut_size ? file_size/cut_size+1 : file_size/cut_size;
  for(int i=1;i<=(int)(file_size/cut_size);++i) /*file_size/cut_size是要分割的文件个数,因为不一定整除,(即最后
                              一个分割的文件大小可能要小于cut_size),所以后面要考虑最后一个分割的文件大小*/
  {
   cut(file_name,file_serial,expand_name,s,fp1,cut_size,size_s);  //调用主分割函数
   cout<<"/tOK! /t完成 "<<file_name<<" 个,剩余 "<<file_num-file_name<<" 个。"<<endl;//接着cut函数的提示
   file_name++;      //文件名序号+1
   file_serial[t]='/0';  //存放文件名序号的数组置空,继续分割下一个文件
  }

  unsigned long  last_size=file_size%cut_size;   //最后一个文件的大小(如果没有分割完的话)  
  if(last_size!=0)  /*如果file_size/cut_size不是整除,则最后一个分割的文件大小就不是cut_size了,而是
                          file_size%cut_size bytes,即last_size,此时同样要 last_size 和999999的大小问题*/
  {  
   cut(file_name,file_serial,expand_name,s,fp1,last_size,size_s); //调用主分割函数
   cout<<"/tOK! /t完成 "<<file_name<<" 个,剩余 "<<file_num-file_name<<" 个。"<<endl; //至此,文件全部分割成功!
   file_serial[0]='/0';  //存放文件名序号的数组置空
  }
  fclose(fp1);   //关闭源文件
 } 
}

 

int main(int argc,char *argv[])
{
 head();  //显示logo
 int expandname_check=argument_check(argc,argv);  //命令行参数个数检测,expandname_check检测是否指定了扩充名
 file_check(argv[1]);      //文件路径及文件名检测
 unsigned long file_size=size_detect(argv[1]);  //file_size是源文件的大小,单位bytes
 double size=(double)file_size;       //把源文件大小转换为double用于精确显示源文件大小
 if(argc==2)           //如果没有指定分割的文件大小则输出说明
 {

  cerr<<"/n/n/n你要分割的源文件 "<<argv[1]<<" 的大小为 "
   <<fixed<<setprecision(2)<<size/1024.0<<" KB。/n"
     "请指定分割的文件大小。/n格式为 st <源文件> <分割大小(KB)>  <指定分割文件的扩展名(可选)>/n例如"
        "/nst "<<argv[1]<<" 1024"<<endl;
  return 1;
    }
 else
 {
  unsigned long cut_size=size_detect(file_size,argv);  //判断输入的分割大小是否正确,cut_size是要分割的大小
        cout<<"/n/n/n源文件 "<<argv[1]<<" 大小为 "<<fixed<<setprecision(2)<<size/1024.0<<" KB。/n"
     "你选择的分割大小为 "<<cut_size/1024<<" KB。"
   <<(expandname_check==1 ? "/n你指定的新文件扩展名为 " : " ")  //如果指定了扩展名则显示提示的信息
   <<(expandname_check==1 ? argv[3] : " ")
      <<"/n源文件将被分割为 "
   <<(file_size%cut_size ? file_size/cut_size+1 : file_size/cut_size)<<" 个子文件。"<<endl;
  cout<<"确认分割么?按 N 键退出,按其它键继续。"<<endl;
  char y=_getch();
  if(y=='N'|| y=='n')
   exit(1);
  cout<<endl;      //刷新缓冲区,因为上面输入了y的值。所以要刷新缓冲区。
  file_cut(argv,file_size,cut_size,expandname_check);   //调用分割函数分割文件。
 }
 cout<<"文件 "<<argv[1]<<" 分割完毕。"<<endl; 
 return 0;
}

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值