Kōpeketanga Raraunga ma te whakamahi i te Huffman algorithm

urunga

I roto i tenei tuhinga ka korero ahau mo te Huffman algorithm rongonui, me tana tono i roto i te kohinga raraunga.

Ko te mutunga, ka tuhia e matou he putunga ngawari. Kua korerohia tenei tuhinga mo Habré, engari kaore he whakatinanatanga mahi. Ko nga kaupapa ariā o te pou o naianei i tangohia mai i nga akoranga rorohiko rorohiko a te kura me te pukapuka a Robert Laforet "Nga Hanganga Raraunga me nga Algorithms i Java". Na, kua tapahia nga mea katoa!

He whakaaro iti

I roto i te konae kuputuhi auau, ka whakawaeheretia tetahi kiripuaki ki te 8 paraka (whakawaehere ASCII) ki te 16 ranei (whakawaehere Waehereao). I muri mai ka whakaarohia e tatou te whakawaehere ASCII. Hei tauira, tangohia te rarangi s1 = “E KORERO SUSIE HE MAHIA”. E 22 te katoa o nga tohu kei roto i te raina, ko te tikanga, tae atu ki nga waahi me te tohu raina hou - 'n'. Ko te konae kei roto i tenei rarangi ka taumaha 22*8 = 176 moka. Ka ara ake te patai: he mea tika te whakamahi i nga moka 8 katoa hei whakawaehere i te tohu kotahi? Kaore matou e whakamahi i nga tohu ASCII katoa. Ahakoa i pena, he pai ake mo te reta tino noa - S - kia hoatu te waehere poto rawa atu, me te reta onge - T (ranei U, 'n' ranei) - kia hoatu he waehere roa ake. Koinei te mea kei roto i te Huffman algorithm: he mea tika kia kimihia te whiringa whakawaehere tino pai ka iti ake te taumaha o te konae. He mea noa ka rere ke te roa o nga tohu mo nga tohu rereke - koinei te mea i ahu mai ai te algorithm.

Whakawaehere

He aha e kore ai e hoatu he tohu ki te tohu 'S', hei tauira, 1 bit te roa: 0, 1 ranei. Me waiho hei 1. Na ko te tuarua o nga ahuatanga noa - ' ' (mokowā) - hoatu 0. Whakaarohia kua timata koe ki te wetewete i to karere - te aho kua whakawaeheretia s1 - ka kite koe ka timata te waehere ki te 1. Na, ka aha koe: ko te ahua S tenei, he ahua ke atu ranei, hei tauira A? Na reira, ka puta he ture nui:

Kaua tetahi waehere hei tohu tuatahi mo tetahi atu

Ko tenei ture te mea matua i roto i te algorithm. Na reira, ka timata te hanga waehere ki te ripanga auau, e tohu ana i te auau (te maha o nga huihuinga) o ia tohu:

Kōpeketanga Raraunga ma te whakamahi i te Huffman algorithm Ko nga tohu me te nuinga o nga takanga me whakawaeherehia kia iti rawa taea te maha o nga moka. Ka hoatu e ahau he tauira o tetahi o nga ripanga waehere ka taea:

Kōpeketanga Raraunga ma te whakamahi i te Huffman algorithm Na ka penei te ahua o te karere kua whakawaeheretia:

10 01111 10 110 1111 00 10 010 1110 10 00 110 0110 00 110 10 00 1111 010 10 1110 01110

I wehea e ahau te waehere o ia ahua me te waahi. E kore tenei e puta i roto i te konae kua kopeke pono!
Ka puta ake te patai: i pehea te ahua o tenei rangatahi ki te hanga i tetahi ripanga waehere? Ka korerohia tenei i raro nei.

Te hanga rakau Huffman

Koinei te waahi ka tae mai nga rakau rapu rua ki te whakaora. Kaua e manukanuka, kaore koe e hiahia ki te rapu, ki te whakauru, ki te whakakore ranei i nga tikanga i konei. Anei te hanganga rakau i java:

public class Node {
    private int frequence;
    private char letter;
    private Node leftChild;
    private Node rightChild;
    ...
}

class BinaryTree {
    private Node root;

    public BinaryTree() {
        root = new Node();
    }
    public BinaryTree(Node root) {
        this.root = root;
    }
    ...
}

Ehara tenei i te waehere oti, kei raro te waehere katoa.

Anei te algorithm mo te hanga rakau:

  1. Waihangahia he ahanoa Node mo ia ahua mai i te karere (raina s1). I roto i to maatau ka 9 nga pona (Nga mea Node). E rua nga mara raraunga kei ia pona: tohu me te auau
  2. Waihangahia he ahanoa Rakau (BinaryTree) mo ia Node. Ka noho te pona hei putake o te rakau.
  3. Whakauruhia enei rakau ki te rarangi matua. Ko te iti o te auau, ka teitei ake te kaupapa matua. Na, i te wa e tango ana, ko te dervo me te iti o te waa ka tohua i nga wa katoa.

I muri mai ka hiahia koe ki te mahi i nga mahi e whai ake nei:

  1. Tangohia nga rakau e rua mai i te rarangi matua ka waiho hei tamariki mo te node hou (te node hou kare he reta). He rite te auau o te node hou ki te tapeke o nga iarere o nga rakau uri e rua.
  2. Mo tenei node, hanga he rakau me te putake ki tenei node. Whakauruhia tenei rakau ki roto i te rarangi matua. (I te mea he auau hou te rakau, tera pea ka puta ki tetahi waahi hou i te rarangi)
  3. Haere tonu i nga hikoinga 1 me te 2 kia kotahi noa te rakau e toe ana ki te rarangi - te rakau Huffman

Whakaarohia tenei algorithm i te raina s1:

Kōpeketanga Raraunga ma te whakamahi i te Huffman algorithm

I konei ko te tohu “lf” (linefeed) te tikanga he raina hou, “sp” (space) he mokowā.

Na he aha kei muri mai?

I whiwhi matou i te rakau Huffman. pai. A he aha te mahi ki a ia? Karekau ratou e tango mo te kore utu, katahi ka whai koe i nga huarahi katoa mai i te putake ki nga rau o te rakau. Me whakaae tatou ki te tohu i te tapa 0 mena ka ahu ki te tamaiti maui me te 1 mena ka ahu ki te taha matau. Ko te tino korero, i roto i tenei tohu, ko te tohu o te tohu ko te ara mai i te pakiaka o te rakau ki te rau kei roto tenei tohu.

Kōpeketanga Raraunga ma te whakamahi i te Huffman algorithm

Koinei te ahua o te ripanga o nga waehere. Kia mahara ki te whakaaro tatou ki tenei ripanga, ka taea e tatou te whakatau mo te "taimaha" o ia tohu - koinei te roa o tana waehere. Na, i roto i te ahua kōpeke, ka paunatia te kōnae taketake: 2 * 3 + 2*4 + 3 * 3 + 6 * 2 + 1 * 4 + 1 * 5 + 2 * 4 + 4 * 2 + 1 * 5 = 65 bits . I te tuatahi 176 nga moka te taumaha. No reira, i whakaitihia e matou ki te 176/65 = 2.7 nga wa! Engari he utopia tenei. Ko te whakarea penei kare pea e whiwhi. He aha? Ka korerohia tenei i muri tata nei.

Wetewaehere

Ana, ko te mea ngawari noa atu ko te wetewete. Ki taku whakaaro he tokomaha o koutou kua pohehe e kore e taea e matou te hanga noa i tetahi konae kua kopeke me te kore he tohu mo te ahua o te whakawaehere - e kore e taea e matou te wetewete! Ae, ae, he uaua ki ahau ki te mohio ki tenei, engari me hanga e ahau he ripanga konae kuputuhi.txt me te ripanga taapiri:

01110
 00
A010
E1111
I110
S10
T0110
U01111
Y1110

Ripanga tāurunga i roto i te puka 'tohu' 'waehere pūāhua'. He aha te 01110 kaore he tohu? Inaa, he tohu, ko nga taputapu java e whakamahia ana e au i te wa e whakaputa ana ki tetahi konae, ko te tohu raina hou - 'n' - ka huri hei raina hou (ahakoa te poauau o te tangi). Na reira, ko te rarangi kau kei runga ko te ahua mo te waehere 01110. Mo te waehere 00, ko te ahua he waahi kei te timatanga o te raina. Ka kii tonu ahau mo to taatau Khan, ko tenei tikanga mo te penapena tepu ka taea te kii ko te tino pohehe. Engari he ngawari ki te mohio me te whakatinana. Ka koa ahau ki te whakarongo ki o korero i roto i nga korero mo te arotautanga.

Ma te whai i tenei ripanga ka tino ngawari ki te wetewete. Kia maumahara tatou he aha te ture i whaia e tatou i te wa e hanga ana te whakawaehere:

Kaua tetahi waehere hei tohu tuatahi mo tetahi atu

Koinei te waahi ka whai waahi ki te whakahaere. Ka panui tatou i te raupapa moka ma te moka, a, i te wa ka puta te aho d, kei roto i nga paraka panui, ka taurite ki te whakawaehere e rite ana ki te ahuatanga o te ahua, ka mohio tonu tatou i whakawaeheretia te ahua o te kiripuaki (me te mea anake!). I muri mai, ka tuhia e matou te ahua ki te raina wetewete (te raina kei roto te karere wetewete), tautuhi i te raina d, ka panui i te konae kua whakawaeheretia.

Реализация

Kua tae ki te wa ki te whakaiti i taku waehere me te tuhi i tetahi putunga. Karangahia ko Compressor.

Me timata ano. Tuatahi, ka tuhia e matou te akomanga Node:

public class Node {
    private int frequence;//частота
    private char letter;//буква
    private Node leftChild;//левый потомок
    private Node rightChild;//правый потомок

   

    public Node(char letter, int frequence) { //собственно, конструктор
        this.letter = letter;
        this.frequence = frequence;
    }

    public Node() {}//перегрузка конструтора для безымянных узлов(см. выше в разделе о построении дерева Хаффмана)
    public void addChild(Node newNode) {//добавить потомка
        if (leftChild == null)//если левый пустой=> правый тоже=> добавляем в левый
            leftChild = newNode;
        else {
            if (leftChild.getFrequence() <= newNode.getFrequence()) //в общем, левым потомком
                rightChild = newNode;//станет тот, у кого меньше частота
            else {
                rightChild = leftChild;
                leftChild = newNode;
            }
        }

        frequence += newNode.getFrequence();//итоговая частота
    }

    public Node getLeftChild() {
        return leftChild;
    }

    public Node getRightChild() {
        return rightChild;
    }

    public int getFrequence() {
        return frequence;
    }

    public char getLetter() {
        return letter;
    }

    public boolean isLeaf() {//проверка на лист
        return leftChild == null && rightChild == null;
    }
}

Inaianei te rakau:

class BinaryTree {
    private Node root;

    public BinaryTree() {
        root = new Node();
    }

    public BinaryTree(Node root) {
        this.root = root;
    }

    public int getFrequence() {
        return root.getFrequence();
    }

    public Node getRoot() {
        return root;
    }
}

Tūtira Matua:

import java.util.ArrayList;//да-да, очередь будет на базе списка

class PriorityQueue {
    private ArrayList<BinaryTree> data;//список очереди
    private int nElems;//кол-во элементов в очереди

    public PriorityQueue() {
        data = new ArrayList<BinaryTree>();
        nElems = 0;
    }

    public void insert(BinaryTree newTree) {//вставка
        if (nElems == 0)
            data.add(newTree);
        else {
            for (int i = 0; i < nElems; i++) {
                if (data.get(i).getFrequence() > newTree.getFrequence()) {//если частота вставляемого дерева меньше 
                    data.add(i, newTree);//чем част. текущего, то cдвигаем все деревья на позициях справа на 1 ячейку                   
                    break;//затем ставим новое дерево на позицию текущего
                }
                if (i == nElems - 1) 
                    data.add(newTree);
            }
        }
        nElems++;//увеличиваем кол-во элементов на 1
    }

    public BinaryTree remove() {//удаление из очереди
        BinaryTree tmp = data.get(0);//копируем удаляемый элемент
        data.remove(0);//собственно, удаляем
        nElems--;//уменьшаем кол-во элементов на 1
        return tmp;//возвращаем удаленный элемент(элемент с наименьшей частотой)
    }
}

Ko te akomanga e hanga ana i te rakau Huffman:

public class HuffmanTree {
    private final byte ENCODING_TABLE_SIZE = 127;//длина кодировочной таблицы
    private String myString;//сообщение
    private BinaryTree huffmanTree;//дерево Хаффмана
    private int[] freqArray;//частотная таблица
    private String[] encodingArray;//кодировочная таблица


    //----------------constructor----------------------
    public HuffmanTree(String newString) {
        myString = newString;

        freqArray = new int[ENCODING_TABLE_SIZE];
        fillFrequenceArray();

        huffmanTree = getHuffmanTree();

        encodingArray = new String[ENCODING_TABLE_SIZE];
        fillEncodingArray(huffmanTree.getRoot(), "", "");
    }

    //--------------------frequence array------------------------
    private void fillFrequenceArray() {
        for (int i = 0; i < myString.length(); i++) {
            freqArray[(int)myString.charAt(i)]++;
        }
    }

    public int[] getFrequenceArray() {
        return freqArray;
    }

    //------------------------huffman tree creation------------------
    private BinaryTree getHuffmanTree() {
        PriorityQueue pq = new PriorityQueue();
        //алгоритм описан выше
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            if (freqArray[i] != 0) {//если символ существует в строке
                Node newNode = new Node((char) i, freqArray[i]);//то создать для него Node
                BinaryTree newTree = new BinaryTree(newNode);//а для Node создать BinaryTree
                pq.insert(newTree);//вставить в очередь
            }
        }

        while (true) {
            BinaryTree tree1 = pq.remove();//извлечь из очереди первое дерево.

            try {
                BinaryTree tree2 = pq.remove();//извлечь из очереди второе дерево

                Node newNode = new Node();//создать новый Node
                newNode.addChild(tree1.getRoot());//сделать его потомками два извлеченных дерева
                newNode.addChild(tree2.getRoot());

                pq.insert(new BinaryTree(newNode);
            } catch (IndexOutOfBoundsException e) {//осталось одно дерево в очереди
                return tree1;
            }
        }
    }

    public BinaryTree getTree() {
        return huffmanTree;
    }

    //-------------------encoding array------------------
    void fillEncodingArray(Node node, String codeBefore, String direction) {//заполнить кодировочную таблицу
        if (node.isLeaf()) {
            encodingArray[(int)node.getLetter()] = codeBefore + direction;
        } else {
            fillEncodingArray(node.getLeftChild(), codeBefore + direction, "0");
            fillEncodingArray(node.getRightChild(), codeBefore + direction, "1");
        }
    }

    String[] getEncodingArray() {
        return encodingArray;
    }

    public void displayEncodingArray() {//для отладки
        fillEncodingArray(huffmanTree.getRoot(), "", "");

        System.out.println("======================Encoding table====================");
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            if (freqArray[i] != 0) {
                System.out.print((char)i + " ");
                System.out.println(encodingArray[i]);
            }
        }
        System.out.println("========================================================");
    }
    //-----------------------------------------------------
    String getOriginalString() {
        return myString;
    }
}

Ko te karaehe kei roto ko wai te whakawaehere/whakaweewaehere:

public class HuffmanOperator {
    private final byte ENCODING_TABLE_SIZE = 127;//длина таблицы
    private HuffmanTree mainHuffmanTree;//дерево Хаффмана (используется только для сжатия)
    private String myString;//исходное сообщение
    private int[] freqArray;//частотаная таблица
    private String[] encodingArray;//кодировочная таблица
    private double ratio;//коэффициент сжатия 


    public HuffmanOperator(HuffmanTree MainHuffmanTree) {//for compress
        this.mainHuffmanTree = MainHuffmanTree;

        myString = mainHuffmanTree.getOriginalString();

        encodingArray = mainHuffmanTree.getEncodingArray();

        freqArray = mainHuffmanTree.getFrequenceArray();
    }

    public HuffmanOperator() {}//for extract;

    //---------------------------------------compression-----------------------------------------------------------
    private String getCompressedString() {
        String compressed = "";
        String intermidiate = "";//промежуточная строка(без добавочных нулей)
        //System.out.println("=============================Compression=======================");
        //displayEncodingArray();
        for (int i = 0; i < myString.length(); i++) {
            intermidiate += encodingArray[myString.charAt(i)];
        }
        //Мы не можем писать бит в файл. Поэтому нужно сделать длину сообщения кратной 8=>
        //нужно добавить нули в конец(можно 1, нет разницы)
        byte counter = 0;//количество добавленных в конец нулей (байта в полне хватит: 0<=counter<8<127)
        for (int length = intermidiate.length(), delta = 8 - length % 8; 
        		counter < delta ; counter++) {//delta - количество добавленных нулей
            intermidiate += "0";
        }
        
        //склеить кол-во добавочных нулей в бинарном предаствлении и промежуточную строку 
        compressed = String.format("%8s", Integer.toBinaryString(counter & 0xff)).replace(" ", "0") + intermidiate;
        		
        //идеализированный коэффициент
        setCompressionRatio();
        //System.out.println("===============================================================");
        return compressed;
    }
    
    private void setCompressionRatio() {//посчитать идеализированный коэффициент 
        double sumA = 0, sumB = 0;//A-the original sum
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            if (freqArray[i] != 0) {
                sumA += 8 * freqArray[i];
                sumB += encodingArray[i].length() * freqArray[i];
            }
        }
        ratio = sumA / sumB;
    }

    public byte[] getBytedMsg() {//final compression
        StringBuilder compressedString = new StringBuilder(getCompressedString());
        byte[] compressedBytes = new byte[compressedString.length() / 8];
        for (int i = 0; i < compressedBytes.length; i++) {
                compressedBytes[i] = (byte) Integer.parseInt(compressedString.substring(i * 8, (i + 1) * 8), 2);
        }
        return compressedBytes;
    }
    //---------------------------------------end of compression----------------------------------------------------------------
    //------------------------------------------------------------extract-----------------------------------------------------
    public String extract(String compressed, String[] newEncodingArray) {
        String decompressed = "";
        String current = "";
        String delta = "";
        encodingArray = newEncodingArray;
        
        //displayEncodingArray();
        //получить кол-во вставленных нулей
        for (int i = 0; i < 8; i++) 
        	delta += compressed.charAt(i);
        int ADDED_ZEROES = Integer.parseInt(delta, 2);
       
        for (int i = 8, l = compressed.length() - ADDED_ZEROES; i < l; i++) {
            //i = 8, т.к. первым байтом у нас идет кол-во вставленных нулей
            current += compressed.charAt(i);
            for (int j = 0; j < ENCODING_TABLE_SIZE; j++) {
                if (current.equals(encodingArray[j])) {//если совпало
                    decompressed += (char)j;//то добавляем элемент
                    current = "";//и обнуляем текущую строку
                }
            }
        }

        return decompressed;
    }

    public String getEncodingTable() {
        String enc = "";
    	for (int i = 0; i < encodingArray.length; i++) {
        	if (freqArray[i] != 0) 
        		enc += (char)i + encodingArray[i] + 'n';
        }
    	return enc;
    }

    public double getCompressionRatio() {
        return ratio;
    }


    public void displayEncodingArray() {//для отладки
        System.out.println("======================Encoding table====================");
        for (int i = 0; i < ENCODING_TABLE_SIZE; i++) {
            //if (freqArray[i] != 0) {
                System.out.print((char)i + " ");
                System.out.println(encodingArray[i]);
            //}
        }
        System.out.println("========================================================");
    }
    }

He akomanga e ngawari ake ai te tuhi ki tetahi konae:

import java.io.File;
import java.io.PrintWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Closeable;

public class FileOutputHelper implements Closeable {
    private File outputFile;
    private FileOutputStream fileOutputStream;

    public FileOutputHelper(File file) throws FileNotFoundException {
        outputFile = file;
        fileOutputStream = new FileOutputStream(outputFile);
    }

    public void writeByte(byte msg) throws IOException {
        fileOutputStream.write(msg);
    }

    public void writeBytes(byte[] msg) throws IOException {
        fileOutputStream.write(msg);
    }

    public void writeString(String msg) {
    	try (PrintWriter pw = new PrintWriter(outputFile)) {
    		pw.write(msg);
    	} catch (FileNotFoundException e) {
    		System.out.println("Неверный путь, или такого файла не существует!");
    	}
    }

    @Override
    public void close() throws IOException {
        fileOutputStream.close();
    }

    public void finalize() throws IOException {
        close();
    }
}

He karaehe kia ngawari ake te panui mai i tetahi konae:

import java.io.FileInputStream;
import java.io.EOFException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;

public class FileInputHelper implements Closeable {
	private FileInputStream fileInputStream;
	private BufferedReader fileBufferedReader;
	
	public FileInputHelper(File file) throws IOException {
		fileInputStream = new FileInputStream(file);
		fileBufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
	}
	
	
    public byte readByte() throws IOException {
    	int cur = fileInputStream.read();
    	if (cur == -1)//если закончился файл
    		throw new EOFException();
    	return (byte)cur;
    }
    
    public String readLine() throws IOException {
    	return fileBufferedReader.readLine();
    }
    
    @Override
    public void close() throws IOException{
    	fileInputStream.close();
    }
}

Na, me te akomanga matua:

import java.io.File;
import java.nio.charset.MalformedInputException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Paths;
import java.util.List;
import java.io.EOFException;
public class Main {
	private static final byte ENCODING_TABLE_SIZE = 127;
	
    public static void main(String[] args) throws IOException {
        try {//указываем инструкцию с помощью аргументов командной строки
            if (args[0].equals("--compress") || args[0].equals("-c"))
                compress(args[1]);
            else if ((args[0].equals("--extract") || args[0].equals("-x"))
            		&& (args[2].equals("--table") || args[2].equals("-t"))) {
            	extract(args[1], args[3]);
            }
            else
                throw new IllegalArgumentException();
        } catch (ArrayIndexOutOfBoundsException | IllegalArgumentException e) {
            System.out.println("Неверный формат ввода аргументов ");
            System.out.println("Читайте Readme.txt");
            e.printStackTrace();
        }
    }

	public static void compress(String stringPath) throws IOException {
        List<String> stringList;
        File inputFile = new File(stringPath);
        String s = "";
        File compressedFile, table;
        
        try {
            stringList = Files.readAllLines(Paths.get(inputFile.getAbsolutePath()));
        } catch (NoSuchFileException e) {
            System.out.println("Неверный путь, или такого файла не существует!");
            return;
        } catch (MalformedInputException e) {
        	System.out.println("Текущая кодировка файла не поддерживается");
        	return;
        }

        for (String item : stringList) {
            s += item;
            s += 'n';
        }

        HuffmanOperator operator = new HuffmanOperator(new HuffmanTree(s));

        compressedFile = new File(inputFile.getAbsolutePath() + ".cpr");
        compressedFile.createNewFile();
        try (FileOutputHelper fo = new FileOutputHelper(compressedFile)) {
        	fo.writeBytes(operator.getBytedMsg());
        }
        //create file with encoding table:
        
        table = new File(inputFile.getAbsolutePath() + ".table.txt");
        table.createNewFile();
        try (FileOutputHelper fo = new FileOutputHelper(table)) {
        	fo.writeString(operator.getEncodingTable());
        }
        
        System.out.println("Путь к сжатому файлу: " + compressedFile.getAbsolutePath());
        System.out.println("Путь к кодировочной таблице " + table.getAbsolutePath());
        System.out.println("Без таблицы файл будет невозможно извлечь!");
        
        double idealRatio = Math.round(operator.getCompressionRatio() * 100) / (double) 100;//идеализированный коэффициент
        double realRatio = Math.round((double) inputFile.length() 
        		/ ((double) compressedFile.length() + (double) table.length()) * 100) / (double)100;//настоящий коэффициент
        
        System.out.println("Идеализированный коэффициент сжатия равен " + idealRatio);
        System.out.println("Коэффициент сжатия с учетом кодировочной таблицы " + realRatio);
    }

    public static void extract(String filePath, String tablePath) throws FileNotFoundException, IOException {
        HuffmanOperator operator = new HuffmanOperator();
        File compressedFile = new File(filePath),
        	 tableFile = new File(tablePath),
        	 extractedFile = new File(filePath + ".xtr");
        String compressed = "";
        String[] encodingArray = new String[ENCODING_TABLE_SIZE];
        //read compressed file
        //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!check here:
        try (FileInputHelper fi = new FileInputHelper(compressedFile)) {
        	byte b;
        	while (true) {
        		b = fi.readByte();//method returns EOFException
        		compressed += String.format("%8s", Integer.toBinaryString(b & 0xff)).replace(" ", "0");
        	}
        } catch (EOFException e) {
        	
        }
        
        //--------------------
        
        //read encoding table:
        try (FileInputHelper fi = new FileInputHelper(tableFile)) {
        	fi.readLine();//skip first empty string
        	encodingArray[(byte)'n'] = fi.readLine();//read code for 'n'
        	while (true) {
        		String s = fi.readLine();
        		if (s == null)
        			throw new EOFException();
        		encodingArray[(byte)s.charAt(0)] = s.substring(1, s.length());        		
        	}
        } catch (EOFException ignore) {}
        
        extractedFile.createNewFile();
        //extract:
		try (FileOutputHelper fo = new FileOutputHelper(extractedFile)) {
			fo.writeString(operator.extract(compressed, encodingArray));
		}
		
		System.out.println("Путь к распакованному файлу " + extractedFile.getAbsolutePath());
    }
}

Mau ano e tuhi te konae readme.txt :)

mutunga

Te mana'o nei au koira anake taku i hiahia ki te korero. Mena kei a koe tetahi korero mo taku ngoikoretanga ki te whakapai ake i te waehere, te algorithm, te arotautanga ranei i te nuinga, katahi ka pai ki te tuhi. Mena kaore au i whakamarama i tetahi mea, tuhia mai ano. E pai ana ahau ki te whakarongo mai i a koe i roto i nga korero!

PS

Ae, ae, kei konei tonu ahau, na te mea kaore au i wareware ki te whakarea. Mo te aho s1, he 48 paita te taumaha o te teepu whakawaehere - he nui ake i te konae puna, a kaore matou i wareware ki nga taapiri taapiri (ko te maha o nga koo taapiri ko te 7) => ka iti iho te tauwehenga kōpeketanga i te kotahi: 176/ (65 + 48*8 + 7) = 0.38. Mena i kite ano koe i tenei, ehara i te mea ko to kanohi anake te mea pai. Ae, ka tino koretake tenei whakatinanatanga mo nga konae iti. Engari ka aha ki nga konae nui? He nui ake nga rahi o nga konae i te rahi o te ripanga whakawaehere. Koinei te waahi e mahi ana te algorithm e tika ana! Hei tauira, mo Ko te korero takitahi a Faust Ka whakaputahia e te pūranga he whakarea tūturu (kaore i tino tika) 1.46 - tata ki te kotahi me te haurua nga wa! Ae, me kii he reo pakeha te konae.

Source: will.com

Tāpiri i te kōrero