Logo Passei Direto
Buscar

Compactador e descompactador de texto

User badge image

Enviado por Rod Barbosa em

Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original

compactador/descompactador.cpp
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <list>
#include <queue>
#include <deque>
#include <algorithm>
#include <time.h>
#include <conio.h>
#include "lebit.cpp"
using namespace std;
struct pnodo
{
 struct nodo *ptr;
};
const pnodo null = { 0 };
struct nodo
{
 char caractere;
 int frequencia;
 pnodo esq, dir, pai;
};
bool operator==(const pnodo &n1, const pnodo &n2)
{
	return n1.ptr->caractere == n2.ptr->caractere;
}
bool operator!=(const pnodo &n1, const pnodo &n2)
{
 return n1.ptr != n2.ptr;
}
bool operator>(const pnodo &n1, const pnodo &n2)
{
 return n1.ptr->frequencia > n2.ptr->frequencia;
}
pnodo gera_arvore(priority_queue<pnodo, deque<pnodo>, greater<pnodo> >& fila)
{
 pnodo e1, e2, aux;
 while(!fila.empty())
 {
 e1 = fila.top(); fila.pop();
 if(fila.empty()) break;
 e2 = fila.top(); fila.pop();
 aux.ptr = new nodo;
 (aux.ptr)->frequencia = (e1.ptr)->frequencia + (e2.ptr)->frequencia;
 (aux.ptr)->esq = e1; (aux.ptr)->dir = e2;
 (aux.ptr)->pai = null;
 (e1.ptr)->pai = aux; (e2.ptr)->pai = aux;
 (aux.ptr)->caractere = 0;
 fila.push(aux);
 }
 return e1;
}
int main ()
{
	pnodo raiz;
	FILE *ent, *sai;
	ent = fopen("teste_sai.bin", "rb");
	
	if (ent == NULL)
	{
		cout <<"Nao pude abrir o arquivo";
		exit(1);
	}
	
	sai = fopen("descompactado.txt", "w");
	if (sai == NULL)
	{
		cout <<"Nao pude criar o arquivo de saida.";
		exit(1);
	}
	
	int numPares;
	fread(&numPares, sizeof(int), 1, ent);
	cout << numPares << endl;
	
	priority_queue< pnodo, deque<pnodo>, greater<pnodo> > fila;
	char carac;
	int freq;
	pnodo aux;
	
	for (int x = 0; x < numPares; x++)
	{
		fread(&carac, sizeof(char), 1, ent);
		fread(&freq, sizeof(int), 1, ent);
		cout << carac << " " << freq << endl;
		aux.ptr = new nodo;
		aux.ptr -> caractere = carac;
		aux.ptr -> frequencia = freq;
		aux.ptr -> esq = null;
		aux.ptr -> dir = null;
		fila.push(aux);
	}
	raiz = gera_arvore(fila);
	int numbit;
	fread(&numbit, sizeof(int), 1, ent);
	cout << numbit << endl;
	pnodo aux1 = raiz;
	byte bit;
	
	for (int x = 0;x < numbit; x++)
	{
		//ler bit do arquivo de entrada
		bit = le_bit(ent);
		
		//escreve o bit
		cout<<(int)bit;
		if (bit == 1)
		{
			aux1 = aux1.ptr -> esq;
		}
		else
		{
			aux1 = aux1.ptr -> dir;
		}
		
		//escreve o caractere no arquivo
		if (!(aux1.ptr -> dir != null) && !(aux1.ptr -> esq != null))
		{
			fwrite(&(aux1.ptr->caractere), sizeof(char), 1, sai);
			aux1 = raiz;
		}
	}
	fcloseall();
	cout <<"\nFim da operaçao.";
	getch();
	
	//o texto descompactado so pode ser visto abrindo o arquivo descompactado.txt
}
compactador/descompactado.txt
compactador/teste.txt
abracadabra
compactador/teste_sai.bin
compactador/lebit.cpp
typedef unsigned char byte;
byte le_bit (FILE *f){
 static byte buffer; //Não perde o valor da variável após encerrar a função (static BUFFER)
 static int cont=0; //local com escopo global
 if(cont==0){
 fread(&buffer, sizeof(byte),1,f);
 cont=8;
 }
 byte res=(byte)(buffer<<(8-cont))>>7;
 --cont;
 return res; //simplificando: return (byte)(buffer<<(8-cont--))>>7;
}
compactador/principal.cpp
//
// Compactador Huffman
// Código desenvolvido pelo Prof. Marcos Vinícius da Silva
// baseado no livro "Algorithms in C++" de Robert Sedgewick
//
// Versão para Visual Studio
//
//Comente esta linha para gerar o código sem saída de depuração
#define DEBUG
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <list>
#include <queue>
#include <deque>
#include <algorithm>
#include <conio.h>
#include <time.h>
static char nome_arquivo_entrada[]="teste.txt";
#ifndef DEBUG
using namespace std;
struct pnodo
{
 struct nodo *ptr;
};
const pnodo null = { 0 };
struct nodo
{
 char caractere;
 int frequencia;
 pnodo esq, dir, pai;
};
bool operator==(const pnodo &n1, const pnodo &n2)
{
	return n1.ptr->caractere == n2.ptr->caractere;
}
bool operator!=(const pnodo &n1, const pnodo &n2)
{
 return n1.ptr != n2.ptr;
}
bool operator>(const pnodo &n1, const pnodo &n2)
{
 return n1.ptr->frequencia > n2.ptr->frequencia;
}
list<pnodo> conta_frequencia(ifstream &f)
{
 list<pnodo> l;
 list<pnodo>::iterator pos;
 pnodo aux;
 aux.ptr = new nodo;
 f.get(aux.ptr->caractere);
 while(!f.eof())
 {
 aux.ptr->esq = aux.ptr->dir = null;
 pos = find(l.begin(), l.end(), aux);
 if(pos != l.end())
 {
 (*pos).ptr->frequencia++;
 delete aux.ptr;
 }
 else {
 aux.ptr->frequencia = 1;
 l.insert(l.end(), aux);
 }
	aux.ptr = new nodo;
 f.get(aux.ptr->caractere);
 }
 delete aux.ptr;
 return l;
}
void copia_lista(const list<pnodo>& lista,
 priority_queue<pnodo, deque<pnodo>, greater<pnodo> >& fila)
{
 list<pnodo>::const_iterator i;
 i = lista.begin();
 while(i != lista.end())
 {
 fila.push(*i);
 i++;
 }
}
pnodo gera_arvore(priority_queue<pnodo, deque<pnodo>, greater<pnodo> >& fila)
{
 pnodo e1, e2, aux;
 while(!fila.empty())
 {
 e1 = fila.top(); fila.pop();
 if(fila.empty()) break;
 e2 = fila.top(); fila.pop();
 aux.ptr = new nodo;
 (aux.ptr)->frequencia = (e1.ptr)->frequencia + (e2.ptr)->frequencia;
 (aux.ptr)->esq = e1; (aux.ptr)->dir = e2;
 (aux.ptr)->pai = null;
 (e1.ptr)->pai = aux; (e2.ptr)->pai = aux;
 (aux.ptr)->caractere = 0;
 fila.push(aux);
 }
 return e1;
}
void grava_frequencias(list<pnodo> &freqs, FILE *arq)
{
 list<pnodo>::iterator i = freqs.begin();
 while(i!=freqs.end())
 {
 char c = (*i).ptr->caractere;
 int f = (*i).ptr->frequencia;
 fwrite(&c, sizeof(char), 1, arq);
 fwrite(&f, sizeof(int), 1, arq);
 i++;
 }
}
void escreve_bit(FILE *f, unsigned char bit)
{
 static unsigned char valor=0, cont=1;
 if(cont < sizeof(char)*8)
 {
 valor = (unsigned char) (valor << 1) | bit;
 cont++;
 }
 else
 {
 valor = (unsigned char) (valor << 1) | bit;
 fwrite(&valor, sizeof(char), 1, f);
 cont=1; valor=0;
 }
}
list<unsigned char> obtem_codigo(char c, list<pnodo> &arv)
{
 list<pnodo>::iterator pos;
 list<unsigned char> bits;
 unsigned char bit;
 nodo aux;
 pnodo paux;
 aux.caractere = c;
 paux.ptr = &aux;
 pos = find (arv.begin(), arv.end(), paux);
 paux = *pos;
 bits.clear();
 while((paux.ptr->pai != null))
 {
 if(!(paux != paux.ptr->pai.ptr->esq))
 bit = 1;
 else
 bit = 0;
 bits.insert(bits.begin(), bit);
 paux = paux.ptr->pai;
 }
 return bits;
}
unsigned int codifica_arquivo(list<pnodo> &arv, ifstream &ent, FILE *sai)
{
 list<unsigned char> codigo;
 list<unsigned char>::iterator i;
 unsigned int contabits=0;
 char c;
 ent.close();
 ent.open(nome_arquivo_entrada);
 ent.get(c);
 while( ! ent.eof() ) {
 codigo = obtem_codigo(c, arv);
 i = codigo.begin();
 while(i != codigo.end()) {
 contabits++;
 escreve_bit(sai, *i++);
 }
	ent.get(c);
 }
 for(unsigned int i=0; i<8-(contabits%8); i++) { // completa o ultimo byte
 escreve_bit(sai, 0);
 }
 return contabits;
}
int main()
{
 list<pnodo> freqs;
 priority_queue< pnodo, deque<pnodo>, greater<pnodo> > fp;
 FILE *arq_sai;
 pnodo raiz;
 long tamanho1=0, bits=0;
 int num_nodos;
 clock_t ini, fim;
 ini = clock();
 ifstream arq_ent(nome_arquivo_entrada);
 if (! arq_ent.is_open() ) {
	 cout << "Não pude abrir o arquivo de entrada teste.txt";
	 getch();
	 exit(1);
 }
 arq_sai = fopen("teste_sai.bin", "wb");
 if (arq_sai == NULL) {
	 cout << "Não pude abrir o arquivo de saida teste_sai.bin";
	 getch();
	 exit(1);
 }
 freqs = conta_frequencia(arq_ent);
copia_lista(freqs, fp);
 raiz = gera_arvore(fp);
 num_nodos = freqs.size();
 fwrite(&num_nodos, sizeof(int), 1, arq_sai);
 grava_frequencias(freqs, arq_sai);
 tamanho1 = ftell(arq_sai);
 fwrite(&bits, sizeof(int), 1, arq_sai); // reserva espaço para o número de bits escritos
 bits = codifica_arquivo(freqs, arq_ent, arq_sai);
 fseek(arq_sai, tamanho1, SEEK_SET); // posiciona no local com o numero de bytes da codificacao
 fwrite(&bits, sizeof(int), 1, arq_sai); // grava o tamanho da codificacao (em bits)
 fcloseall();
 fim = clock();
 cout << "Tempo gasto: "<<(fim-ini)/CLOCKS_PER_SEC;
 getch();
 return 0;
}
#endif
//
//
//
#ifdef DEBUG
using namespace std;
struct pnodo
{
 struct nodo *ptr;
};
const pnodo null = { 0 };
struct nodo
{
 char caractere;
 int frequencia;
 pnodo esq, dir, pai;
};
bool operator==(const pnodo &n1, const pnodo &n2)
{
	return n1.ptr->caractere == n2.ptr->caractere;
}
bool operator!=(const pnodo &n1, const pnodo &n2)
{
 return n1.ptr != n2.ptr;
}
bool operator>(const pnodo &n1, const pnodo &n2)
{
 return n1.ptr->frequencia > n2.ptr->frequencia;
}
ostream& operator<<(ostream &o, const list<pnodo> &l)
{
 list<pnodo>::const_iterator i;
 i = l.begin();
 while(i != l.end())
 {
 o << (*i).ptr->caractere << " : " << (*i).ptr->frequencia << endl;
 i++;
 }
 return o;
}
ostream& operator<<(ostream &o, priority_queue<pnodo, deque<pnodo>, greater<pnodo> > pq)
{
 while(!pq.empty())
 {
 o << pq.top().ptr->caractere << "\t";
 pq.pop();
 }
 return o;
}
list<pnodo> conta_frequencia(ifstream &f)
{
 list<pnodo> l;
 list<pnodo>::iterator pos;
 pnodo aux;
 aux.ptr = new nodo;
 f.get(aux.ptr->caractere);
 while(!f.eof())
 {
 aux.ptr->esq = aux.ptr->dir = null;
 pos = find(l.begin(), l.end(), aux);
 if(pos != l.end())
 {
 (*pos).ptr->frequencia++;
 delete aux.ptr;
 }
 else {
 aux.ptr->frequencia = 1;
 l.insert(l.end(), aux);
 }
	aux.ptr = new nodo;
 f.get(aux.ptr->caractere);
 }
 delete aux.ptr;
 return l;
}
void copia_lista(const list<pnodo>& lista,
 priority_queue<pnodo, deque<pnodo>, greater<pnodo> >& fila)
{
 list<pnodo>::const_iterator i;
 i = lista.begin();
 while(i != lista.end())
 {
 fila.push(*i);
 i++;
 }
}
pnodo gera_arvore(priority_queue<pnodo, deque<pnodo>, greater<pnodo> >& fila)
{
 pnodo e1, e2, aux;
 while(!fila.empty())
 {
 e1 = fila.top(); fila.pop();
 if(fila.empty()) break;
 e2 = fila.top(); fila.pop();
 aux.ptr = new nodo;
 (aux.ptr)->frequencia = (e1.ptr)->frequencia + (e2.ptr)->frequencia;
 (aux.ptr)->esq = e1; (aux.ptr)->dir = e2;
 (aux.ptr)->pai = null;
 (e1.ptr)->pai = aux; (e2.ptr)->pai = aux;
 (aux.ptr)->caractere = 0;
 fila.push(aux);
 }
 return e1;
}
void imprime_arvore(pnodo r, int nivel)
{
 if(r.ptr)
 {
 imprime_arvore((r.ptr)->esq, nivel+1);
 for(int i=0; i<nivel; i++) cout << '\t'; // indentação
 if (!(r.ptr->esq != null) && !(r.ptr->dir!=null)) // escreve a raiz
 cout << (r.ptr)->caractere << endl;
 else
 cout << (r.ptr)->frequencia << endl;
 imprime_arvore((r.ptr)->dir, nivel+1);
 }
}
void grava_frequencias(list<pnodo> &freqs, FILE *arq)
{
 list<pnodo>::iterator i = freqs.begin();
 while(i!=freqs.end())
 {
 char c = (*i).ptr->caractere;
 int f = (*i).ptr->frequencia;
 fwrite(&c, sizeof(char), 1, arq);
 fwrite(&f, sizeof(int), 1, arq);
 i++;
 }
}
void escreve_bit(FILE *f, unsigned char bit)
{
 static unsigned char valor=0, cont=1;
 if(cont < sizeof(char)*8)
 {
 valor = (unsigned char) (valor << 1) | bit;
 cont++;
 }
 else
 {
 valor = (unsigned char) (valor << 1) | bit;
 fwrite(&valor, sizeof(char), 1, f);
 cont=1; valor=0;
 }
}
list<unsigned char> obtem_codigo(char c, list<pnodo> &arv)
{
 list<pnodo>::iterator pos;
 list<unsigned char> bits;
 unsigned char bit;
 nodo aux;
 pnodo paux;
 aux.caractere = c;
 paux.ptr = &aux;
 pos = find (arv.begin(), arv.end(), paux);
 paux = *pos;
 bits.clear();
 while((paux.ptr->pai != null))
 {
 if(!(paux != paux.ptr->pai.ptr->esq))
 bit = 1;
 else
 bit = 0;
 bits.insert(bits.begin(), bit);
 paux = paux.ptr->pai;
 }
 return bits;
}
unsigned int codifica_arquivo(list<pnodo> &arv, ifstream &ent, FILE *sai)
{
 list<unsigned char> codigo;
 list<unsigned char>::iterator i;
 unsigned int contabits=0;
 char c;
 ent.close();
 ent.open(nome_arquivo_entrada);
 ent.get(c);
 while( ! ent.eof() ) {
 codigo = obtem_codigo(c, arv);
 i = codigo.begin();
 cout << " ";
 while(i != codigo.end()) {
 contabits++;
 cout<<(int)*i;
 escreve_bit(sai, *i++);
 }
	ent.get(c);
 }
 for(unsigned int i=0; i<8-(contabits%8); i++) { // completa o ultimo byte
 escreve_bit(sai, 0);
 }
 return contabits;
}
int main()
{
 list<pnodo> freqs;
 priority_queue< pnodo, deque<pnodo>, greater<pnodo> > fp;
 FILE *arq_sai;
 pnodo raiz;
 long tamanho1=0, bits=0;
 int num_nodos;
 ifstream arq_ent(nome_arquivo_entrada);
 if (! arq_ent.is_open() ) {
	 cout << "Não pude abrir o arquivo de entrada teste.txt";
	 getch();
	 exit(1);
 }
 arq_sai = fopen("teste_sai.bin", "wb");
 if (arq_sai == NULL) {
	 cout << "Não pude abrir o arquivo de saida teste_sai.bin";
	 getch();
	 exit(1);
 }
 freqs = conta_frequencia(arq_ent);
 cout << freqs; //depuração
 copia_lista(freqs, fp);
 cout << endl << "Fila: \t" << fp << endl << endl; //depuração
 raiz = gera_arvore(fp);
 imprime_arvore(raiz, 0); //depuração
 num_nodos = freqs.size();
 fwrite(&num_nodos, sizeof(int), 1, arq_sai);
 grava_frequencias(freqs, arq_sai);
 tamanho1 = ftell(arq_sai);
 cout << "\nBytes do Código: "<<ftell(arq_sai); //depuração
 cout << endl; // debug
 fwrite(&bits, sizeof(int), 1, arq_sai); // reserva espaço para o número de bits escritos
 bits = codifica_arquivo(freqs, arq_ent, arq_sai);
 cout << "\nNúmero de Bits Codificados: " << bits << endl;
 cout << "\nTamanho total do arquivo compactado: "<<ftell(arq_sai)<<" bytes";
 fseek(arq_sai, tamanho1, SEEK_SET); // posiciona no local com o numero de bytes da codificacao
 fwrite(&bits, sizeof(int), 1, arq_sai); // grava o tamanho da codificacao (em bits)
 fcloseall();
 getch();
 return 0;
}
#endif

Teste o Premium para desbloquear

Aproveite todos os benefícios por 3 dias sem pagar! 😉
Já tem cadastro?