Обработка дополнительных байтов при сжатии / распаковке по Хаффману

#c #data-structures #visual-studio-2017 #huffman-code

#c #структуры данных #visual-studio-2017 #хаффман-код

Вопрос:

У меня есть программа, которая создает дерево Хаффмана на основе частоты чтения символов ASCII в текстовом файле ввода. Коды Хаффмана хранятся в строковом массиве из 256 элементов, пустой строке, если символ не прочитан. Затем эта программа также кодирует и сжимает выходной файл и в настоящее время обладает некоторыми функциональными возможностями при распаковке и декодировании.

Вкратце, моя программа принимает входной файл, сжимает и кодирует выходной файл, закрывает выходной файл и открывает кодировку в качестве входного файла, и принимает новый выходной файл, который должен содержать декодированное сообщение, идентичное исходному текстовому файлу ввода.

Моя проблема в том, что в моем тестовом запуске во время сжатия я замечаю, что у меня есть 3 дополнительных байта, и, в свою очередь, когда я распаковываю и декодирую свой закодированный файл, эти 3 дополнительных байта декодируются в мой выходной файл. В зависимости от объема текста в исходном входном файле мои другие тесты выводят эти дополнительные байты.

Мои исследования привели меня к нескольким предложениям, таким как превращение первых 8 байт вашего закодированного выходного файла в 64 бита беззнакового long long, которые задают количество байтов в файле, или использование псевдо-EOF, но я застрял на том, как бы я с этим справился, и какой из двух способов является разумным, учитывая код, который я уже написал, или любой из них вообще является разумным способом?

Приветствуются любые рекомендации или решение этой проблемы.

(Для функции encodedOutput fileName является параметром входного файла, fileName2 является параметром выходного файла)

(Для функции decodeOutput fileName2 является параметром входного файла, fileName 3 является параметром выходного файла)

code[256] является параметром для обеих этих функций и содержит код Хаффмана для каждого уникального символа, прочитанного в исходном входном файле, например, символ ‘H’, считываемый во входном файле, может иметь код «111», сохраненный в массиве code для code[72] во время его передачи функциям.

freq[256] содержит частоту каждого считываемого символа ascii или 0, если его нет в исходном входном файле.

 void encodeOutput(const string amp; fileName, const string amp; fileName2, string code[256]) {
    ifstream ifile; //to read file
    ifile.open(fileName, ios::binary);
    if (!ifile)//to check if file is open or not
    {
        die("Can't read again"); // function that exits program if can't open
    }
    ofstream ofile;
    ofile.open(fileName2, ios::binary);
    if (!ofile) {
        die("Can't open encoding output file");
    }
    int read; 
    read = ifile.get(); //read one char from file and store it in int
    char buffer = 0, bit_count = 0;
    while (read != -1) {//run this loop until reached to end of file(-1)
        for (unsigned b = 0; b < code[read].size(); b  ) { // loop through bits (code[read] outputs huffman code)
            buffer <<= 1;
            buffer |= code[read][b] != '0';
            bit_count  ;
            if (bit_count == 8) {
                ofile << buffer;
                buffer = 0;
                bit_count = 0;
            }
        }
        read = ifile.get();
    }

    if (bit_count != 0)
        ofile << (buffer << (8 - bit_count));

    ifile.close();
    ofile.close();
}

void decodeOutput(const string amp; fileName2, const string amp; fileName3, string code[256], const unsigned long long freq[256]) {
    ifstream ifile;
    ifile.open(fileName2, ios::binary);
    if (!ifile)
    {
        die("Can't read again");
    }
    ofstream ofile;
    ofile.open(fileName3, ios::binary);
    if (!ofile) {
        die("Can't open encoding output file");
    }
    priority_queue < node > q;
    for (unsigned i = 0; i < 256; i  ) {
        if (freq[i] == 0) {
            code[i] = "";
        }
    }

    for (unsigned i = 0; i < 256; i  )
        if (freq[i])
            q.push(node(unsigned(i), freq[i]));

    if (q.size() < 1) {
        die("no data");
    }

    while (q.size() > 1) {
        node *child0 = new node(q.top());
        q.pop();
        node *child1 = new node(q.top());
        q.pop();
        q.push(node(child0, child1));
    } // created the tree
    string answer = "";
    const node * temp = amp;q.top(); // root 
    for (int c; (c = ifile.get()) != EOF;) {
        for (unsigned p = 8; p--;) { //reading 8 bits at a time 
            if ((c >> p amp; 1) == '0') { // if bit is a 0
                temp = temp->child0; // go left
            }
            else { // if bit is a 1
                temp = temp->child1; // go right
            }
            if (temp->child0 == NULL amp;amp; temp->child1 == NULL) // leaf node
            {
                answer  = temp->value;
                temp = amp;q.top();
            }
        }
    }
  ofile << ans;
}
  

Ответ №1:

Из-за правил комплексного продвижения, (buffer << (8 - bit_count)) будет целочисленным выражением, в результате чего будет записано 4 байта. Чтобы записать только один байт, вам нужно преобразовать его в символ.

 ofile << char(buffer << (8 - bit_count));