Autor Wątek: Własny format plików  (Przeczytany 7415 razy)

Offline kombain

  • Użytkownik

# Marzec 03, 2008, 11:14:27
Witam. Chciałbym stworzyć coś na kształt własnego formatu plików, coś jak format MPQ Blizzarda. W jednym pliku mogą być przechowywane różne dane jak bitmapy, filmy itp. (archiwum). Myślałem o zastosowaniu jakiejś biblioteki zip'o-podobnej, ale czy jest to w miarę szybkie rozwiązanie? Może są już jakieś gotowe sposoby implementacji takich rzeczy? Możecie coś polecić?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

RageX

  • Gość
# Marzec 03, 2008, 11:21:33
zlib :). Tak jak to od dawien dawna robi chociazby id software. Wszystkie dane pakuja do plikow *.pk3, tyle tak naprawde sa zwyklymi zip'ami rozpakowywanymi w trakcie pracy gry

Offline Khaine

  • Użytkownik

# Marzec 03, 2008, 22:01:09
a jak zlibem rozpakowac plik i wyciagnac n-ty plik? Troszke korzystalem z zliba i tam jest funkcja rozpakowujaca archiwum, ale do bufora, wiec jesli mamy plik 2gb danych to zeby wyciagnac jedna texture z niego musimy stworzyc bufor 2gb w pamieci?!?!? :o Domyslam sie, ze jest inny sposob. Jaki?

Offline Elwis

  • Użytkownik

# Marzec 03, 2008, 22:16:21
Trochę dziwnie. Jak dla mnie projektowanie własnych typów plików to najprzyjemniejsza robota :)

Offline Ventor

  • Użytkownik

# Marzec 03, 2008, 22:24:41
a jak zlibem rozpakowac plik i wyciagnac n-ty plik? Troszke korzystalem z zliba i tam jest funkcja rozpakowujaca archiwum, ale do bufora, wiec jesli mamy plik 2gb danych to zeby wyciagnac jedna texture z niego musimy stworzyc bufor 2gb w pamieci?!?!? :o Domyslam sie, ze jest inny sposob. Jaki?
Ja korzystam ze zliba i robię to w ten sposób że plik składa się z nagłówków i danych spakowanych zlibem, np każda tekstura ma swój nagłówek opisujący ją, m.in. offset do danych. Nie ma wtedy problemu o którym piszesz, bo z nagłówków wiem gdzie są dane i odczytuję to co potrzebne i rozpakowuję.

Trochę dziwnie. Jak dla mnie projektowanie własnych typów plików to najprzyjemniejsza robota :)
Mój sposób należy do przyjemnych, bo format jest wymyślony przeze mnie, tylko same dane kompresuję.

Offline Khaine

  • Użytkownik

# Marzec 04, 2008, 00:50:18
Cytuj
Ja korzystam ze zliba i robię to w ten sposób że plik składa się z nagłówków i danych spakowanych zlibem, np każda tekstura ma swój nagłówek opisujący ją, m.in. offset do danych. Nie ma wtedy problemu o którym piszesz, bo z nagłówków wiem gdzie są dane i odczytuję to co potrzebne i rozpakowuję.
Ja robie podobnie, tylko ze kazdy plik w tym archiwum mam osobno spakowany. A Ty masz to archiwum spakowane? Bo jesli tak to jak wyciagasz tylko konkretny plik nie rozpakowujac calosci?

RageX

  • Gość
# Marzec 04, 2008, 01:31:58
Nie używałem zliba... ale pewnie coś w stylu ReadCosTam(uint offset, uint count) ze stream'u.
Otwierasz stream wskazujesz offset od którego zacząć czytanie, gdzie ma skończyć, rozpakowujesz i gotowe.
Tak przypuszczam tylko, oczywiście.

Offline Ventor

  • Użytkownik

# Marzec 04, 2008, 07:41:37
Cytuj
Ja korzystam ze zliba i robię to w ten sposób że plik składa się z nagłówków i danych spakowanych zlibem, np każda tekstura ma swój nagłówek opisujący ją, m.in. offset do danych. Nie ma wtedy problemu o którym piszesz, bo z nagłówków wiem gdzie są dane i odczytuję to co potrzebne i rozpakowuję.
Ja robie podobnie, tylko ze kazdy plik w tym archiwum mam osobno spakowany. A Ty masz to archiwum spakowane? Bo jesli tak to jak wyciagasz tylko konkretny plik nie rozpakowujac calosci?
Może nieprecyzyjnie się wyraziłem, ale robię dokładnie tak jak Ty. Na początku pliku jest nagłówek zawierający m.in. typy i offsety do wszystkich zasobów (nie używam nazw plików, ale gdybym używał to tu też bym je zapisał). Każdy zasób opisany jest swoim 16 bajtowym nagłówkiem zawierającym rozmiar spakowany, rozpakowany, flagi i sumę kontrolną, a bezpośrednio za tym nagłówkiem są dane (we wcześniejszej wersji był jeszcze offset do danych, ale zrezygnowałem z tego). Flagi określają czy dane są spakowane, zaszyfrowane i czy sprawdzać sumę kontrolną.

Chcąc dostać się np do konkretnej tekstury odczytuję offset z pierwszego nagłówka, później odczytuję ten drugi 16 bajtowy nagłówek i dane. Zależnie od flag sprawdzam sumę kontrolną, odszyfrowuję i rozpakowuję.

Offline Khaine

  • Użytkownik

# Marzec 04, 2008, 10:45:14
aha, no ja mam bardzo podobnie, tylko ze dodatkowo przechowuje nazwy plikow, zeby mozna bylo zrobic loadFile("plik", archiwum);
Ale nie wydaje mi sie, zeby takie podejscie bylo jakos szczegolnie wydajne. Zauwazmy, ze zeby zaladowac kazdy plik musimy go najpierw rozpakowac, co jest mniej (czytalem, ze dosc szybko) lub bardziej czasochlonne. Jesli bysmy mieli tylko raz rozpakowac plik byloby szybciej.

Offline Ventor

  • Użytkownik

# Marzec 04, 2008, 12:10:10
Odczytywanie skompresowanych danych i dekompresja w locie często jest szybsza od odczytywania zdekompresowanych danych. Zdekompresowane więcej zajmują a jak wiadomo odcztywanie z dysku za szybkie nie jest. Co do zależności prędkości dekompresji od długości pliku to chyba jest dosyć liniowa - 10 plików po 1MB rozpakuje się praktycznie w takim samym czasie co jeden 10MB.

Ja uważam, że jest to dobry sposób, a na pewno lepszy od wrzucania wszystkiego do jednego wora i kompresowania. Nie zawsze potrzebne jest wszystko z pliku, więc nie warto całego dekompresować, a wyszukiwanie offsetu w skompresowanych danych (o ile w ogóle zlib ma taką możliwość) na pewno będzie wolniejsze.

Offline Khaine

  • Użytkownik

# Marzec 04, 2008, 20:13:08
no racja, rozsadny argument. Moglem wczesniej w ten sam sposob pomyslec ;)

Offline spax

  • Użytkownik

# Marzec 04, 2008, 21:02:03
Można by też wszystkie 'nagłówki' plików wpakować na sam początek. Przyspieszyło by to nam wyliczanie plików (wszystkie nagłówki za jednym odczytem). A potem mając taką listę tych  nagłówków (+ informacja z jakiej paczki pochodzi dany nagłówek) można łatwo podmieniać dodawać nowe, po prostu dodając nową paczkę do katalogu z grą (łatwość aktualizacji gry).

http://www.spax.top100.net.pl/wp_blog/index.php/2007/09/22/jak-mozna-zbudowac-vfs/

Offline kombain

  • Użytkownik

# Marzec 04, 2008, 22:54:04
Serdeczne dzięki za wszystkie (p)odpowiedzi, szczególnie spaxowi za linka :D Ciekaw jestem, jak to będzie się zachowywało w praktyce. System ten ma być zaimplementowany nie w grze lecz w aplikacji, która wyświetla na quadach obrazy z plików bmp, jpg itp. jak i również z filmów, które użytkownik sam sobie wybiera. Dodatkowo może sobie dodać ruchomy tekst i zapisać taką prezentację do osobnego pliku, w którym powinny znaleźć się użyte jako tekstury bitmapy i filmy. Ma to pozwolić na przenoszenie takiego pliku do innego komputera z tą samą aplikacją i umożliwić odtworzenie prezentacji. Z tym, że odczyt i zapis z/do takiej paczki musi być tak szybki jak skopiowanie analogicznych danych do katalogu.
Niestety w takim przypadku tworzenie kilku plików/paczek jest niemożliwe :/ Spróbuje z jednym. Mam tylko pytanie, może trochę noobowate: jak do takiej paczki stworzonej np zlibem dodać nagłówek i całą resztę? Serializować jakiś związany z tymi danymi obiekt i dodać do archiwum jako plik o zawsze tej samej nazwie i na początku odczytu tylko ten plik wyodrębniać i deserializować?

//Edit:
Najciemniej zawsze pod latarnią. Zacznę od tego a później zobaczymy:
http://www.warsztat.gd/articles.php?x=view&id=6
« Ostatnia zmiana: Marzec 04, 2008, 23:12:46 wysłana przez kombain »

Offline Ventor

  • Użytkownik

# Marzec 04, 2008, 23:06:01
Można by też wszystkie 'nagłówki' plików wpakować na sam początek. Przyspieszyło by to nam wyliczanie plików (wszystkie nagłówki za jednym odczytem). A potem mając taką listę tych  nagłówków (+ informacja z jakiej paczki pochodzi dany nagłówek) można łatwo podmieniać dodawać nowe, po prostu dodając nową paczkę do katalogu z grą (łatwość aktualizacji gry).

http://www.spax.top100.net.pl/wp_blog/index.php/2007/09/22/jak-mozna-zbudowac-vfs/
Można i wcześniejsza wersja mojego formatu miała taką możliwość bo każdy nagłówek miał offset do danych. Teraz dane mam bezpośrednio za nagłówkiem, dlatego, ze mogę w ten sposób łatwo wyciągnąć z całago archiwum i zapisać pojedyncze pliki w formacie 16 bajtowy nagłówek + dane. Rozszerzenie takiego pliku to skrót określający typ danch np tekstura, siatka itp.

Dane w takich pojedynczych plikach i tak nie są bezpośrednio wyciągane np z jpg-ów tylko mają mój format, więc w efekcie każdy zasób ma swój własny format, rozszerzenie i może kiedyś ikonkę ;) Nie ma dzięki temu problemów wynikających z ograniczeń poszczególnych formatów typu bmp czy 3ds, takimi sprawami zajmują się konwertery, a sam silnik dostaje praktycznie 100% pewne dane potwierdzone sumą kontrolną CRC32, więc nie musi już nic kontrolować, liczyć czy konwertować, od razu działa.
« Ostatnia zmiana: Marzec 04, 2008, 23:07:57 wysłana przez Ventor »

Offline Khaine

  • Użytkownik

# Marzec 05, 2008, 02:12:41
zastanawiam sie czy sumy kontrolne sa jakos szczegolnie potrzebne. Zle pliki to blad usera i niech on sie tym martwi, a aplikacja niech oszczedzi na czasie.

Zastanawiam sie jeszcze nad taka opcja. Pliki nie sa skompresowane. Wiem, tracimy duzo miejsca (np. w oblivionie ok 1gb na modelach), ale jesli ktos sprytnie sobie ulozy dane to np. wczytujac level jednym wywolaniem funkcji (np. fread) odczytuje od razu wszystkie dane (np. textury) do jednego bufora. Mamy wtedy jeden spojny blok pamieci z texturami. Potem juz tylko robimy sobie wskazniki i offset na tym bloku i powinno byc cacy. Taki jeden odczyt bedzie szybszy w porownaniu z odczytem i dekompresja n mniejszych plikow, tworzeniem z nich zasobow etc. No i nie mamy fragmentacji. Co Wy na to?