对自己打造文件切割机一文的补充
文/图 kflnig
===================================
《自己打造文件切割机》一文:http://www.zzzyk.com/kf/201009/74171.html.灰狐的代码还是有很多的不足之处,非常明显的一处就是在文件分割时的关键代码有很多需要改进的地方。首先,BCB的文件流类比C的那些文件函数好记和好用得多,没有发挥出C++类库的威力,就简单论开发效率来讲,C++还是稍微比C快一点(效率也许会稍微低一点);最重要的是,就是所有代码都是几乎随心所欲的跟电脑要内存,这也就怪不得效率会这么低了。通常,读写文件的话,我们有两种选择,一种是用API函数,另一种是用类库。我比较喜欢类库,效率高嘛!
首先我们需要包括文件头include <fstream.h>。fstream包括istream(输入流)和ofstream(输出流),这些输入输出都是相对变量而言的。也就是说,写文件相对变量来讲是输出(从变量输出到文件),而读文件却是属于输入流。这是Pascal(Delphi)出身的程序员最觉得头痛的问题之一。
对于操作文件的修改代码,我给出的还是单线程的,因为这种东西是大家用的,我怕自己代码写的太多错误率高。不过类库并非都是好的,还是有些不足的地方,比如不能直接读出文件的大小等(或许是我自己知识浅薄),于是我就自己花了一个晚上,用API自己写了一个文件流类,加入了一些功能以弥补不足,只是竟然效率比那个稍微低了一点(真的是不可思议,我的几乎都是API的浅包装啊),我自己写的类中的函数命名都是按照标准的文件输入输出流来命名的,为了方便,所以我稍微使用了一些结构化异常。
下面的代码都是运行在控制台下的,在Windows XP+BCB6.0下调试通过。
我的类库还有非常多的地方需要完善,比如说一些比较危险的函数,如deletefile,我不敢加进去,怕万一有问题害人害己那就非常不好了。最后还是得谈谈效率,论效率我的代码甚至比灰狐的还低不少(两者都是单线程),一是C语言本身的函数的高效性,二是我读写文件的时候比较小气,都是1MB读取,适合一些内存不怎么多的机器使用。下面解释一下我的代码中难懂的一些代码。由于是连夜赶出来的,所以不免会有一些小错误。#include <windows.h>
#include <iostream.h>
#include <vcl.h>
void cutfile();
void restorefile();
class kifstream{//对应ifstream,本库要搞多线程估计不行
private:
HANDLE ifile;
DWORD tsize;
bool endoffile;
public:
kifstream(char name[]);
kifstream(){};
bool open(char name[]);
bool read(char buffer[],int num);
bool seek(int position);
unsigned int tellp();
unsigned int size();
void close();
unsigned int gcount();
bool eof();
};
kifstream::kifstream(char name[])
{
open(name);
}
bool kifstream::open(char name[])
{
ifile=CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (ifile==INVALID_HANDLE_VALUE) return false;
else
{
endoffile=false;//打开的时候置是否到达文件末尾位为false
return true;//打开成功
}
}
bool kifstream::read(char buffer[],int num)
{
if (ReadFile(ifile,buffer,num,&tsize,NULL)!=0)//tsize是实际读入的字节数
if (tsize!=0)
{
endoffile=false;
return true;
}
else
{
endoffile=true;
return true;
}
else return false;
}
unsigned int kifstream::gcount()//得到上一次read到底读了多少字节
{
return tsize;
}
unsigned int kifstream::size()
{
return GetFileSize(ifile,NULL);
}
bool kifstream::seek(int position) //对于这个随机访问,还有一些功能需要完善。
{
if (SetFilePointer(ifile,position,NULL,FILE_BEGIN)==0xFFFFFFFF) return false;
else return true;//相对开头移动文件指针
}
unsigned kifstream::tellp()
{
return SetFilePointer(ifile,0,0,FILE_CURRENT);//利用它的返回值,告诉你文件指针在哪里。
}
void kifstream::close()
{
CloseHandle(ifile);//千万不要忘记关闭
}
bool kifstream::eof()
{
if (tellp()==size()) return true;//这是一种文件刚刚读到末尾时候的特殊情况,一定不要忘记考虑
else return endoffile;//在read的时候,这个endoffile的值会改变。
}
#pragma hdrstop由于kofstream和kifstream基本相似,所以就不再介绍了。最好把它们都提取出来放到各自的头文件中。
const int buffersize=1024*1024;//每次读的大小1MB
const int eachsize=buffersize*10;//定义10MB为一个文件
#pragma argsused
int main(int argc, char* argv[])
{
cutfile();
return 0;
}void cutfile()
{
DWORD time1,time2;
unsigned int part,totalsize=0;
int n,num,index=0;
char *buffer;
time1=GetTickCount();
kifstream fl1("d:\Powerword2007.16972.0.exe");//示例需要分割的文件
kofstream fl2;
AnsiString fname;//喜欢C++标准库的朋友也可以使用string类型。
__try
{
buffer=new char[buffersize];//1MB
while(!fl1.eof())
{
if (fl1.size() % eachsize==0) part=fl1.size() / eachsize;//万一刚刚好的情况
else
part=fl1.size()/eachsize +1; //计算需要几部分++index;
fname="d:\fenge\";
fname=fname+IntToStr(index);
fname=fname+".rar";
fl2.open(fname.c_str());//以上几行为产生文件名num=eachsize / buffersize;//计算需要读几次,因为分割基本都以1MB以上分割,所以一般都整除
for (n=1;n<=num;++n)
{
fl1.read(buffer,buffersize);
fl2.write(buffer,fl1.gcount());//分割
}
fl2.close() ;
}
}
__finally
{
fl1.close() ;
delete []buffer;
}
time2=GetTickCount();
cout<<time2-time1<<"ms"<<endl;
getchar();
}void restorefile()
{DWORD time1,time2;
unsigned int part,totalsize=0;
int num,index=0;
char *buffer;
time1=GetTickCount();
kifstream fl1;
kofstream fl2("d:\fenge\Powerword2007.16972.0.exe");
AnsiString fname;
__try
{
buffer=new char[buffersize];
if (fl1.size() % eachsize==0) part=fl1.size() / eachsize;
else part=fl1.size() / eachsize +1;//计算被分成了多少份
for (num=1;num<=part;++num)
{
++index;
fname="d:\fenge\";
fname=fname+IntToStr(index);
fname=fname+".rar";
fl1.open(fname.c_str());while(!fl1.eof())
{
fl1.read(buffer,buffersize);
fl2.write(buffer,fl1.gcount());
}
fl1.close() ;
}
}
__finally
{
fl2.close() ;
delete []buffer;
}
time2=GetTickCount();
cout<<time2-time1<<"ms"<<endl;
getchar();
}
在代码上没有什么建树,只是修改了灰狐随便向电脑要内存的缺点。因为个人觉得控制台的代码较GUI的容易弄懂,所以写的都是控制台代码。写到最后夸奖一句灰狐,他的代码风格挺不错的,代码很容易看懂。
最后基于美化界面的考虑,我再给出一个透明界面的代码。__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
m_nAlpha = 255;
SetWindowLong(Handle,GWL_EXSTYLE, GetWindowLong(Handle,GWL_EXSTYLE)|WS_EX_LAYERED);
SetAlpha(m_nAlpha);
}
void __fastcall TForm1::SetAlpha(int nAlpha)
{
SetLayeredWindowAttributes(Handle,NULL,nAlpha,LWA_ALPHA);
}
以上代码只要调节m_nAlpha的值就可以得到透明程度不同的窗体了
补充:综合编程 , 其他综合 ,