Title: File Splitter
Question: Split and join large files
Answer:
Many of us experience this incontrovertible need to slice large files
into smaller pieces - the foll piece of code helps do just that - you
can split large files into smaller pieces,(port/upload them..) and
re-join them later.
The crux of the file-splitter is the function, PERFORMSPLIT :
procedure PerformSplit(const srcFn , dstDir: String; numSlices : Integer);
var
dstFl ,batCmd, tmpFn : String;
srcFStrm : TFileStream;
strmSize , destFlSize , modRes : LongInt;
cntSlice : Integer;
accom : boolean;
begin {0}
{
srcFn - File to split
dstDir - directory that 'll hold the file slices and the .BAT file that
joins them
numSlices - number of slices
}
accom := false;
{the flag above ('accom') is used when the source file cannot be
accomodated wholly in the no. of slices specified, i.e., if the last
piece needs to contain lesser data - we could have done without this
flag, computing the space size of each slice on the fly, but this makes
the code look just a little easier
}
srcFStrm := TFileStream.create(srcFn,fmOpenRead);
strmSize := srcFStrm.size;
destFlsize := strmSize div numSlices;
modRes := strmsize mod numSlices;
if (modRes) 0 then {1}
begin
dec(numSlices);
accom := true;
end; {1}
srcFStrm.position := 0;
try {2}
cntslice := 1;
tmpFn := extractfilename(changefileext(srcFn,''));
Application.ProcessMessages;
while cntslice begin {3}
dstFl := tmpFn+'_$_'+inttostr(cntslice);
{batCmd - contains the DOS 'Copy' command that 'll be executed by the
.bat file to join the file slices}
batCmd := batCmd + dstFl + '+';
dstFl := IncludeTrailingPathDelimiter(dstDir)+dstFl;
strmcopy(dstFl,srcFStrm,destFlSize);
inc(cntslice);
end; {3}
if accom then // 1 slice left
begin {4}
inc(destFlSize,modRes);
dstFl := tmpFn+'_$_'+inttostr(cntslice);
batCmd := batCmd + dstFl +'+';
dstFl := IncludeTrailingPathDelimiter(dstDir)+dstFl;
strmcopy(dstFl,srcFStrm,destFlSize);
end; {4}
setLength(batCmd,length(batCmd)-1);
batCmd := 'COPY /B '+ batCmd + ' '+extractfilename(srcFn);
generateBatFile(dstDir,extractfilename(changefileext(srcFn,''))+'_$_.bat', batCmd);
finally
srcFStrm.free;
end; {2}
end; {0}
{the foll proc saves the slices to the destination directory }
procedure StrmCopy(const destFl : String;const srcFStrm :
TFileStream;destFlSize : longInt);
var
dstFStrm : TFileStream;
begin
dstFStrm := TFileStream.create(destfl,fmCreate);
try
dstFstrm.CopyFrom(srcFStrm,destFlSize);
finally
dstFStrm.free;
end;
end;
{the foll proc creates a DOS-Batch(.bat) file that re-joins the file
slices to obtain the original file, provided the file slices and the
.bat file are in the same folder}
procedure generateBatFile(const dstDir , batName, batCmd : String);
var
batFl : TextFile;
dstBAT : String;
begin
dstBAT := IncludeTrailingPathDelimiter(dstDir)+batName;
assignfile(batFl,dstBAT);
rewrite(batFl);
writeln(batFl,'rem Auth : Prashant Gulati');
writeln(batFl,batCmd);
closefile(batFl);
end;
Note :
1) The above program,in its present form,would not be able to
regenerate the source files that have spaces in their names.
Nonetheless, an easy work-around is not a problem
2) When executing the batch file make sure that the file slices and the
.bat are in the same directory
3) If you find execution using .bat files slow, you could write a small
module that would regenerate the file using the same approach (file
streams) as discussed above
Please rate this article if you liked it :)
Affly
Prashant Gulati