Failu Arhivēšana (2000)




Autors: V. Tolmačevs

 
Lietotājam ir nepieciešamība pārnest failus no viena datora uz otru. Daudziem lietotājam nav datoru tiklu, kurā jūs varat kopēt failus, tad rasties nepieciešamība nokopēt failu uz disketi, bet faila izmērs varbūt lielāks par disketes ietilpību. Varbūt arī gadījums, kad lietotājam ir nepieciešams palielināt cieta diska brīvu vietu bez datu zaudējumiem. Šajos gadījumos es rekomendē izmantot programmas - arhivatorus (t.i. programmas, kuri ļauj samazināt failu izmērus bez datu zaudējumus).
Eksistē dažādas programmas - arhivatori, viņi strādā dažādās operātājsistēmās, piemēram Windows, Unix, MS-DOS. Es gribēju izstrādāt programmu - arhivatoru, kura strādā MS-DOS vidē, bet kurā jābūt labākam interfeisam neka 'Arj' vai 'Zip' arhivatoriem. Piemēram 'Arj' neizmanto krasus savā interfeisā un nevar strādāt bez komandas no komandas rinda. Manai programmai jāatbalsta komandas no komandas rinda, ka piemēram 'Arj', 'Zip' un jāatbalsta man vajadzīgu interfeisu, ka arī programmai ir jāstrādā bez komandas no komandas rinda.

1.    TEORETISKĀ DAĻA


1.1.                        Problēmu apraksts


Daudzie lietotāji doma, kā samazināt faila izmērus, lai nokopēt to uz disketi vai palielināt cieta diska brīvu vietu bez datu zaudējumiem. Šī programma var samazināt faila izmērus (nokodēt) un kad ir nepieciešams, programma var atjaunot kodēta faila saturu (būs fails, ka pirms kodēšanai). Ja faila izmērs ir ļoti mazs un viņš sastāv no dažādiem simboliem, tad var iznākt, ka kodēta faila izmērs ir lielāks pār sākotnēja faila izmēru. Šajā situācijā es nerekomendē izmantot manu programmu ‘Arhivator’, tāpēc kā šeit viņa nepalīdzes jums.
Programma paredzēta faila izmēru samazināšanai (arhivēšanai) un faila atjaunošanai bez datu zaudējumu.

1.2.                        Metodes apraksts


Īsi apskatīsim arhivēšanas metodes, kuriem ir pietekami ilga vēsture. Vairāk informācijas jūs varat atrast grāmatās [3] [5].
Eksistē dažādas pieejas šī problēmai. Apskatīsim "neveiksmīgu" pieeju šī problēmai, tas RLE (Run Length Encoding) metode, viņš kode sērijas garumu. Šī metode aizvieto atkārtojamas simbolu virknes uz vienu simbolu un to atkārtojumu skaitu. Problēma ir sekojoša, atjaunošanas (uncoding) gaitā mums ir nepieciešams atšķirt kodētu sēriju no citiem simboliem. Risinājums ir sekojošs, pievienot šīm simbolu virknēm kaut kādu virsrakstu, piemēram izmantot pirmo bitu, kā kodētas virknes pazīme. Metode ir pietekami efektīva priekš grafisku attēlu formātā baits uz punktu (byte on pixel), piemēram formāts PCX izmanto kodēšanu RLE. Metodes trūkums ir zema samazināšanas pakāpe, piemēram tekstā bez divburtu vārdiem viņš var nokodēt tikai tukšas simbolu zīmes rindas sākumā.
LZW (Lempel Ziv Welch) metode vēsture sākas maijā 1977. gadā no raksta "IEEE Trans" publikācijas žurnālā "Информационные теории", raksta autori bija Dž. Zivs (J. Ziv) un A. Lempels (A. Lempel). Pēc tām šo algoritmu uzlaboja Terri A. Velčems (Terry A. Welch) un pēdējā variantā šis algoritms bija atspoguļots rakstā "IEEE Computer" jūnijā 1984. gadā. Šī rakstā bija aprakstīti algoritma detaļas un dažādas realizācijas problēmas. Šis algoritms kode secīgus dažādus simbolus. Šis algoritms kodēšanas laikā "mācās". Algoritma priekšrocība ir to, ka nav nepieciešams kodēta failā rakstīt simbolu kodu tabulu.



1.3.                        Izmantota metode


Aplūkosim arhivēšanas (kodēšanas) metodi, kurš tiek izmantots manā programmā:
Kodēšana (encoding) strādā ar datu plūsmu kaut kādā alfabētā, tajā laikā simbolu frekvence (atkārtojums) ir dažāda. Arhivēšanas mērķis ir datu plūsmas pārveidošana uz bitu plūsmu ar minimālu garumu To mēs varam iegūt samazinājot datu plūsmas entropīju, izmantojot simbolu frekvenci: kodu garumam jābūt proporcionālam informācijai, kurā ir ieejas plūsmā. Ja mēs zinam frekvences varbūtības sadalījumu, tad mēs varam iegūt optimālu kodēšanu. Uzdevums ir sarežģītāk gadījumā, ja simbolu frekvences sadalījums iepriekš nav zināms. Šajā gadījumā eksistē divas dažādas pieejas.
Pirmā pieeja: aplūkot ieejas datu plūsmu un uzbūvēt kodēšanu pamatojoties uz savākto statistiku (mums ir jālasa dati, kuri atrodas failā, divas reizes, kas ierobežo pielietošanas sfēru šādiem algoritmiem). Tādā gadījumā izmantotas kodēšanās shēmai jābūt uzrakstītai izejas datu plūsmā, kuru pēc tām dekoderis izmantojies. Piemēram statikas Hafmana kodēšana (Huffman).
Otrā pieeja izmanto, tā saucamo adaptīvo koderu (adaptive coder). Šajās pieejas galvena ideja ir mainīt kodēšanas shēmu atkarība no sākotnējas datu. Tādu algoritmu mēs pagājām tikai vienu reizi, jo viņam nav vajadzīga informācija pār kodēšanas izmantotu shēmu tieša veidā. Dekoderis, nolasot kodētu plūsmu, sinhroniski ar koderu maina kodēšanas shēmu, sākot ar kādu jau zināmu. Adaptīvā kodēšana var vairāk samazināt izejas datu plūsmas garumu, tāpēc ka varbūt paredzēti frekvences izmaiņas. Piemēram, dinamiska Hafmena kodēšana.
Aplūkosim statikas Hafmena kodēšanu. Šī kodēšana salīdzina ieejas simbolus (parasti tie ir dažāda garuma bitu ķēdes) ar mainīga garuma bitu ķēdi. Koda garums simboliem ir proporcionāls viņas frekvences bināram logaritmam, kurš ņemts ar pretējo zīmi. Šī kodēšana ir prefiksa, kas ļauj viegli to dekodēt (prefiksā kodēšanā kāda simbola kods neatbilsta cita simbola koda prefiksam).
Pieņemsim ka, ieejas alfabētā ir četri simboli: a, b, c, d, viņas frekvences ir atbilstoši vienādi ar 1/2, 1/4, 1/8, 1/8. Šim alfabētam Hafmena kodēšana izskatās šādi:

Simbols
Frekvence
Ieeja kods
Izejas kods
a
1/2
00
0
b
1/4
01
10
c
1/8
10
110
d
1/8
11
111

Piemēram, ķēdes abaaacb kods ieejas plūsmā izskatās šādi: 00 01 00 00 00 10 01, bet izejas izskatās šādi: 0 10 0 0 0 110 10 (tukša vieta starp cipariem ir pievienota lai vieglāk lasītu). Ieejas mums bija 14 bitu, bet izejas mums ir ja 11 bitu. Hafmena kodēšana parasti ir uzbūvēta un saglabāta bināra koka veidā, kurā lapās atrodas simboli, bet uz lokiem 'uzrakstīti' cipari 0 vai 1. Simbola kods ir ceļš no koka saknes līdz šim simbolam. Izmantojot Hafmena adaptīvo kodēšanu paradās problēma, kura sastāv no pastāvīgas koka koriģēšanas sakarā ar ieejas plūsmas mainīgu statistiku.
Hafmena metodes priekšrocības ir viņas pietekami augsts ātrums un samazināšanas labā kvalitāte. Šīs algoritms jau sen ir zināms un plaši pielietots, piemēram tā ir programma Compress OS UNIX (programmas realizācija) un kodēšanas standarts faksiem (Hunter) (aparatūras realizācija).
Hafmena kodēšana ir minimāla pārpilnība nosacījumā, ja katrs simbols ir kodēts ar atsevišķu ķēdi alfabētā (simbola koda ķēde var saturēt tikai 0 un 1).
Hafmena metodes trūkums ir samazināšanas pakāpes sakarība no varbūtības simbolu tuvuma pie negatīviem divnieka pakāpēm, tas ir saistīts ar to, ka katrs simbols ir kodēts ar veselu bitu skaitu.
To mēs vislabāk varam redzēt situācijā, kad ir divsimbolu alfabēta kodēšana: šajā gadījumā samazināšanas vienmēr nav, neskatoties uz dažādu simbolu varbūtību; algoritms faktiski "noapaļo" tos līdz 1/2. Šī problēma varbūt dalīji atrisināta ieejas plūsmas bloķēšanas dēļ (t.i. ievads aplūkošanā jaunu simbolus, kuru veids ir 'ab', 'abc',… šeit a, b, c - sākotnēja alfabēta simboli). Tomēr, tas neļauj atbrīvoties no zaudējumiem pilnībā (tie tikai samazinās proporcionāli bloka izmēram) un palielina koda koka augstumu: ja, piemēram ieejas alfabēta simboli ir 8 bitu baiti ar vērtībām 0…255, tad kad mēs bloķējam pa diviem simboliem mēs ieguvām 65536 simbolus (koda koka lapas skaits ir 65536), bet kad mēs bloķējam pa trim - ieguvām 16777216. Atbilstoši pieaug prasības atmiņai un koka būvēšanas laiks (bet adaptīva kodēšanā - arī koka atjaunošanas laiks, tas nozīmē arī samazināšanas laiks). Zaudējumi ir vidēji 1/2 bita uz simbolu, gadījumā kad nav kodēšanas, bet kad kodēšana ir - 1/4 un 1/6 bita atbilstoši blokiem, kurš garums ir 2 un 3.

2.    PRAKTISKĀ DAĻA


2.1.                        Uzdevuma nostādne


Šī programma ir utilītprogramma ar nosaukumu ‘Arhivator’. Tā būs paredzēta faila izmēru samazināšanai.
Izejot no teorētiskas daļas noteikumiem, mēs varam definēt prasības savai programmai:
1.     programmai jānodrošina paziņojumu un pieprasījumu izvade ekrānā (lietotāja interfeisu).
2.     programmai jānodrošina iespēju pieņemt parametrus no komandas rindas.
3.     programmai jānodrošina lietotājam iespēju ievadīt faila nosaukumu un direktoriju.
4.     programmai jākodē failu, pēc lietotāja izvēles:
4.1.      jāskaita faila simbolu daudzums un katra simbola frekvence.
4.2.      pareizi jāizveido kodu katram simbolam.
4.3.      jāieraksta kodētā failā kodu tabulu.
4.4.      jālasa pa simbolu no faila, jāatrada simbola kods, jāieraksta simbola kods kodētā failā.
5.     programmai jāatjauno kodēta faila saturu:
5.1.      jālasa no kodēta faila kodu tabulu.
5.2.      jālasa no kodēta faila pa simbolu, jāatrada simbolu pēc koda kodu tabulā, jāieraksta failā simboli.

Programmas izveides gaitā arī jānodrošina šādas nefunkcionālās prasības:
1)    CPU 80386 SX – 25 MHz.
2)    RAM 1 Mb.
3)    HDD 150 Kb.
4)      OS DOS (Windows).

Izstrādājamai programmai ir jāveic dažādas darbības, kurus varam sadalīt pa trim lielākām grupām: interfeisu atbalstīšana, faila kodēšana, kodēta faila atjaunošana.
Savukārt mēs varam izdalīt no grupa ‘faila kodēšana’ šīs apakšgrupas:
Ø jāskaita faila simbolu daudzums un katra simbola frekvence.
Ø pareizi jāizveido kodu katram simbolam.
Ø jāieraksta kodētā failā kodu tabula.
Ø jālasa pa simbolu no faila, jāatrada simbola kods, jāraksta simbola kods kodētā failā.


No grupas ‘kodēta faila atjaunošana’ izdalīsim šādas operācijas:
Ø jālasa no kodēta faila kodu tabulu.
Ø jālasa no kodēta faila pa simbolu, jāatrada simbols pēc koda kodu tabulā, jāraksta atjaunotā failā simbols.

No grupās ‘interfeisu atbalstīšana’   izdalīsim šādas operācijas:
Ø jāatbalsta faila nosaukumu pieņemšana no komandas rindas un pamatojaties uz to paplašinājumu jāizvēlas vajadzīga operācija (kodēšana vai atjaunošana) bez direktoriju un faila nosaukumu ievadīšanas programmas izpildes laikā;
Ø pieprasījums ievadīt faila atradīšanas direktoriju;
Ø pieprasījums ievadīt faila nosaukumu;
Ø paziņojumu izvade ekrānā;
Ø programmas arhitektūra sastāv no 5 moduļiem:
Ø interfeisu atbalstīšana (mazas funkcijas, kuras atbalsta izvadi ekrānā, ka arī dažādus paskaidrojumus) (Modulis Arh_inte.pas);
Ø skaita simbolu daudzumu failā, skaita katra simbola atkārtojumu un izveido pagaidu failu ar nosaukumu ‘vit.tmp’ (Modulis Arh_coun.pas);
Ø izveido kodētu failu (Modulis Arh_cod.pas);
Ø atjauno kodētu failu (Modulis Arh_ucod.pas);
Ø  nodrošina lietotājam iespēju izvēlēt kodēšanas vai atjaunošanas operāciju (Arh_main.pas);


2.2.                        Algoritma apraksts


Moduļa ‘Arh_main.pas’ algoritms

Ø Pārbaudam ja eksistē parametri no komandas rinda;
Ø Ja parametri eksistē:
Ø Pārejam uz faila eksistēšanu un paplašinājumu pārbaude;
Ø Ja parametri neeksistē:
Ø Pieprasam ievadīt faila atradīšanas direktoriju;
Ø Ja direktorija eksistē:
Ø Pieprasam ievadīt faila nosaukumu ar paplašinājumu;
Ø Ja fails eksistē:
Ø Pārbaudam faila paplašinājumu:
Ø Ja paplašinājums nav ‘vit’, tad izsaucam procedūru ‘coding’;
Ø Ja paplašinājums ir ‘vit’, tad izsaucam procedūru ‘uncoding’;
Ø Ja fails neeksistē šajā direktorijā izvadam paziņojumu, pār to, ka fails neeksistē;
Ø Ja direktorija neeksistē, tad izvadam paziņojumu, pār to, ka direktorija neeksistē;
Ø Darba beigšana;

2.3.                        Programmas apraksts


2.3.1.   Lietojumsfēra


Programma ir paredzēta faila izmēra samazināšanai.
Programmēšanas valoda – TURBO PASCAL 7.0. Programma izpildīta ar Pentium 166 MMX datoru operātājsistēmas MS DOS vidē.
Programmas darbība ir pārbaudīta vairākus reizes, ievadot dažādus faila nosaukumus un failiem bija dažādi saturi, ka arī dažādi paplašinājumi.


2.3.2.   Ievaddati


Direktorijas nosaukums, faila nosaukums, fails (jebkurš faila tips vai kodēts fails).


2.3.3.   Izvaddati


Atjaunots fails vai kodēts fails, informācija pār darbības veikšanu un operācijas procentuālas izteiksmi.


2.3.4.   Ziņas par programmas apjomu un izpildes laiku


Galvena programma: Arh_main.pas – 2323B

Moduli:
1.  Arh_inte.pas – 3949B
Arh_inte.tpu – 4704B
2.  Arh_coun.pas – 1228B
Arh_coun.tpu – 2064B
3.  Arh_cod.pas – 5048B
Arh_cod.tpu – 6768B
4.  Arh_ucod.pas – 3086B
Arh_ucod.tpu – 4240B
Izpildāmais fails Arh_main.exe – 19520B
Programmas izpildes laiks – atkarīgs no datora procesora, no cieta diska ātruma un no lietotāja (cik ātri viņš atbildīs uz programmas pieprasījumiem).







2.3.5.   Moduļu apraksts


Programma sastāv no pieciem moduļiem (zīm. 1.).



 









.


 



Zīm. 1.

Moduli tiek glabāti dažādos failos (1.tab.). Programmas pirmteksts dots 1. pielikuma.

Moduļi un faili
Modulis
Pirmteksta fails
Objektfails
Arh_main
Arh_inte
Arh_cod
Arh_coun
Arh_ucod
Arh_main.pas
Arh_inte.pas
Arh_cod.pas
Arh_coun.pas
Arh_ucod.pas

Arh_inte.tpu
Arh_cod.tpu
Arh_coun.tpu
Arh_ucod.tpu
1. tabula

Programmas atkļūdošanai un izpildei tiks izveidots izpildāms fails Arh_main.exe.

2.3.6.   Procedūru un funkciju apraksts


Modulis ‘Arh_inte.pas’:
Procedure Cls – attīra ekrānu;
Procedure Curoron – ieslēdz kursoru;
Procedure Cursoroff – izslēdz kursoru;
Procedure Frame (X, Y, X1, Y1, Cvet, Bk, Till: integer) – zīme ekrānā logu;
Function Vvod (Chto: String; X, Y, X1, Y1, Kolvo_Simvolov: Integer; Chisla: Boolean): String – nolasa simbolus no tastatūras;
Procedure I_Reading (Percent: Integer) – izvada ekrānā logu un skaitļu;
Procedure Error (What: String) – izvada ekrānā paziņojumu pār kļūdu;

Modulis ‘Arh_cod.pas’:
Procedure Coding (File_Name, Exten: String) – izveido kodēto failu;
Function Len: Integer – Atgriež kodu garumu;


Modulis ‘Arh_coun.pas’
Procedure Counter (File_Name: String) – skaita simbolus tekstā failā, katra simbola atkārtojumu un ieraksta šīs datus failā ‘vit.tmp’;

Modulis ‘Arh_ucod.pas’
Procedure UnCoding (File_Name: String) – izveido teksta failu no kodēta faila;
Procedure Msearch – Atrod simbolu pēc koda un ieraksta simbolu tekstā failā;

3.    LIETOTĀJA INSTRUKCIJA


Programmas izpilde notiek ar faila ‘Arh_main.exe’ palaišanu.
Mēs varam palaist programmu ar parametri un bez tam. Ja mēs palaižam to ar parametri mums ir jānorada faila nosaukums ar paplašinājumu un to pilnu ceļu. Tad jums nevajag ievadīt faila atrašanas direktoriju un to nosaukumu programmas izpildes gaitā.
Ja mēs palaižam programmu bez parametra. Pēc programmas palaišanas tiek atspoguļots logs, kurā jums ir jāievada faila atrašanas direktorija. Ja jūs ievadīsiet neeksistējošu direktoriju, tad programma, ekrānā lejā, izvadīs atbilstošu paziņojumu, pār to, ka direktorija neeksistē, pieprasīs jūs vai iziet no programmas, ja ne, tad atkal ievadam direktoriju, ja iziet, tad izejam no programmas. Pēc eksistējošas direktorijas ievadīšanas jums ir jāievada faila nosaukumu ar paplašinājumu. Ja fails eksistē un viņas paplašinājums ir nav ‘vit’, tad sākam kodēšanas procesu, ja paplašinājums ‘vit’, tad sākam atjaunošanas procesu. Programmas izpildes gaita ekrānā būs redzami dažādi paziņojumi un paskaidrojumi, jums tikai ir jāskatās ekrānā un jālasa izvadāma informācija. Pēc programmas beigas, ja bija izpildīta kodēšana vai atjaunošana, būs fails, kurš tiek izveidots kodēšanas vai atjaunošanas dēļ (fails glabājas direktorijā, kuru ievadīja lietotājs).

4.    PROGRAMMAS FUNKCIONĒŠANAS KONTROLES PIEMĒRS


Programmas pārbaudei es kodēju un atjaunoju dažādus failus ar dažādiem paplašinājumiem un dažādiem izmēriem.



Testēšanās laikā kļūdas nebija redzami.

2. Zīm. Direktorijas ievade.



Šajā zīm. 2. tiek pāradīts direktorijas ievadīšanas process. Šeit lietotājs ievada neeksistējošo direktoriju un ekrānā lejā mēs redzam paziņojumu pār to. Tagad lietotājs var uzspiest taustiņu ESC un iziet no programmas vai nospiest jebkuru citu taustiņu un izlabot ceļu.

3. Zīm. Faila nosaukuma ievadīšana.
Šajā zīm. 3. šeit tiek paradīts faila nosaukuma ievadīšanas process. Šajā gadījumā mēs redzam, kā lietotājs ievada nepareizu faila nosaukumu. Atkal ekrānā lejā mēs redzam paskaidrojumu un lietotājs var iziet no programmas uzspiežot taustiņu ESC vai var izlabot ievadītu faila nosaukumu nospiežot jebkuru taustiņu.








4. Zīm. Darba beigšana.
Šajā zīmējuma tiek paradīta programmas pabeigšana ekrānā tiek izvadīts paziņojums par to, kāda ir samazināšanas gradē procentos (cik procentus sastāda kodēta faila izmērs no sākuma faila izmēru).


5.    SECINĀJUMI


Kvalifikācijas darba izveidošanas gaitā bija izpildīts uzdevuma analīze, ka arī programmas prasības noteikšana. Pēc analizēšanas bija izstrādāts algoritms, kurš strādā pēc ‘Hafmana kodu’ principa tikai neizmanto binārus kokus.
Kvalifikācijas darba bija atrisināta programmēšanas valodā TURBO PASCAL 7.0. un izpildīta ar datora Pentium 166 MMX operētājsistēmā MS-DOS vidē. Visas kļūdas, kuri radojas darba izpildes gaitā bija uzlaboti, izstrādāta programma bija testēta vairākas reizes un kļūdas nebija vairāk redzētas.
Kvalifikācijas darbs bija ļoti sarežģīts. Tā izpildei bija nepieciešamas apmēram 58 stundas, no kurām 5 stundas aizņēma uzdevuma analīze, 20 stundas aizņēma  programmas izveide, apmēram 18 stundas – pārskata noformēšana, palīkušas stundas es veltīju programmas testēšanai un kļūdu uzlabošanai.

6.    IZMANTOTA LITERATŪRA


1.     Керниган Б., Ритчи Д. Язык программирования PASCAL. – Москва, 1992.
2.     Справочник по функциям TURBO PASCAL 7.0. 3.1-4.0. – Киев: Диалектика, 1994.- 416 с.
3.     Witten, I.H., Neal, R.M., and Cleary, J.G. Arithmetic coding for data compression.
4.     Commun. ACM 30, 6 (June 1987), 520-540. Классическая работа по арифметическому кодированию.
5.     Кричевский, Р.Е. Сжатие и поиск информации. - М.: Радио и связь, 1989.

7.    PIELIKUMS


PROGRAMMAS PIRMTEKSTS

Modulis 'Arh_main':

Program Arhivat_Main;

Uses CRT,Arh_Inte,Arh_Cod,Arh_UCod;

Label End_Prog;
Var Key:Char;
    S_Direct:String[60];
    Curr_Direct:String[255];
    File_name:String[12];
    Exten:String[3];
    I:Integer;
    Ok,Exit:Boolean;
    F:File of Byte;

Begin
 GetDir(0,Curr_Direct);
 Cls;
 IF ParamCount>0 Then
  Begin
   File_Name:=ParamStr(1);
   Assign(F,File_name);
   {$I-}
    Reset(F);
   {$I+}
   IF (IOResult<>0) Then
    Begin
     Writeln('File not exist or incorect path!');
     Write('Press any key');
     IF Readkey=Chr(0) Then
      Readkey;
     Goto End_Prog;
    End;
  End
 Else
  Begin
   Exit:=False;
   Repeat
    Cls;
    Frame(9,11,71,14,White,Blue,14);
    GotoXY(20,1);
    Writeln('Enter source directory:');
    GotoXY(2,2);
    Write(S_Direct);
    S_Direct:=Vvod(S_Direct,10,13,70,13,60,False);
    {$I-}
     ChDir(S_Direct);
    {$I+}
    IF (IOResult<>0) Then
     Begin
      Ok:=False;
      Cursoroff;
      Error('path.');
      Key:=Readkey;
      IF Key=Chr(0) Then
       Readkey;
      Cursoron;
      IF (Key=Chr(27)) Then
       Exit:=True;
     End
    Else
     Ok:=True;
   Until((OK) or (Exit));
   Ok:=False;
   While ((OK=False) and (Exit=False)) Do
    Begin
     Cls;
     Frame(9,11,71,14,White,Blue,14);
     GotoXY(19,1);
     Writeln('Enter filename with extension:');
     GotoXY(2,2);
     Write(File_Name);
     File_Name:=Vvod(File_Name,10,13,70,13,12,False);
     Assign(F,File_Name);
     {$I-}
      Reset(F);
     {$I+}
     IF (IOResult<>0) Then
      Begin
       Ok:=False;
       Cursoroff;
       Error('filename.');
       Key:=Readkey;
       IF Key=Chr(0) Then
        Readkey;
       Cursoron;
       IF (Key=Chr(27)) Then
        Exit:=True;
      End
     Else
      Ok:=True;
    End;
  End;
 Cursoroff;
 IF (Not Exit) Then
  Begin
   Close(F);
   I:=1;
   While ((I<=Length(File_Name)-3) and (File_Name[I]<>'.')) Do
    Inc(I);
   IF (I<=Length(File_Name)-3)  Then
    Exten:=Copy(File_Name,I+1,3);
   For I:=1 To Length(Exten) Do
    Exten[i]:=UpCase(Exten[i]);
   {Coding}
   IF (Exten<>'VIT') Then
    Coding(File_Name,Exten)
   Else
    {UnCoding}
     Uncoding(File_Name)
  End;
End_Prog:
 Cursoron;
 Cls;
 ChDir(Curr_Direct);
End.

Modulis 'Arh_Coun':

Unit Arh_Coun;
Interface
Uses Arh_Inte;
 Procedure Counter(File_Name:String);
Implementation
Type PSymbol=^Symbol;
     Symbol=Record
             Symb:Byte;
             Kol_vo:LongInt;
            End;
     Arr_Symb=Array[0..255] of PSymbol;

Procedure Counter(File_Name:String);
Var Mass:Arr_Symb;
    F:File of Byte;
    I,One_Percent:LongInt;
    II:Integer;
    F1:File of Symbol;
    Temp:Byte;

 Begin
  For I:=0 To 255 Do
   Mass[I]:=Nil;
  Assign(F,File_Name+'exe');
  Reset(F);
  Cls;
  Frame(34,18,45,20,15,1,20);
  Write('Reading...');
  I_Reading(0);
  One_Percent:=Trunc(FileSize(F)/100);
  For I:=1 To FileSize(F) Do
   Begin
    IF ((I mod One_percent)=0) Then
     I_Reading(I div One_Percent);
    Read(F,Temp);
    II:=0;
    While ((Mass[II]<>Nil) and (II<=255) and (Mass[II]^.Symb<>Temp)) Do
     Inc(II);
    IF Mass[II]=Nil Then
     Begin
      New(Mass[II]);
      Mass[II]^.Symb:=Temp;
      Mass[II]^.Kol_vo:=1;
     End
    Else
     Inc(Mass[II]^.Kol_vo);
   End;
  Close(F);
  Assign(F1,'vit.tmp');
  Rewrite(F1);
  I:=0;
  While ((Mass[I]<>Nil) and (I<=255)) Do
   Begin
    Write(F1,Mass[I]^);
    Inc(I);
   End;
  Close(F1);
 End;
End.

Modulis 'Arh_Cod':

Unit Arh_Cod;
Interface
Uses Arh_Coun,Arh_Inte,CRT;
Type PSymbol=^Symbol;
     Symbol=Record
             Symb:Byte;
             Kol_vo:LongInt;
            End;
     Arr_Symb=Array[0..255] of PSymbol;

Procedure Coding(File_Name,Exten:String);
Implementation
Procedure Coding(File_Name,Exten:String);
Type PG_Symbol=^G_Symbol;
     G_Symbol=Record
               Gr_Symb:String[255];
               Kolvo:LongInt;
               Sym_Code:String[255];
              End;
     Arr_G_Symbol=Array[0..255] of PG_Symbol;
     PStroka=^Stroka;
     Stroka=String[255];

Var F:File of Symbol;
    a,b:Byte;
    Mass:Arr_Symb;
    One_Percent,I,II,III:LongInt;
    Posled:Array [0..255] of PStroka;
    K,Kol_Sym:Integer;
    Code_mass:Arr_G_Symbol;
    PTemp:PG_Symbol;
    Kolvo_Symb:Byte;
    F1:File of byte;
    F_cod:File of byte;

Function Len:Integer;
 Begin
  i:=0;
  While (Code_mass[i]^.Gr_Symb<>chr(a)) Do
   inc(i);
  Len:=Length(Code_mass[i]^.Sym_code);
 End;

 Begin
  Cls;
  Counter(File_Name);
  Assign(F,'vit.tmp');
  Reset(F);
  Kol_Sym:=0;
  I:=0;
  Cls;
  Frame(30,18,50,20,15,1,20);
  Write('Generating codes...');
  While (Kol_Sym
   Begin
    New(Mass[Kol_Sym]);
    Read(F,Mass[Kol_Sym]^);
    Inc(Kol_Sym);
   End;
  Close(F);
  Erase(F);
  Kolvo_Symb:=Kol_Sym-1;
  II:=0;
  While (II<=Kolvo_Symb) Do
   Begin
    New(Code_mass[II]);
    Code_mass[II]^.Gr_Symb:=Char(Mass[II]^.Symb);
    Code_mass[II]^.Kolvo:=Mass[II]^.Kol_vo;
    Dispose(Mass[II]);
    Inc(II);
   End;
  For I:=0 To Kolvo_Symb-1 Do
   For II:=I+1 To Kolvo_Symb Do
    IF (Code_mass[II]^.Kolvo>Code_Mass[I]^.Kolvo) Then
     Begin
      PTemp:=Code_mass[I];
      Code_mass[I]:=Code_mass[II];
      Code_mass[II]:=PTemp;
     End;
  k:=-1;
  For Kolvo_Symb:=Kolvo_Symb Downto 2 Do
   Begin
    Code_mass[Kolvo_Symb-1]^.Kolvo:=Code_mass[Kolvo_Symb-1]^.Kolvo+Code_mass[Kolvo_Symb]^.Kolvo;
    Code_mass[Kolvo_Symb-1]^.Gr_Symb:=Code_mass[Kolvo_Symb-1]^.Gr_Symb+Code_mass[Kolvo_Symb]^.Gr_Symb;
    Inc(K);
    New(Posled[K]);
    Posled[K]^:=Code_mass[Kolvo_Symb]^.Gr_Symb;
    Dispose(Code_mass[Kolvo_Symb]);
    Code_mass[Kolvo_Symb]:=Nil;
    For I:=0 To Kolvo_Symb-1 Do
     For II:=I+1 To Kolvo_Symb Do
      IF (Code_mass[II]^.Kolvo>Code_Mass[I]^.Kolvo) Then
       Begin
        PTemp:=Code_mass[I];
        Code_mass[I]:=Code_mass[II];
        Code_mass[II]:=PTemp;
       End;
   End;
  Code_mass[0]^.Sym_Code:='1';
  Code_mass[1]^.Sym_Code:='0';
  While (K>-1) Do
   Begin
    I:=0;
    While (Code_mass[I]^.Gr_Symb[length(Code_mass[I]^.Gr_Symb)]<>Posled[K]^[Length(Posled[K]^)]) and (K>-1) Do
     Inc(I);
    IF (k>-1) Then
     Begin
      II:=1;
      While (Code_mass[II]<>Nil) Do
       Inc(II);
      New(Code_mass[II]);
      Code_mass[II]^.Sym_Code:=Code_mass[I]^.Sym_Code+'0';
      Code_mass[I]^.Sym_Code:=Code_mass[I]^.Sym_Code+'1';
     Code_mass[II]^.Gr_Symb:=copy(Code_mass[I]^.Gr_Symb,Length(Code_mass[I]^.Gr_Symb)-Length(Posled[K]^)+1,Length(Posled[K]^));
      Delete(Code_mass[I]^.Gr_Symb,Length(Code_mass[I]^.Gr_Symb)-Length(Posled[K]^)+1,Length(Posled[K]^));
      Dispose(Posled[K]);
      Dec(K);
      Code_mass[II]^.Kolvo:=0;
     End;
   End;
  Delete(File_Name,Length(File_Name)-2,3);
  Assign(F_cod,(File_Name+'vit'));
  Rewrite(F_cod);
  Kolvo_Symb:=Kol_Sym-1;
  a:=ord(Exten[1]);
  Write(F_cod,a);
  a:=ord(Exten[2]);
  Write(F_cod,a);
  a:=ord(Exten[3]);
  Write(F_cod,a);
  Write(F_cod,Kolvo_Symb);
  For I:=0 To Kol_Sym-1 Do
   Begin
    a:=ord(Code_mass[I]^.Gr_Symb[1]);
    Write(F_cod,a);
    a:=length(Code_mass[I]^.Sym_code);
    Write(F_cod,a);
    k:=0;
    a:=0;
    For II:=1 To length(Code_mass[I]^.Sym_Code) Do
     Begin
      a:=a shl 1;
      IF Code_mass[I]^.Sym_Code[II]='1' Then
       a:=a+1;
      Inc(k);
      IF (k=8) Then
       Begin
        Write(F_cod,a);
        a:=0;
        k:=0;
       End;
     End;
    IF (K<>0) Then
     Write(F_cod,a);
   End;
  Assign(F1,File_Name+Exten);
  Reset(F1);
  k:=0;
  b:=0;
  Cls;
  Frame(30,18,50,20,15,1,20);
  Write('Creating archive...');
  I_Reading(0);
  One_Percent:=Trunc(FileSize(F1)/100);
  For III:=1 To FileSize(F1) Do
   Begin
    IF ((III mod One_percent)=0) Then
     I_Reading(III div One_Percent);
    Read(F1,a);
    For II:=1 To len Do
     Begin
      b:=b shl 1;
      IF Code_mass[I]^.Sym_Code[II]='1' Then
       b:=b+1;
      Inc(k);
      IF (k=8) Then
       Begin
        Write(F_cod,b);
        b:=0;
        k:=0;
       End;
     End;
   End;
  Write(F_cod,b);
  Write(F_cod,byte(k));
  Cls;
  Close(F_cod);
  Assign(F_cod,(File_Name+'vit'));
  Reset(F_cod);
  Frame(28,10,52,12,WHITE,BLUE,12);
  Write('Compression ratio = ',(Filesize(F_cod)*100) div (FileSize(F1)),'%');
  Frame(33,15,47,17,WHITE,BLUE,17);
  Write('Press any key');
  IF Readkey=Chr(0) Then
   Readkey;
  Close(F1);
  Close(F_cod);
 End;
End.

Modulis 'Arh_ucod':

Unit Arh_UCod;
Interface
Uses Arh_Inte,CRT;
 Procedure Uncoding(File_Name:String);
Implementation
Procedure Uncoding(File_Name:String);
Type PSym_Code=^Sym_Code;
     Sym_Code=Record
               Symbol:Char;
               S_Code:String[255];
              End;
Var F:File of Byte;
    F1:File of Char;
    II,I:Integer;
    Tek_Symb,One_Percent:LongInt;
    T,Tmps:String[255];
    Cod,Temp,Kolvo_Symb:Byte;
    Code_mass:Array [0..255] of PSym_Code;

Procedure MSearch;
Var k,j:Integer;
    TempStr:String;
 Begin
  k:=0;
  TempStr:=T[1];
  j:=1;
  While (J<=Length(T)) Do
   Begin
    k:=0;
    While ((Code_mass[k]^.S_Code<>TempStr) and (k<=Kolvo_Symb)) Do
     inc(K);
    IF (Code_mass[k]^.S_Code=TempStr) Then
     Begin
      Write(F1,Code_mass[K]^.Symbol);
      Delete(T,1,Length(TempStr));
      Delete(TempStr,1,255);
      TempStr:=T[1];
      j:=1;
     End
    Else
     Begin
      Inc(J);
      TempStr:=TempStr+T[J];
     End;
   End;
 End;

 Begin
  Cls;
  Frame(34,12,46,14,White,Blue,14);
  GotoXY(2,1);
  Write('Uncoding...');
  Delete(File_Name,Length(File_Name)-2,3);
  Assign(F,File_Name+'vit');
  Reset(F);
  Delete(Tmps,1,255);
  Read(F,Temp);
  Tmps:=Tmps+chr(Temp);
  Read(F,Temp);
  Tmps:=Tmps+chr(Temp);
  Read(F,Temp);
  Tmps:=Tmps+chr(Temp);
  Assign(F1,File_Name+Tmps);
  Rewrite(F1);
  I_Reading(0);
  One_Percent:=Trunc(FileSize(F)/100);
  Tek_Symb:=3;
  Read(F,Kolvo_Symb);
  Inc(Tek_Symb);
  For I:=0 To Kolvo_Symb Do
   Begin
    New(Code_mass[I]);
    Read(F,Temp);
    Inc(Tek_Symb);
    Code_mass[I]^.Symbol:=Chr(Temp);
    Read(F,Temp);
    Inc(Tek_Symb);
    Code_mass[I]^.S_Code:='';
    While (Temp<>0) Do
     Begin
      Read(F,Cod);
      Inc(Tek_Symb);
      T:='qwertyui';
      For II:=1 To 8 Do
       Begin
        IF (Cod>127) Then
         T[II]:='1'
        Else
         T[II]:='0';
        Cod:=Cod Shl 1;
       End;
      IF (Temp>=8) Then
       Begin
        Code_mass[I]^.S_Code:=Code_mass[I]^.S_Code+T;
        Temp:=Temp-8;
       End
      Else
       Begin
        Code_mass[I]^.S_Code:=Code_mass[I]^.S_Code+copy(T,Length(T)-(Temp-1),Temp);
        Temp:=0;
       End;
     End;
   End;
  T:='';
  Read(F,Temp);
  Inc(Tek_Symb);
  While (Not EOF(F)) Do
   Begin
    IF ((Tek_Symb mod One_percent)=0) Then
     I_Reading(Tek_Symb div One_Percent);
    Cod:=Temp;
    Read(F,Temp);
    Inc(Tek_Symb);
    IF (Not EOF(F)) Then
     Begin
      Tmps:='qwertyui';
      For II:=1 To 8 Do
       Begin
        IF (Cod>127) Then
         Tmps[II]:='1'
        Else
         Tmps[II]:='0';
        Cod:=Cod Shl 1;
       End;
      T:=T+Tmps;
      Msearch;
     End;
   End;
  IF Temp>0 Then
   Begin
    Tmps:='qwertyui';
    For II:=1 To 8 Do
     Begin
      IF (Cod>127) Then
       Tmps[II]:='1'
      Else
       Tmps[II]:='0';
      Cod:=Cod Shl 1;
     End;
    Delete(Tmps,1,Length(Tmps)-Temp);
    T:=T+Tmps;
    MSearch;
   End;
  Close(F);
  Close(F1);
 End;
End.
Modulis 'Arh_inte':

Unit Arh_Inte;
Interface
  Procedure Cls;
  procedure cursoron;
  procedure cursoroff;
  Procedure Frame(X,Y,X1,Y1,Cvet,Bk,Till:Integer);
  Function Vvod(Chto:String;X,Y,X1,Y1,Kolvo_Simvolov:Integer;Chisla:Boolean):String;
  Procedure Error(What:String);
  Procedure I_Reading(Percent:Integer);
Implementation
Uses Crt;
Procedure Cls;
 Begin
  TextBackGround(Black);
  Window(1,1,80,25);
  ClrScr;
 End;

Procedure Cursoron;
Begin
 asm
           mov ax,$0100;
           mov cx,$1F1f;
           int 10h;
 end;
End;

procedure cursoroff;
begin
                asm
            mov             AX,$0100;
            mov cx,$2020;
            int 10h;
        end;
end;

Procedure Frame(X,Y,X1,Y1,Cvet,Bk,Till:Integer);
Var I:Integer;
 Begin
  Window(X,Y,X1,Till);
  TextColor(Cvet);
  TextBackGround(Bk);
  ClrScr;
  Window(X,Y,X1,Till+1);
  GotoXY(X1-X+1,Till-Y+1);
  Write('ј');
  GotoXY(1,1);
  Write('Й');
  For I:=2 To X1-X Do
   Write('Н');
  Write('»');
  For I:=2 To Till-Y Do
   Begin
    GotoXY(1,I);
    Write('є');
   End;
  GotoXY(1,Till-Y+1);
  Write('И');
  For I:=2 To X1-X Do
   Write('Н');
  For I:=2 To Till-Y Do
   Begin
    GotoXY(X1-X+1,I);
    Write('є');
   End;
  Window(X,Y+1,X1,Y1);
  GotoXY(2,1);
 End;

Function Vvod(Chto:String;X,Y,X1,Y1,Kolvo_Simvolov:Integer;Chisla:Boolean):String;
Var Klavisha:Char;
    Temp_Str:String;
    I,Pozition:Integer;
    Plus:String[1];
    Vvod_Chisla:Set Of Char;
 Begin
  Vvod_Chisla:=['0'..'9',',','.'];
  Window(X,Y,X1,Y1);
  Temp_Str:=Chto;
  Klavisha:=' ';
  Pozition:=1;
  While Klavisha<>Chr(13) Do
   Begin
    Klavisha:=Readkey;
    IF ((Klavisha<>Chr(13)) and (Klavisha<>Chr(8)) and (Klavisha<>Chr(0)) and (Klavisha<>Chr(27)) and (Klavisha<>Chr(9))) Then
     IF ((Chisla=False) and (Kolvo_Simvolov>Length(Temp_Str))) Then
      Begin
       Plus:=Klavisha;
       Insert(Plus,Temp_Str,Pozition);
       GotoXY(Pozition,1);
       For I:=Pozition To Length(Temp_Str) Do
        Write(Temp_Str[I]);
       Inc(Pozition);
       GotoXY(Pozition,1);
      End
     Else
      IF ((Klavisha in Vvod_Chisla) and (Kolvo_Simvolov>Length(Temp_Str))) Then
       Begin
        Plus:=Klavisha;
        Insert(Plus,Temp_Str,Pozition);
        GotoXY(Pozition,1);
        For I:=Pozition To Length(Temp_Str) Do
         Write(Temp_Str[I]);
        Inc(Pozition);
        GotoXY(Pozition,1);
       End;
    IF ((Klavisha=Chr(8)) and (Pozition>1)) Then
     Begin
      Dec(Pozition);
      Delete(Temp_Str,Pozition,1);
      GotoXY(Pozition,1);
      For I:=Pozition To Length(Temp_Str) Do
       Write(Temp_Str[I]);
      Write(' ');
      GotoXY(Pozition,1);
     End;
    IF Klavisha=Chr(0) Then
     Begin
      Klavisha:=ReadKey;
      IF Klavisha=Chr(75) Then
       IF Pozition>1 Then
        Begin
         Dec(Pozition);
         GotoXY(Pozition,1);
        End;
      IF Klavisha=Chr(77) Then
       IF Pozition
        Begin
         Inc(Pozition);
         GotoXY(Pozition,1);
        End;
      IF Klavisha=Chr(79) Then
       Begin
        Pozition:=Length(Temp_Str)+1;
        GotoXY(Pozition,1);
       End;
      IF Klavisha=Chr(71) Then
       Begin
        Pozition:=1;
        GotoXY(Pozition,1);
       End;
      IF (Klavisha=Chr(83)) and (Length(Temp_Str)>0) Then
       Begin
        Delete(Temp_Str,Pozition,1);
        For I:=Pozition To Length(Temp_Str) Do
         Write(Temp_Str[I]);
        Write(' ');
        GotoXY(Pozition,1);
       End;
     End;
   End;
  Vvod:=Temp_Str;
 End;

Procedure Error(What:String);
 Begin
  Frame(18,21,61,24,White,Blue,24);
  Write('You have entered incorrect ',What);
  GotoXY(2,2);
  Write('Press (ESC) to Exit or any key to Continue');
 End;

Procedure I_Reading(Percent:Integer);
 Begin
  Frame(38,22,42,24,White,Blue,24);
  Write(Percent,'%');
 End;
End.



Nav komentāru:

Ierakstīt komentāru