Jak w temacie. Powiedzmy, ze mam kilka obrazków w JPG, dzwięków i siatek 3DS i chciałbym je zapisać w jednym pliku, a potem odczytać za pomocą strumieni. Jest na to jakiś sposób? [???]
oczywiście, że jest
Można to zrobić np. tak:
Zapisujesz do pliku tablicę np. array [0..25] of LongWord;
Element [0] będzie przechowywał informację o ilości plików znajdujących się w "bazie". Elementy [1..25] bedą przechowywały kolejne offstey położeń plików, po to aby móc je swobodnie wywoływać. Za tą tablicą dajesz już tylko pliki i po kłopocie.
// odczyt np. 19 pliku
AssignFile(F, '....');
Reset(F, 1);
Seek(F, Offsety[19]);
BlockRead(F, Bufor, Offsety[20]-Offsety[19]);
Mozna też użyć klasy TFileStram. Jak by co to pisz na gg. Nic nie stoi na przeszkodzie aby tablica info w pliku była rekordem, dodatkowo przechowującym nazwy plików.
zamiast kombinować jak koń pod górkę zainteresuj się strumieniami i poszukaj bo podawałem nawet dokładny kod jak zapisać i potem odczytać jpega i text chyba do jednego pliku
OLDFILE:=TFileStream.Create(sciezkapliku,fmOpenRead); //Plik źródłowy
NEWFILE :=TFileStream.Create(sciezkapliku2,fmOpenReadWrite); //Plik docelowy, musi istniec najlepiej stworzyc go gdzies wczesniej procedura rewrite, lub TFileStream.Create(sciezkapliku2,fmCreate);
NEWFILE.position:=NEWFILE.size
daneplikow.sposobdzielenia := 1024 //- tu musisz zapamietac ile bajtów pobierasz zeby potem przywrócic plik
daneplikow.rozmiarpliku:=OldFile.Size;
daneplikow.nazwapliku='Nazwa pliku'
// Proponuje daneplikow zapisac w jakims pliku rekordowym
daneplikow.liczbaoperacji:= (OldFile.Size div daneplikow.sposobdzielenia)
daneplikow.rozmiarosbuf:= (OldFile.Size mod daneplikow.sposobdzielenia)
for i:=1 to daneplikow.liczbaoperacji do
begin
SetLength(Buffer,daneplikow.sposobdzielenia);
oldfile.Read(Buffer[0],daneplikow.sposobdzielenia);
newfile.Write(Buffer[0] ,daneplikow.sposobdzielenia);
end;
oldfile.Read(Buffer[0],daneplikow.rozmiarosbuf);
newfile.Write(Buffer[0],daneplikow.rozmiarosbuf);
FreeAndNil(NewFile);
FreeAndNil(OldFile);
write(Plikzdanymi,daneplikow);
I po krzyku analogicznie robisz wyodrebniacza :)
Sorki za późną odpowiedź, ale mialem troche szkoły.
Misiekd napisał(a)
(...) poszukaj bo podawałem nawet dokładny kod jak zapisać i potem odczytać jpega i text chyba do jednego pliku
Gdybym to znalazł to nie było by tematu [glowa]
A wracając do tematu, to napisałem takie dwa programiki:
- Zapisywanie do jednego pliku: (podam tylko procedure, która zbiera pliki z listbox'a i zapisuje do pliku o nazwie w Edit1.Text):
procedure TForm1.Button3Click(Sender: TObject);
const
sposobdzielenia = 1024;
var
wynik: TFileStream;
inne: array of TFileStream;
licznik, l2: integer;
temp1: integer;
temp2: int64;
s: ShortString;
buffer: array of Char;
dl, ilosc: integer;
begin
if (ListBox1.Items.Count = 0) then
raise Exception.Create('Nie wybrano plików');
wynik := TFileStream.Create(edit1.Text, fmCreate);
SetLength(inne, ListBox1.Items.Count);
temp1 := ListBox1.Items.Count;
wynik.Write(temp1, SizeOf(temp1));
for licznik := 0 to ListBox1.Items.Count - 1 do
begin
inne[licznik] := TFileStream.Create(ListBox1.Items.Strings[licznik], fmOpenRead);
temp2 := inne[licznik].Size;
wynik.Write(temp2, SizeOf(temp2));
s := ExtractFileName(ListBox1.Items.Strings[licznik]);
wynik.Write(s, SizeOf(s));
end;
for licznik := 0 to ListBox1.Items.Count - 1 do
begin
ilosc := inne[licznik].Size div sposobdzielenia;
dl := inne[licznik].Size mod sposobdzielenia;
for l2 := 0 to ilosc do
begin
SetLength(buffer, sposobdzielenia);
inne[licznik].Read(buffer[0], sposobdzielenia);
wynik.Write(buffer[0], sposobdzielenia);
end;
inne[licznik].Read(buffer[0], dl);
wynik.Write(buffer[0], dl);
inne[licznik].Free;
end;
wynik.Free;
end;
- Wyodrębniacz:
procedure TForm1.Button1Click(Sender: TObject);
const
sposobdzielenia = 1024;
var
strumien: TFileStream;
licznik, ile, l2: integer;
rozmiary: array of int64;
nazwy: array of Shortstring;
pliki: array of TFileStream;
ilosc, dl: integer;
buffor: array of char;
begin
if not (FileExists(edit1.Text)) then
raise Exception.Create('Nieodnaleziono pliku!');
strumien := TFileStream.Create(Edit1.Text, fmOpenRead);
strumien.Read(ile, SizeOf(ile));
SetLength(rozmiary, ile);
SetLength(nazwy, ile);
for licznik := 0 to ile - 1 do
begin
strumien.Read(rozmiary[licznik], SizeOf(rozmiary[licznik]));
strumien.Read(nazwy[licznik], SizeOf(nazwy[licznik]));
ListBox1.Items.Add(nazwy[licznik]);
end;
SetLength(pliki, ile);
for licznik := 0 to ile - 1 do
begin
pliki[licznik] := TFileStream.Create(Edit2.Text + nazwy[licznik], fmCreate);
dl := (rozmiary[licznik] mod sposobdzielenia);
ilosc := (rozmiary[licznik] div sposobdzielenia);
if (ilosc > 0) then
for l2 := 1 to ilosc do
begin
SetLength(buffor, sposobdzielenia);
strumien.Read(buffor[0], sposobdzielenia);
pliki[licznik].Write(buffor[0], sposobdzielenia);
end;
strumien.Read(buffor[0], dl);
pliki[licznik].Write(buffor[0], dl);
pliki[licznik].Free;
end;
strumien.Free;
nazwy := nil;
rozmiary := nil;
ShellExecute(application.Handle, 'open', PChar(Edit2.Text), nil, nil, SW_SHOWNORMAL);
end;
I jest jeden problem, a mianowicie po "wypakowaniu" plików tylko pierwszy jest zapisany prawidłowo, a kolejne już nie. Ich rozmiary są dokładnie takie same jak u źródeł. Ma kto jakiś pomysł?
POKASUJ SWOJE DUPLIKATY!!
zapis
var
InS, OutS: TFileStream;
i, Len: Integer;
FName: string;
begin
OutS := TFileStream.Create('Out name', fmCreate); //stworzenie wyjściowego
try
for i := 0 to ListBox1.Items.Count - 1 do
begin
InS := TFileStream.Create(ListBox1.Items.Strings[licznik], fmOpenRead); //odczytanie pliku
try
FName := ExtractFileName(ListBox1.Items.Strings[licznik]); //pobranie nazwy pliku
Len := Length(FName); //pobranie długości nazwy
OutS.Write(Len, SizeOf(Len)); //zapisanie długości nazwy
OutS.Write(Pointer(FName)^, Len); //zapisanie nazwy
OutS.Write(InS.Size, SizeOf(InS.Size)); //zapisanie długości pliku
OutS.CopyFrom(InS, 0); //zapisanie pojedyńczego pliku do "archiwum"
finally
FreeAndNil(InS);
end;
end;
finally
FreeAndNil(OutS);
end;
end;
odczyt
var
InS, OutS: TFileStream;
Len: Integer;
Size: Int64;
FName: string;
begin
InS := TFileStream.Create('In name', fmOpenRead); //otwarcie "spakowanego" pliku
try
while InS.Position < InS.Size do
begin
InS.Read(Len, SizeOf(Len); //odczytanie długości nazwy
SetString(FName, nil, Len); //przygotowanie bufora do odczytania nazwy
InS.Read(Pointer(FName)^, Len); //odczytanie nazwy
InS.Read(Size, SizeOf(Size); //odczytanie wielkości pliku
OutS := TFileStream.Create(FName, fmCreate); //stworzenie pliku
try
OutS.CopyFrom(InS, Size); //przekopiowanie pojedyńczego pliku
finally
FreeAndNil(OutS);
end;
end;
finally
FreeAndNil(InS);
end;
end;
pisane z palca, ale na 99,9% będzie działać
dodatkowo przy użyciu ZLibEx możesz pakować "w locie" dodawane pliki i rozpokowywać je przy wyodrębnianiu. ZLibEx działa na strumieniach więc nie powinno być problemów
Kilka poprawek i działa. Wielkie dzięki za wszystkie odpowiedzi. [browar]