Dzielenie plików
Adam Boduch
Tematem tego gotowca będzie dzielenie plików. Czasem może się to przydac,
gdy np. piszesz program, który chcesz na przykład podzielić na dyskietki.
Wtedy trzeba podzielić program na porcje 1,38 MB. W takim wypadku znajdzie
zastosowanie nienijszy gotowiec.
Na samym początku trzeba określić bufor, czyli kawałki, którymi będziemy
kopiować fragmenty pliku. Bufor taki może np. wynosić 500, czyli 500
bajtów. W takim wypadku plik podzielimy fragmentami - każdy po 500 bajtów.
Oczywiście można określić większy bufor. Ja w przykładowym programie
umieściłem komponent TTrackBar, dzięki któremu sam użytkownik może określić
bufor.
W samym programie wykorzystamy strumienie TFileStream. W celu większego
zapoznania się z tym tematem poczytaj artykuł w dziale Delphi. Samo
załadowanie pliku do strumienia wygląda tak:
Input := TFileStream.Create(FileName, fmOpenRead);
"FileName" to ściezka do pliku. Następnie trzeba określić ile potrzebnych
będzie iteracji pętli, która rozdzieli plik:
for I := 0 to (Input.Size div BuffSize) do
"BuffSize" to bufor, a Input.Size to wielkość pliku. A w pętli po "trochu"
następuje czytanie określonej porcji danych równych BuffSize. Dane te są
kopiowanie do innego strumienia:
for I := 0 to (Input.Size div BuffSize) do
begin
Application.ProcessMessages;
ProgressBar.Position := i;
{ za kazda iteracja petli - przesun sie w zawartosic pliku o rozmiarbufora }
Input.Seek(i * BuffSize, soFromBeginning);
{ utworz w nowo utworzonym folderze plik odpowiadajacy fragmentowidzielonego pliku }
Output := TFileStream.Create((DirPath + '\\' +ExtractFileName(FileName) + IntToStr(i) + '.temp'),
fmCreate);
try
{ nastepnie za pomoca funkcji CopyFrom ze strumienia zostajeprzekopiowana
okreslona ilosc bajtow (bufor) do strumienia Output. Jezelipozostala do
skopiowania czesc jest mniejsza od bufora to trzeba skopiowac tylkote
czesc, ktora pozostala do skopiowania... :))
}
if (Input.Size - (i * BuffSize)) < BuffSize then
Output.CopyFrom(Input, (Input.Size - (i * BuffSize)))
else Output.CopyFrom(Input, BuffSize);
finally
Output.Free;
end;
end;
W ten sposób zostaje tworzonych n plików, z których każdy plik ma rozmiar =
BuffSize.
Cała procedura do dzielenia plików wygląda tak:
procedure TMainForm.DivFile(const FileName: string);
var
Input : TFileStream;
Output : TFileStream;
i : Integer;
DirPath : string;
BuffSize : Integer;
begin
BuffSize := BufferTrack.Position; // pobierz rozmiar bufora ( rozmiarjednego pliku )
DirPath := FileName + '.temp'; // dodaj rozszerzenie
mkDir(DirPath); // utworz folder
Input := TFileStream.Create(FileName, fmOpenRead);
try
ProgressBar.Max := (Input.Size div BuffSize);
{ po podzieleniu rozmiaru pliku przez bufor daje to nam ilosc kawalkow zktorch
skladal sie bedzie podzielony plik }
for I := 0 to (Input.Size div BuffSize) do
begin
Application.ProcessMessages;
ProgressBar.Position := i;
{ za kazda iteracja petli - przesun sie w zawartosic pliku o rozmiarbufora }
Input.Seek(i * BuffSize, soFromBeginning);
{ utworz w nowo utworzonym folderze plik odpowiadajacy fragmentowidzielonego pliku }
Output := TFileStream.Create((DirPath + '\\' +ExtractFileName(FileName) + IntToStr(i) + '.temp'),
fmCreate);
try
{ nastepnie za pomoca funkcji CopyFrom ze strumienia zostajeprzekopiowana
okreslona ilosc bajtow (bufor) do strumienia Output. Jezelipozostala do
skopiowania czesc jest mniejsza od bufora to trzeba skopiowac tylkote
czesc, ktora pozostala do skopiowania... :))
}
if (Input.Size - (i * BuffSize)) < BuffSize then
Output.CopyFrom(Input, (Input.Size - (i * BuffSize)))
else Output.CopyFrom(Input, BuffSize);
finally
Output.Free;
end;
end;
finally
Input.Free;
end;
end;
Tak przedstawia się procedura dzielenia pliku na mniejsze. A co z
połączeniem tych plików ponownie w jedną całość? Tutaj sprawa jest bardzo
podobna. Z tym, że z jakiegoś danego katalogu następuje odczytanie
wszystkich znajdujących się tam plików. Następnie pętla for po wszystkich
tych plikach. A w pętli kolejno następuje odczytanie zawartości pliku i
dodanie do strumienia głównego (strumień główny to łączony plik).
procedure TMainForm.ConnectFile(const Dir: string);
var
SR : TSearchRec;
Found : Integer;
I : Integer;
Input : TFileStream;
Output : TfileStream;
NumberOfFiles : Integer;
begin
NumberOfFiles := 0;
{
te instrukcje maja na celu uzyskanie ilosci plikow .temp znajdujacychsie
w okreslonej lokalizacji - ilosc plikow oznacza zmienna NumberOfFile.
}
Found := FindFirst(Dir + '\\*.temp', faAnyFile, SR);
while Found = 0 do
begin
Inc(NumberOfFiles);
Found := FindNext(SR);
end;
FindClose(SR);
{
te instrukcje odpowiadaja za stworzenie pliku - to do niego zostaniewlaczona
zawartosci pliczkow - kwalkow...
}
if not FileExists(ExtractFileDir(Dir) +ChangeFileExt(ExtractFileName(Dir), '')) then
Output := TFileStream.Create(ExtractFileDir(Dir) +ChangeFileExt(ExtractFileName(Dir), ''), fmCreate)
else Output := TFileStream.Create(ExtractFileDir(Dir) +ChangeFileExt(ExtractFileName(Dir), ''), fmOpenWrite);
ProgressBar.Max := NumberOfFiles;
try
for I := 0 to NumberOfFiles -1 do
begin
Application.ProcessMessages;
ProgressBar.Position := i;
{ tutaj nastepuje otwarcie pliku-kawalka do skopiowania }
Input := TFileStream.Create(Dir + '\\' +ExtractFileName(ChangeFileExt(DirListBox.Directory, '')) + IntToStr(i) +'.temp',
fmOpenRead);
try
{ tutaj do pliku laczonego kopiujemy zawartosc malego pliczku(czesci) }
Output.CopyFrom(Input, Input.Size);
finally
Input.Free;
end;
end;
finally
Output.Free;
end;
end;
Najlepiej, abyś sam zobaczył ten program w działaniu. Źródła możesz
ściągnąć ze strony http://4programmers.net/file.php?id=387