我想做一个文件分割工具!要如何实现!解决就给分
有源代码更佳!
说说思路也行!
有源代码更佳!
说说思路也行!
解决方案 »
- 求教几个DATASET与事务的问题 偶总是很模糊
- 如何控制下拉列表中的值不可更改
- 又是ACEESS查询日期+时间的问题,特急~~快帮我解决了吧,搞死我了~
- 如何在信使服务中传递文件?
- 问一下怎么判断一个只读文件是否在被别的应用程序使用
- 给大家介绍一个好站点,http://www.dev-club.com,开发者俱乐部,里面有不少高手
- 怎么让图片逆时针旋转90度,或者说旋转270度?谢谢!
- TbitMap实例能否装入Jpg文件,如果可以,怎样装入。
- 长驻内存任何做?
- 动态添加的菜单项,怎么编写相应该的事件呢?
- ★★★★窗体中加入了三个FastReport的TfrReport控件做报表,为什么窗体打开的速度非常慢???高手们请进,在线等!!!谢谢★★★★
- 既然Delphi8那么好,为什么还有那么多人在用D6和D7???
-------------------------------------------------------------------------------- 在实际工作中,经常会遇到一些比较大而自己又非常需要的文件,并且必须通过软盘来进行转移。这时候就必须对该文件进行分割,然后分盘拷贝,最后再恢复。如果手头没有相应的分割软件,那就麻烦了。不过,如果您机器里装有VC++5.0,并具备一定VC++5.0编程的知识,就完全可以编写出自己的分割工具,还可以根据个人的喜好,设计出具有自己风格的用户界面。
前不久,笔者就用VC++5.0编写了一个自己的分割软件。通过多次分割试验,效果还可以,完全可以实现对文件的分割处理。以下就是整个软件的编写过程。
一. 文件分割的基本原理
文件之所以能够被分割,是与文件在计算机里的存储方式密切相关的,大家都知道,所有文件都是以二进制的形式存储于介质(包括硬盘、软盘等外部存储器)之中。计算机在读取文件时,总是把数据转化成二进制的形式,然后再根据文件系统的相应规定来分别进行处理。具体的说明可参见相关资料。基于这个道理,所有文件都可以以二进制的格式进行读写、分割,然后再以二进制的格式把分割后的文件重新组合起来。这样就实现了对文件的分割和恢复。这里要用到一个DOS的内部命令——COPY,具体用法如下:
copy filename1/b+filename2/b+
…+filenameN/b filename
这里,开关选项b是指以二进制的形式对文件进行拷贝;filenameN是被分割成的N个文件;filename是组合后的文件名,一般同原文件名。
二. 程序编写过程及禅解
1.先创建一个名为Splite的工程文件,利用AppWizard生成一个基于对话框的程序框架。对话框具有如图所示的各类控件。其中,编辑框1要求输入要被分割的文件名,可以通过浏览按钮选择;列表框2能够显示分割后的文件列表;编辑框3显示分割成的文件数,也就是需要的软盘数;要分割的文件被选择之后,按下分割按钮,即可进行分割操作。
2.程序编写
(1).使用Class Wizard的Member Variables 制表页给编辑框1(ID号为:IDC_EDIT_FILENAME)添加变量m_fName。
(2).在SpliteDlg.h里加上下面程序段阴影部分的代码。
class CSpliteDlg : public CDialog
{
// Construction
public:
CSpliteDlg(CWnd* pParent = NULL); // standard constructor
CString SplitFileName[20],FileTitle;
DWORD FileLength,SingleDisk;
BOOL FileState;
int DiskNum;
// Dialog Data
//{{AFX_DATA(CSpliteDlg)
enum { IDD = IDD_SPLITE_DIALOG };
CString m_fName;
//}}AFX_DATA
int SplitDiskNum(CFile &files);
BOOL SpliteFiletoNum(CFile &file);
SplitFileName[20]是分割后的文件名数组,这里定义为20个;FileTitle是除去后缀的文件名;FileLength是要分割的文件长度;布尔量FileState是判断分割是否成功的标志,成功则在列表框2中显示分割后的文件列表;整型数DiskNum是指分割后的文件数。
函数SplitDiskNum(CFile &files)对要分割的文件进行判断,并返回分割后的文件数(也就是需要的软盘数);函数SpliteFiletoNum(CFile &file)将完成文件的分割过程,成功则返回TURE,否则返回FALSE。
(3).打开SpliteDlg.cpp,在SpliteDlg.cpp里添加上述函数和其它功能的实现代码。如下:
a.在构造函数中添加以下阴影处代码
SingleDisk=2048*705; //一张软盘的容量
FileState=FALSE;
DiskNum=1;
b.在OnPaint(CDC *pDC)函数末尾添加以下代码:
UpdateData(FALSE); //初始化编辑框1的变量
GotoDlgCtrl(GetDlgItem(IDC_EDIT_FILENAME)); //将光标指定到编辑框1中
CListBox *pList =(CListBox *) GetDlgItem(IDC_LIST_RESULT);
//设置列表框2的ClistBox对象指针
pList->ResetContent(); //重新设置列表框内容
if(FileState==TRUE) //文件分割成功
{
for(i=0;i<=disknum;i++)
pList->AddString(SplitFileName[i]); //向列表框中添加分割后的文件名
}
c.利用Class Wizard添加“浏览”按钮的响应函数,代码如下:
void CSpliteDlg::OnButtonBrowse()
{
char Filter[]=“所有文件(*.*)|*.*||";
CFileDialog dlgOpen(TRUE,0,0,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,
(LPCTSTR)Filter,NULL);
if(dlgOpen.DoModal()==IDOK)
{
m_fName=dlgOpen.GetPathName();
FileTitle=dlgOpen.GetFileName(); //取得要分割的文件名(不包含路径、扩展名)
}
else return ;
SetDlgItemText(IDC_EDIT_FILENAME, (LPCTSTR)m_fName); //在编辑框1中显示文件名
SetDlgItemText(IDC_EDIT_DISKNUM, _T(“")); //在编辑框3中覆盖前次操作的文件数
Invalidate(TRUE); //对对话框窗口进行重画
}
d.利用Class Wizard添加“分割”按钮的响应函数,代码如下:
void CSpliteDlg::OnButtonSplite()
{
CFile files;
CFileException fe;
if (!files.Open(m_fName, CFile::modeRead | CFile::shareDenyWrite, &fe))
{
CString sMsg;
sMsg.Format(“读取%s文件时发生错误!",m_fName);
AfxMessageBox(sMsg,MB_OK,0);
return ;
}
int i;
DiskNum=SplitDiskNum(files);
CString sMsg;
if(DiskNum>=2)
{
sMsg.Format(“%d",DiskNum);
SetDlgItemText(IDC_EDIT_DISKNUM, (LPCTSTR)sMsg); //在编辑框3中显示文件数
进 if(SpliteFiletoNum(files)==0) //调用分割函数行分割操作
{
AfxMessageBox(“分割文件失败!",MB_OK,0);
}
else
{
AfxMessageBox(“分割文件成功!",MB_OK,0);
FileState=TRUE; //分割成功,设置成功标志
Invalidate(TRUE);
}
}
else return;
files.Close(); //关闭打开的被分割文件
}
添加函数SplitDiskNum(CFile &files)代码如下:
int CSpliteDlg::SplitDiskNum(CFile &files)
{
int DiskNum;
FileLength=files.GetLength(); //取得要分割文件的长度
if(FileLength<=singledisk)
{
AfxMessageBox(“该文件能被一张盘复制,不必分割!",MB_OK,0);
DiskNum=0;
}
else DiskNum=FileLength/SingleDisk+1; //计算分割后的文件数
return DiskNum;
}
添加函数SpliteFiletoNum(CFile &file)代码如下:
BOOL CSpliteDlg::SpliteFiletoNum(CFile &file)
{
BOOL Success=FALSE;
int i;
DWORD dwBitsSize=SingleDisk; // dwBitsSize是指写入文件的字节数
CFile filed;
CString FileNum;
//开辟数据缓冲区,大小为一张软盘的容量
HANDLE filedate;
filedate = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,SingleDisk);
unsigned char * imgtemp;
imgtemp=(unsigned char *)::GlobalLock((HGLOBAL)filedate);
//对文件进行分割,并写入分割后的文件中
for(i=1;i<=disknum;i++)
{
FileNum.Format(“%d.%d",i,i);
SplitFileName[i-1]=FileTitle+FileNum;
if(i==DiskNum) dwBitsSize =FileLength-(DiskNum-1)*SingleDisk;
file.Seek(SingleDisk*(i-1),CFile::begin);
if(file.ReadHuge(imgtemp, dwBitsSize)!= dwBitsSize)
return FALSE;
filed.Open(SplitFileName[i-1],CFile::modeCreate|CFile::modeWrite,0);
filed.WriteHuge(imgtemp, dwBitsSize);
filed.Close();
}
if(i==(DiskNum+1)) Success=TRUE; //判断分割是否成功
//创建合并文件的批处理文件
FileNum=_T(“.bat");
SplitFileName[DiskNum]=FileTitle+FileNum;
filed.Open(SplitFileName[DiskNum],CFile::modeCreate|CFile::modeWrite,0);
CString BatContent=_T(“copy ");
CString BatFile[20];
for(i=0;i {
BatFile[i]=SplitFileName[i]+_T(“/b");
BatContent+=BatFile[i];
if(i!=DiskNum-1) BatContent+=_T(“+");
else BatContent+=_T(“ ");
}
BatContent+=m_fName;
//按照“copy filename1/b+filename2/b+…+filenameN/b filename”的顺序写入批处理
for(i=0;i {
unsigned char ch=BatContent[i];
filed.Write(&ch,1);
}
return Success;
filed.Close();
}
以上是该程序的主要代码,在VC++5.0下通过编译后,将生成可执行文件Split.exe。该程序只是实现了对文件的分割处理,读者也可以根据个人需要,设计出自己喜好的界面风格,还可以加入其它相关的功能。本文旨在起到抛砖引玉的作用,给广大读者以启发,希望大家都能编写出功能强大并且属于自己的分割软件。
(天津 房超)
(一)编程原理:
文件分割实际上就是将目标文件用二进制读写的方法,精确的连续保存为合适大小的独立文件,一般来说,分割后的文件在正确组装前是不能被使用的。
文件还原是文件分割的逆过程,即是将分割后的文件严密的按照分割顺序用二进制读写的方法写入一个同一个文件的过程,只要程序算法和逻辑正确严密,分割前和分割后的文件是没有一个字节的差别的。
之所以使用双通道技术是因为当被分割的文件较大或者非常大(远远大于内存)时,使用单个文件通道定义的内存二进制缓冲数组非常容易造成内存的用尽而导致操作失败,另一方面,它的处理速度和可靠性也是非常令人担忧的。
编程思路是,首先使用双通道技术将目标文件分割成指定大小的文件,扩展名依次是“指定文件名+.源文件扩展名+.分割序号”,并且生成一个还原信息文件“被分割文件名.hj”,该文件将记录文件分割的有关信息;文件还原时,同样利用双通道,按照在还原信息文件中登记的信息,将待还原的文件写入同一个文件中。
(二)编程实践:
(1)启动vb6,建立一个标准exe工程,添加一个窗体form1,添加microsoft common dialog control 6.0控件,命名为cod1;添加两个frame控件(frame1的caption=“文件分割”,frame2的caption=“文件还原”);添加五个标签框,caption属性依次为“被分割文件名”、“分割后文件大小”、“分割后文件保存在”、“单位:bytes字节”、“还原信息文件名”、“还原后文件保存在”;由上至下一次添加四个caption=“浏览...”的命令按钮command1、command2、command3、command4;由上至下依次添加5个textbox按钮txtFileName、txtFileLength、Txtoutname、txtTemplateName、txtOutputFile;添加两个命令按钮cmdsplit,caption=“开始分割”、cmdunsplit,caption=“开始还原”;两个命令按command5、command6用来指示操作执行进度。代码如下:
Option Explicit
Private Sub cmdSplit_Click() ’文件分割
Dim err_descr As String ’定义接收返回错误码的字符串变量
If Not SplitFile(txtFileName.Text,0,err_descr,CLng(txtFileLength.Text),Txtoutname.Text) Then
MsgBox "文件操作产生了错误——" & err_descr,vbExclamation
Else
MsgBox "文件分割操作已经圆满完成!"
End If
End Sub ’当splitfile公用过程返回值=true表示操作成功,否则失败并返回错误简短的提示
Private Sub cmdUnsplit_Click() ’文件还原
Dim err_descr As String
If Not ReassembleFile(txt TemplateName.Text,False,txtOutputFile.Text) Then
MsgBox "文件操作产生了错误——" & err_descr,vbExclamation
Else
MsgBox "文件还原操作已经圆满完成!"
End If
End Sub ’当ReassembleFile公用过程返回值=true表示操作成功,否则失败并返回错误简短的提示
Private Sub Command1_Click() ’选择被分割文件
CoD1.Filter="所有格式文件*.*|*.*"
CoD1.ShowOpen
If CoD1.FileName<>"" Then
txtFileName.Text=CoD1.FileName
End If ’如果未选中文件就退出过程
End Sub
Private Sub Command2_Click() ’分割后文件保存路径名称
With CoD1
If txtFileName.Text="" Then
MsgBox "请首先选择一个被分割文件!"
Exit Sub
End If ’如果未选定被分割文件退出过程
.ShowSave
If .FileName<>"" Then
Txtoutname.Text=.FileName
End If ’如果未指定保存文件名退出
End With
End Sub
Private Sub Command3_Click() ’传回还原信息文件名
With CoD1
.FileName=""
.Filter="还原信息文件*.hj|*.hj" ’只显示*.hj还原信息文件
.ShowOpen
If .FileName<>"" Then
txtTemplateName.Text=.FileName
End If
End With
End Sub
Private Sub Command4_Click() ’得到并计算还原后文件名、扩展名
Dim g
With CoD1
If txtTemplateName.Text="" Then
MsgBox "请首先选择一个还原信息文件!"
Exit Sub ’如果还原信息文件未被选中,则退出过程
End If
.Filter=""
.FileName="" ’清空过期文件名和类型指针
.ShowSave
If .FileName<>"" Then
g=InStr(1,txtTemplateName.Text,".") ’查找第一个“.”
txtOutputFile.Text=.FileName & Mid
(txtTemplateName.Text,g,4) ’返回文件的用户指定名称和原扩展名
End If
End With
End Sub
Private Sub Form_Load()
Me.Left=(Screen.Width-Me.Width)/2
Me.Top=(Screen.Height-Me.Height)/2 ’窗体居中
Me.Caption=App.Title ’初始化标题栏
End Sub ’主程序结束
(2)添加一个模块Module1,其中包含各种算法具体实现过程,双击模块写入以下代码:
Type FileSection
Bytes() As Byte
End Type ’定义实际内存数组
Type SectionedFile
Files() As FileSection
End Type ’定义辅助内存数组,以备扩展使用
Type FileInfo
OrigProjSize As Long ’文件大小
OrigFileName As String
FileCount As Integer
FileStartNum As Long
End Type ’定义还原信息文件结构参数
Public Function SplitFile(SplitFileName As String,BeginningNumber As Long,ReturnErrorDes As String,Split As Long,oName As String) As Boolean
Dim SaveName As String ’分割后文件名
Dim fnum As Integer,fnum1 As Integer ’文件通道变量
SplitFile=True ’如果下面没有错误,返回真值
On Error GoTo CleanUp
Dim CurrentFile As SectionedFile,m_lngNumFil As Long,m_LngLoop As Long,FilesLen As Long
FilesLen=FileLen(SplitFileName) ’得到被分割文件大小
If FilesLen <= Split + 1 Then
SplitFile=False
ReturnErrorDes="被分割文件大小小于分割后文件大小,请重新设置!"
Exit Function
End If ’如果被分割文件小于分割后文件,退出过程
fnum=FreeFile ’返回第一个空闲通道用来读取
Open SplitFileName For Binary As fnum ’用二进制方式打开被分割文件
If CInt(FilesLen/Split)>=FilesLen/Split Or CInt(FilesLen/Split)=FilesLen/Split Then
m_lngNumFil=CInt(FilesLen/Split)
Else
m_lngNumFil=CInt(FilesLen/Split)+1
End If ’精确计算文件将被分割的个数
ReDim CurrentFile.Files(1) ’分配一个内存辅助数组
For m_LngLoop=1 To m_lngNumFil
’这个循环用来将文件分割,并且生成分割后的文件
If m_LngLoop < m_lngNumFil Then ’如果不是最后一次循环
ReDim CurrentFile.Files(1).Bytes(1 To Split)
’ 重新分配大小等于分割尺寸的内存数组
Get #fnum,,CurrentFile.Files(1).Bytes
’读取等于分割大小的二进制数据到内存数组
Else ’如果是最后一次循环
ReDim CurrentFile.Files(1).Bytes To FilesLen-((m_lngNumFil-1)*Split))
’重新分配大小等于遗留长度的内存数组
Get #fnum,,CurrentFile.Files(1).Bytes
Close #fnum ’关闭读取文件通道
End If
SaveName=oName & "." & Format(BeginningNumber-1+m_LngLoop,"00#") ’计算分割后的文件名,扩展名为00?
fnum1=FreeFile ’得到第二个空闲通道用来写入
Open SaveName For Binary As fnum1
Put #fnum1,1,CurrentFile.Files(1)
DoEvents
Close #fnum1 ’用二进制方式写入分割后的文件
Form1.Command6.Caption=FormatPercent(m_LngLoop / m_lngNumFil) ’显示简单的进度指示
Form1.Command5.Caption=SaveName ’显示正在操作的文件名
Next
Dim FileInfoFile As FileInfo ’定义还原信息文件内容
FileInfoFile.FileCount=m_lngNumFil ’分割后文件个数
FileInfoFile.OrigFileName=oName ’输出文件名
FileInfoFile.OrigProjSize=FileLen(SplitFileName) ’被分割文件大小
FileInfoFile.FileStartNum=BeginningNumber ’分割后文件起始编号
SaveName=oName & ".HJ" ’还原信息文件名
fnum=FreeFile
Open SaveName For Binary As #fnum
Put #fnum,,FileInfoFile
Close #fnum ’写入还原信息文件
Exit Function
CleanUp: ’如果出现错误
ReturnErrorDes=Err.Description
SplitFile=False ’返回值为false
End Function
PublicFunctionReassembleFile(Template FileName As String,Optional UseOldFilenameAsBoolean=True,OutPutName as string)As Boolean ’定义文件还原操作公用过程
On Error GoTo e
Form1.MousePointer=11
Dim FileInfo As FileInfo,outname As String,File As SectionedFile,m_LngLoop As Long,OpenName
Dim fnum As Integer,fnum1 As Integer
ReassembleFile=True
fnum=FreeFile
Open TemplateFileName For Binary As #fnum
Get #fnum,,FileInfo
Close #fnum ’读取还原信息文件的有关内容
If UseOldFilename Then
outname=FileInfo.OrigFileName
Else
outname=OutPutName
End If ’是否自己指定还原后文件名
ReDim File.Files(1)
fnum1=FreeFile
Open outname For Binary As #fnum1
For m_LngLoop=1 To FileInfo.FileCount
’通过还原信息中记载的文件个数确定读取次数
OpenName=FileInfo.OrigFileName & "." & Format((FileInfo.FileStartNum-1+m_LngLoop),"00#")
’得到分割后生成的文件名称、路径
fnum=FreeFile
Open OpenName For Binary As #fnum
Get #fnum,1,File.Files(1)
Close #fnum ’读取
Put #fnum1,,File.Files(1).Bytes ’写入
Form1.Command6.Caption=FormatPercent(m_LngLoop/FileInfo.FileCount)
Form1.Command5.Caption=OpenName
Next
Close #fnum1
Form1.MousePointer=0
Exit Function
e:
MsgBox "文件操作产生了错误:" & Err.Description,vbExclamation
ReassembleFile=False
Form1.MousePointer=0
End Function
(三)运行调试:
首先通过浏览指定被分割文件名、分割后文件大小、分割后文件名或者还原信息文件名、还原后文件名,然后点击开始分割或者开始还原即可,该程序算法严谨,但是,为了保留一定的扩展能力和对以往源代码的兼容性,也存在一些冗余代码,读者尽可以根据自己的喜好进行改进。另外,使用vb5的朋友注意了,本文函数FormatPercent函数只能在vb6中使用,它的作用是将一个表达式转化成百分数,你必须采用其他的变通方法,其他代码全部通用。
function UniteFile(SourceFile,TargetFile:String):Boolean;
var
Target,Source: TFileStream;
MyFileSize: Integer;
begin
try
Source:= TFileStream.Create(SourceFile,fmOpenReadWrite);
Target:= TFileStream.Create(TargetFile,fmOpenReadWrite);
try
Target.Seek(0,soFromEnd);
Target.CopyFrom(Source,Source.Size);
MyFileSize:=source.Size;
Target.WriteBuffer(MyFileSize,SizeOf(MyFileSize));
finally
Target.Free;
Source.Free;
end;
except
Result:= False;
Exit;
end;
Result:= True;
end;//流文件分解
function ApartFile(SourceFile,TargetFile:String):Boolean;
var
Source: TFileStream;
Target: TMemoryStream;
MyFileSize: Integer;
begin
try
Target:= TMemoryStream.Create;
Source:= TFileStream.Create(SourceFile,fmOpenReadWrite);
try
Source.Seek(-sizeof(MyFileSize),soFromEnd);
Source.ReadBuffer(MyFileSize,SizeOf(MyFileSize)); //读出资源大小
Source.Seek(-MyFileSize-sizeof(MyFileSize),soFromEnd); //定位资源位置
Target.CopyFrom(Source,MyFileSize); //取出资源
Target.SaveToFile(TargetFile); //存放到文件
finally
Source.Free;
Target.Free;
end;
except
Result:= False;
Exit;
end;
Result:= True;
end;
unit CutFrm;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls, FileCtrl, ImgList, Buttons
,ShellAPI,StrUtils;type
TForm1 = class(TForm)
PageCutFile: TPageControl;
TabSheetCutSize: TTabSheet;
TabSheetCutFile: TTabSheet;
TabSheetSelectFile: TTabSheet;
TabSheetDestDir: TTabSheet;
SourceDir: TDirectoryListBox;
FileList: TFileListBox;
Splitter1: TSplitter;
Splitter2: TSplitter;
Panel2: TPanel;
Drive: TDriveComboBox;
Label1: TLabel;
Filter: TFilterComboBox;
DestDir: TDirectoryListBox;
DestDrive: TDriveComboBox;
BtnNew: TButton;
BtnDelete: TButton;
Panel3: TPanel;
Label3: TLabel;
RadioGroupSize: TRadioGroup;
ImageList1: TImageList;
Panel1: TPanel;
Label2: TLabel;
STextFilePath: TStaticText;
Label6: TLabel;
STextDestPath: TStaticText;
Label8: TLabel;
STextFileSize: TStaticText;
Label9: TLabel;
STextCutSize: TStaticText;
LblSizeUnit: TLabel;
Label10: TLabel;
Memo: TMemo;
EdtFileName: TEdit;
LblDestDir: TLabel;
SpBtnStart: TSpeedButton;
ProgressBar: TProgressBar;
EdtNewDir: TEdit;
Label11: TLabel;
Panel5: TPanel;
Label7: TLabel;
Label12: TLabel;
EdtCutSize: TEdit;
UpDown: TUpDown;
LblSizeUnit2: TLabel;
STextFileSize2: TStaticText;
Label14: TLabel;
ChkBox: TCheckBox;
procedure RadioGroupSizeClick(Sender: TObject);
procedure UpDown1Click(Sender: TObject; Button: TUDBtnType);
procedure SpBtnStartClick(Sender: TObject);
procedure FileListDblClick(Sender: TObject);
procedure PageCutFileChange(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure BtnNewClick(Sender: TObject);
procedure BtnDeleteClick(Sender: TObject);
procedure DestDirDblClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;
implementation{$R *.dfm}procedure TForm1.RadioGroupSizeClick(Sender: TObject);
begin
case RadioGroupSize.ItemIndex of
0: EdtCutSize.Text:= '2000' ; //2000 K
1: EdtCutSize.Text:= '1440' ; //1440 K
2: EdtCutSize.Text:= '1200' ; //1200 K
3: EdtCutSize.Text:= '1000' ; //1000 K
4: EdtCutSize.Text:= '720' ; //720 K
5: EdtCutSize.Text:= '500' ; //500 K
6: EdtCutSize.Text:= '300' ; //300 K
7: EdtCutSize.Text:= '200' ; //200 K
8: EdtCutSize.Text:= '100' ; //100 K
else EdtCutSize.Text:= '50' ; //100 K
end;
end;procedure TForm1.UpDown1Click(Sender: TObject; Button: TUDBtnType);
begin
RadioGroupSize.ItemIndex:=-1;
EdtCutSize.SetFocus;
end;procedure TForm1.SpBtnStartClick(Sender: TObject);
var
fs:TFileStream;
ms:TmemoryStream;
bat:TextFile;
SaveFileName,BatFileName:string;
CutSize,FileCount,i:integer;
begin
//用一个'文件流' 以只读方式打开原始文件
fs:=TfileStream.create(STextFilePath.Caption,fmOpenRead);
// 然后创建一个'内存流'
ms:=TmemoryStream.create;
//根据文件切割的大小计算字节数,
CutSize:=StrToInt(STextCutSize.Caption)*1024; SaveFileName:=STextDestPath.Caption+'\'
+ExtractFileName(STextFilePath.Caption);
FileCount:= 1; //切割过程中显示一个进度,让用户了解进度,
ProgressBar.Min:= 0;
//根据文件大小设定最大最大值和步长
ProgressBar.Max:= (fs.size div CutSize)+1;
ProgressBar.step:= 1; while fs.Position<fs.Size-1 do
begin
ms.position:= 0;
ms.size:= 0;
if fs.size-fs.Position<CutSize then
CutSize:=fs.size-fs.position;
//从'文件流'中向'内存流'中拷贝指定的大小
ms.CopyFrom(fs,CutSize);
//响应应用程序其他消息,如让应用程序修改进度条
//但需注意避免死循环
application.ProcessMessages; //在切割过程中不断修改进度条的当前位置,给用户一个运动的状态。
ProgressBar.StepIt;
//文件扩展名累计创建(方便合并),
//并将内存流存储到目标文件夹下
ms.SaveToFile(ChangeFileExt(SaveFileName,'.'+inttostr(FileCount))); Memo.lines.add('正在生成第 '+IntToStr(FileCount)+' 个文件!');
inc(FileCount);
end;
fs.Free; {在 Dos 中有一条命令可以完成文件的合并
Copy file1 /b +file2 /b file3
所以要生成一个批处理命令文件,就可以在需要的时候能自动完成合并工作} //生成一个批处理命令文件名
BatFileName:=STextDestPath.Caption+'\'
+ChangeFileExt(ExtractFileName(STextFilePath.Caption),'.bat'); AssignFile(bat,BatFileName);
rewrite(bat);
writeln(bat,'echo off');
writeln(bat,'echo 谢谢使用文件分割器 1.0 .....');
writeln(bat,'echo .');
writeln(bat,'echo 正在准备生成文件'+ExtractFileName(BatFileName));
writeln(bat, 'echo .');
writeln(bat,' echo 按 CTRL + Z 键可以中止,其他键继续!');
writeln(bat,'pause'); for i := 1 to FileCount + 1 do
begin
if i = 1 then
writeln(bat,'copy '+
ChangeFileExt(ExtractFileName(SaveFileName),'.1')
+'/b '+ExtractFileName(SaveFileName))
else
writeln(bat,'copy '+ExtractFileName(SaveFileName)+'/b +'
+ChangeFileExt(ExtractFileName(SaveFileName),'.'+inttostr(i))
+'/b');
end;
Application.MessageBox('切割成功完成!','信息框',MB_OK+MB_ICONINFORMATION);end;procedure TForm1.FileListDblClick(Sender: TObject);
var
fs:TFileStream;
AFileSize:Single;
FileName,NewFolder:string;
DotPosition:integer;
begin
PageCutFile.ActivePage:=TabSheetDestDir;
DestDir.Directory:=SourceDir.Directory; FileName:=ExpandFileName(FileList.FileName);
fs:=TfileStream.create(FileName,fmOpenRead);
//获得文件大小
LblSizeUnit2.Caption:='K';
AFileSize:=fs.Size/1024; if AFileSize>1000 then
begin
AFileSize:=AFileSize/1000;
LblSizeUnit2.Caption:='M';
end;
STextFileSize2.Caption:=FloatToStrF(AFileSize,ffFixed,4,2);
fs.Free; NewFolder:=ExtractFileName(FileName);
DotPosition:=pos('.',NewFolder);
NewFolder:=Copy(NewFolder,1,DotPosition-1);
EdtNewDir.Text:=NewFolder;
end;procedure TForm1.PageCutFileChange(Sender: TObject);
var
CanStart:boolean;//判断是否可以开始
fs:TFileStream;
AFileSize:Single;
begin
//当选择切割文件页面时
if PageCutFile.ActivePage=TabSheetCutFile then
begin
CanStart:=False;
STextFilePath.Caption:=FileList.FileName;
STextDestPath.Caption:=DestDir.Directory;
STextCutSize.Caption:=EdtCutSize.Text;
if FileExists(STextFilePath.Caption)then
begin
CanStart:=True;
//用一个'文件流' 以只读方式打开原始文件
//用一个'文件流' 以只读方式打开原始文件,以便获得文件大小
fs:=TfileStream.create(STextFilePath.Caption,fmOpenRead);
LblSizeUnit.Caption:='K'; // 文件大小单位为千字节
AFileSize:=fs.Size/1024; // 获得文件大小,并换算为千字节
if AFileSize>1000 then // 如果文件大于一千字节,则以兆字节为单位
begin
AFileSize:=AFileSize/1000; //将文件大小换算为兆字节
LblSizeUnit.Caption:='M'; // 显示单位为 M
end;
// 函数FloatToStrF 将浮点数转为字符串并格式化输出,保留两位小数
STextFileSize.Caption:=FloatToStrF(AFileSize,ffFixed,4,2);
fs.Free; // 释放TfileStream变量所占内存资源
end
else begin
Application.MessageBox('请选取文件!','信息框',MB_OK+MB_ICONINFORMATION);
PageCutFile.ActivePage:=TTabSheet(TabSheetSelectFile);
end;
SpBtnStart.Enabled:=CanStart;
memo.Lines.Clear;
ProgressBar.Position:=0;
end;
end;procedure TForm1.FormCreate(Sender: TObject);
begin
PageCutFile.ActivePageIndex:=0;
end;procedure TForm1.BtnNewClick(Sender: TObject);
var
NewFolder:string;
begin
//判断 DestDir.Directory 最右边一个字符是否是 '\'
//使用RightStr 需要引用单元 StrUtils
if RightStr(DestDir.Directory,1)='\' then
NewFolder:=DestDir.Directory+EdtNewDir.Text
else
//设置新文件夹路径
NewFolder:=DestDir.Directory+'\'+EdtNewDir.Text; MKDir(NewFolder);
DestDir.Directory:=NewFolder;
end;
procedure DelTree(Folder:string);
var
sr:TsearchRec; //调用FindFirst时所返回的文件信息,参见帮助
begin
if FindFirst(Folder+'\*.*',faAnyFile,sr)=0 then
begin
repeat if (sr.Attr and faDirectory)=faDirectory then
//判断所找到的文件是否是文件目录
begin
if ((sr.Name<>'.')and(sr.Name<>'..')) then
begin
//删除子文件夹
DelTree(Folder+'\'+sr.Name);
end;
end
else begin
//删除文件
DeleteFile(Folder+'\'+sr.Name);
end;
until FindNext(sr) <> 0;
end;
FindClose(sr);
ChDir('..');
//删除空目录
RmDir(Folder);
end;
procedure TForm1.BtnDeleteClick(Sender: TObject);
var
Folder:string;
opStruct:TSHFileOpStruct;
begin
Folder:=DestDir.Directory;
{if ChkBox.Checked then
begin
DestDir.Directory:=Folder+'..';
with opStruct do begin
Wnd:=0;
wFunc:=FO_DELETE;
pFrom:=PChar(Folder);
fFlags:=FOF_ALLOWUNDO;
end;
SHFileOperation(opStruct);
end
else} begin
if Application.MessageBox(PChar('要删除目录 '+Folder+' 吗?')
,PChar('确认信息'),Mb_YesNo)=ID_YES then
begin
DelTree(Folder);
DestDir.Directory:=Folder+'..';
end;
end;
end;procedure TForm1.DestDirDblClick(Sender: TObject);
begin
BtnDelete.Enabled:=True;
end;end.
效果一样的