OSZCZĖDZANIE MIEJSCA NA DYSKIETKACH

<lead>W artykule tym chciaībym opisaź, w jaki sposób moūna
zaoszczėdziź nieco miejsca na dyskietkach, a przy okazji
zwiėkszyź szybkoōź operacji na plikach. Adresowany jest on
gīównie do tych osób, które piszā programy korzystajāce z wielu
plików, np. magazyny dyskowe, sīowniki itd.

<a>Īukasz Szelāg

<txt>Zanim opiszė samā metodė, posīuūė siė przykīadem wziėtym z
ūycia. Pisaīem kiedyō program, który przechowywaī swoje dane w
wielu zewnėtrznych plikach. Plików tych byīo w sumie 527 o
īācznej wielkoōci okoīo 200 KB. Po sformatowaniu dysku (pojemnoōź
okoīo 880 KB), skopiowaīem pliki i zauwaūyīem, ūe na dysku
pozostaīo zaledwie 288 KB wolnego miejsca. Jak to moūliwe? Gdzie
siė podziaīo brakujācych 400 KB? Okazuje siė, ūe kaūdy plik
oprócz danych zawiera jeszcze wiele innych informacji --
atrybuty, wielkoōź itd. Poza tym system operacyjny musi gdzieō na
dysku zapamiėtaź nazwy poszczególnych plików oraz ich poīoūenia.
Jeūeli plików jest maīo, to nie jest to aū tak istotne, jednak
jeōli jest ich duūo, o niewielkich wielkoōciach tak jak w
powyūszym przykīadzie, ma to kluczowe znaczenie w
zagospodarowaniu miejsca na dysku.

Rozwiāzaniem opisanego problemu moūe byź poīāczenie wszystkich
krótkich plików w jeden i zapamiėtanie w osobnym pliku nazw,
dīugoōci i offsetów poīāczonych plików. Daje to jeszcze jednā
dodatkowā korzyōź -- kopiowanie danych, np. instalacja programu
na twardym dysku, jest nieporównywalnie krótsze. Kopiowanie
kilkuset plików trwa bardzo dīugo, czėsto ponad 10 minut.

Po tym wstėpie mogė przedstawiź program, który realizuje opisanā
powyūej operacjė. Zostaī on napisany za pomocā kompilatora SAS/C
i wykorzystuje niektóre jego cechy, takie jak np. automatyczne
otwarcie biblioteki dos.library. Jeōli Twój kompilator jej nie
otwiera, musisz to zrobiź samodzielnie. Z uwagi na to, ūe program
wykorzystuje funkcjė FPrintf(), moūna go uruchomiź tylko pod
Kickstartem V36 i wyūszym. Zresztā jest to tylko przykīad i ma na
celu jedynie zilustrowanie idei postėpowania. Kaūdy
zainteresowany moūe na jego podstawie napisaź wīasny program.

Program powinien zostaź uruchomiony z CLI i wymaga podania
katalogu, w którym znajdujā siė pliki do poīāczenia, nazwa pliku
docelowego, nazwa pliku indeksu (do którego zostanā zapisane
informacje o nazwach, dīugoōciach i offsetach poīāczonych plików)
oraz (opcjonalnie) wielkoōź bufora I/O w bajtach, np.:

<l>indexer "Work:data" "T:poīāczone_pliki" "T:index" 100000

<txt>Plik indeksu jest zwykīym plikiem tekstowym. Informacja o
kaūdym pliku jest zapisywana w trzech kolejnych jego liniach,
tzn. nazwa, dīugoōź i offset.

Naleūy oczywiōcie napisaź program, który wykona czynnoōź odwrotnā
do powyūszej, tzn. odczyta wybrany plik z pliku zawierajācego
poīāczone pliki. Nie bėdė przytaczaī tutaj caīego programu, podam
tylko parė wskazówek. Po otwarciu pliku zawierajācego poīāczone
pliki naleūy przestawiź wskaśnik czytania z pliku na pozycjė
pliku, który chcemy odczytaź, np.:

<l>	if (file = Open("poīāczone pliki", MODE_OLDFILE))

	{

		Seek(file, offset, OFFSET_BEGINNING)

	...

<txt>Nastėpnie moūna skopiowaź dane do tworzonego pliku za pomocā
funkcji Read() i Write(). Oczywiōcie procedura powinna przedtem
odczytaź z pliku indeksu dīugoōź i offset dla danego pliku.

I to juū wīaōciwie wszystko. Podajė jeszcze informacjė, ūe
powyūszy program znajduje siė w sieci Aminet, katalog dev/misc.
Jeūeli ktoō ma jakieō dodatkowe pytania, moūe siė ze mnā
skontaktowaź za poōrednictwem poczty elektronicznej pod adresem
luk@i17linux.ists.pwr.wroc.pl lub na IRC -- kanaī #amigapl
(Luk).


<l>

/*

** $VER: indexer.c 1.0 (5.11.95)

** Program īaczy wszystkie pliki z podanego katalogu,

** zapisuje je kolejno do wskazanego pliku oraz

** tworzy plik indeksu, w którym zostanā umieszczone

** informacje o nazwach, dīugoōciach i poīoūeniach

** poīāczonych plików.

*/



#include <proto/exec.h>

#include <exec/memory.h>

#include <proto/dos.h>

#include <stdio.h>

#include <stdlib.h>



void main(int argc, char *argv[])

{

  struct FileInfoBlock finfo;   /* opis otwieranego pliku */

  BPTR lock, oldlock;

  BPTR exfile, outfile, index;  /* otwierane pliki */

  UBYTE *buffer;                /* bufor roboczy */

  ULONG buffsize = 50000;       /* wielkoōź bufora */

  ULONG outsize;                /* dīugoōź tworzonego pliku */

  LONG buffread;                /* liczba bajtów wczytywanych do bufora */

  UBYTE i;



  /* minimalna wersja systemu operacyjnego */

  extern LONG __OSlibversion = 36;



  /* tekst informacji o programie */

  static UBYTE *info[] =

  {

     "indexer v1.0 (c)1995 by Lukasz Szelag.",

     "This  program  was  developed with SAS/C compiler on Amiga 1200 and",

     "helps  developers  who  have  to write routines which manage lot of",

     "files (for example for disk magazines writers). It allows to reduce",

     "the  disk  space  and increase the speed of disk operations. If you",

     "have any ideas, bug reports or if you want the complete source code",

     "of this tiny program just feel free to contact with me:\n",

     "  e-mail: lszelag@panamint.ict.pwr.wroc.pl",

     "     www: sun1000.ci.pwr.wroc.pl/amiga/amiuser/luk",

     "     IRC: #amiga, #amigapl, #usa (Luk)\n"

  };



  /* tekst pomocy */

  static UBYTE *help[]=

  {

     "Usage: indexer <dir> <outfile> <index> [buffer]",

     "dir     - directory with files to process",

     "outfile - filename for final file",

     "index   - filename for data description",

     "buffer  - I/O buffer (default 50000 bytes)\n\n",

  };



  /* wyōwietlenie informacji o programie */

  for (i = 0; i<10; i++) printf("\n%s", info[i]);



  /*

  Sprawdzenie  poprawnoōci  skīadni wywoīania programu. Jeūeli jest bīėdna,

  to wyōwietlenie pomocy.

  */

  if ((argc<4) || (argc>5))

  {

    for (i = 0; i<5; i++) printf("\n%s", help[i]);

    exit(RETURN_FAIL);

  }



  /* przydzielenie pamiėci na bufor I/O */

  if (argc>4) buffsize = atol(argv[4]);

  if (buffer = AllocMem(buffsize, MEMF_PUBLIC))

  {

    /* otwarcie pliku, w którym zostanā umieszczone odczytane pliki */

    if (outfile = Open(argv[2], MODE_NEWFILE))

    {

      /* otwarcie pliku, w którym zostanie umieszczony indeks plików */

      if (index = Open(argv[3], MODE_NEWFILE))

      {

        /* lock do wybranego katalogu */

        if (lock = Lock(argv[1], ACCESS_READ))

        {

          /* wejōcie do katalogu */

          oldlock = CurrentDir(lock);



          /* sprawdzenie kolejnych plików z katalogu */

          if (Examine(lock, &finfo))

          {

            do

            {

              /* sprawdzenie, czy jest to plik */

              if (finfo.fib_DirEntryType<0)

              {

                /* otwarcie pliku */

                if (exfile = Open(finfo.fib_FileName, MODE_OLDFILE))

                {

                  /*

                  Skopiowanie   danego   pliku   poprzez  bufor  na  koniec

                  tworzonego pliku.

                  */

                  outsize = 0;

                  printf("\n%s", finfo.fib_FileName);

                  do

                  {

                    buffread = Read(exfile, buffer, buffsize);

                    Write(outfile, buffer, buffread);

                    outsize += buffread;

                  }

                  while (outsize<finfo.fib_Size);

                  Close(exfile);



                  /*

                  Dopisanie  do  pliku  indeksu,  nazwy skopiowanego pliku,

                  jego  dīugoōci oraz poīoūenia (offsetu) wzglėdem poczātku

                  tworzonego pliku.

                  */

                  FPrintf(index, "%s\n%ld\n%ld\n",

                          finfo.fib_FileName,

                          finfo.fib_Size,

                          Seek(outfile, 0, OFFSET_CURRENT)-finfo.fib_Size);

                }

              }

            }

            while (ExNext(lock, &finfo));

          }

          /* odtworzenie bieūācego katalogu i zwolnienie locka */

          CurrentDir(oldlock);

          UnLock(lock);

        }

        else

        {

          printf("\nCouldn't lock directory !\n\n");

          Close(index);

          Close(outfile);

          FreeMem(buffer, buffsize);

          exit(RETURN_FAIL);

        }

        Close(index);

      }

      else

      {

        printf("\nCouldn't open file %s !\n\n", argv[3]);

        Close(outfile);

        FreeMem(buffer, buffsize);

        exit(RETURN_FAIL);

      }

      Close(outfile);

    }

    else

    {

      printf("\nCouldn't open file %s !\n\n", argv[2]);

      FreeMem(buffer, buffsize);

      exit(RETURN_FAIL);

    }

    FreeMem(buffer, buffsize);

  }

  else

  {

    printf("\nNot enough memory for I/O buffer !\n\n");

    exit(RETURN_FAIL);

  }

  printf("\n\nOperation finished.\n\n");

  exit(RETURN_OK);

}
