Kilka plików w jednym pliku

0

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? [???]

0

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.

0

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

0

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 :)

0

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:

  1. 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;
  1. 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ł?

0

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

0

Kilka poprawek i działa. Wielkie dzięki za wszystkie odpowiedzi. [browar]

1 użytkowników online, w tym zalogowanych: 0, gości: 1