Ir ao conteúdo

Posts recomendados

Postado

Boa noite, estou criando um compactador de arquivos e para manipular o arquivo eu preciso ler e manipular os bits do arquivo, andei pesquisando como ler arquivos com ofstream e ifstream, o problema é que eu ainda não entendi como ter acesso aos bits puros, os 0 e 1 do arquivo, nos exemplos que vi na internet só fala de ler campos ou variáveis em nenhum lugar fala de como ler os bits propriamente ditos.

  Depois de ler eu teria que escrever, também como eu escreveria os zeros e uns direto no disco rígido direto no arquivo, por exemplo, eu preciso ler o primeiro bit do arquivo aí viria (01101010) aí eu escreveria um novo arquivo com (10010101)(um byte por vez) mas como eu escreveria esses bits exatos que são o que eu quero??? E depois teria que ler e escrever o próximo byte até chegar no final do arquivo...

  Só consegui ler e escrever texto...

  • Amei 1
Postado
6 horas atrás, kleberaugus disse:

Boa noite, estou criando um compactador de arquivos e para manipular o arquivo eu preciso ler e manipular os bits do arquivo, andei pesquisando como ler arquivos com ofstream e ifstream, o problema é que eu ainda não entendi como ter acesso aos bits puros, os 0 e 1 do arquivo, nos exemplos que vi na internet só fala de ler campos ou variáveis em nenhum lugar fala de como ler os bits propriamente ditos

 

Você não vai "manipular os bits do arquivo". Vai procurar ler grandes partes do arquivo e vai manipular as variáveis na memória, por eficiência. Ainda que pudesse ler bits ainda seriam em campos conhecidos como variáveis.

 

Usar streams é uma opção. Claro que não pode ler arquivos com ofstream, certo? Apenas ifstream. Não precisa necessariamente usar streams. Pode usar fopen() mesmo.

 

O algoritmo que vai usar vai determinar como é melhor ler. Se vai compactar em blocos, tipo z-modem 8K nos anos 90, RLE, zip... De todo modo vai alocar buffers, arrays de tamanho adequado para ir montando a saída. E vai declarar buffers de entrada onde vai ler um número possivelmente maior de bytes, bem maior. 

 

E vai usar ponteiros para ir navegando na entrada e gerando a saída conforme os blocos compactados forem ficando prontos.

Estou escrevendo de memória e espero que faça sentido. 

 

O simples é criar uma classe, digamos Compacta, e no construtor pode declarar os arquivos de entrada e saída e algum parâmetro eventual de configuração e campos de métrica, que é o que geralmente se faz.

  • Curtir 1
Postado

Tudo isso que você falou eu fiz, o problema é que essa droga só lê e escreve em arquivo txt, quando leio ou escrevo com outra extensão simplesmente não acontece nada.

 

	ifstream inFile("C:/Users/klebe/Desktop/teste.kle", ios::binary);
	if (inFile) {
		// get length of file:
		inFile.seekg(0, inFile.end);
		int length = inFile.tellg();
		inFile.seekg(0, inFile.beg);



		// allocate memory:
	
		char* buffer = new char[length]; //Lê no máximo 7 bits, o oitavo deve ser sinal só até 127

		inFile.read(buffer, 1); //ler quantos bytes? Preciso ler 1 por vez.

Ler um byte por vez é só para teste.

  • Curtir 1
Postado
2 horas atrás, kleberaugus disse:

Tudo isso que você falou eu fiz, o problema é que essa droga só lê e escreve em arquivo txt, quando leio ou escrevo com outra extensão simplesmente não acontece nada.

 

 

Não me leve a mal, mas talvez você devesse ver essas coisas de outro modo. Ainda pode ser cedo para você diferenciar "essa droga" de algo que você ainda não entende direito.

 

streams são orientadas para texto mesmo. Por definição. E operam com buffers para eficiência. E são mesmo eficientes. Mas podem trabalhar com bytes. Não bits ;)

 

Aparentemente copiou seu programa do exemplo postado em http://www.cplusplus.com/reference/istream/istream/read/ e digitou em cima

 

image.png.972b4326c4b74449f377dd1500352ce9.png

 

Mas talvez nem precise disso. Vou te mostrar outro exemplo, que eu escrevi agora mesmo, e é quase igual porque é pra fazer a mesma coisa ;) 

 

Rode em sua máquina. 

 

O exemplo:

    copie [entrada] [saida] 

Claro que 'copie' é o nome do programa. E ele copia da entrada para a saída. Os dois parâmetros são opcionais, então você pode usar

  copie	// tenta copiar 'teste.png' para 'copia.png'
  copie azul.txt // tenta copiar azul.txt para 'copia.png'
  copie azul.txt verde.bmp // tenta copiar 'azul.txt' para 'verde.bmp'

O simples: se não der nenhum parâmetro na linha ele procura 'teste.png' no diretório corrente e copia para 'copia.png' no diretório corrente. Mas copia qualquer arquivo já que opera em fluxos --- streams --- binários.

 

Como o exemplo que usou, aloco um buffer de tamanho variável. No caso 64k = 65536 bytes. Entenda que streams já operam com buffer então provavelmente estaria bem lendo byte a byte.

 

Então o programa copia o arquivo de entrada para o arquivo de saída, em blocos de 64K. Ao final libera o bloco e fecha os arquivos

 

Veja o loop de cópia:

    while (!in.eof())
    {
        in.read(buffer, bloco);
        if (in.gcount())
        {   // leu algo
            cout << in.gcount() << endl;
            total = total + in.gcount();
            out.write(buffer, in.gcount());
        };  // if()
    };  // while()
    in.close();
    out.close();
    delete[] buffer;

O simples. No seu caso ao invés de só copiar o conteúdo de buffer igualzinho para a saída você cria uma função de compressão e passa o resultado dela para o write. Algo assim

    int comprime(char* in, unsigned N, char* out);

E escreve, supondo que comprime retorna o tamanho do buffer comprimido

    
    out.write(
      outro_buffer, 
      comprime(buffer,in.gcount(),outro_buffer)
    );

Ou faz algo mais elaborado gravando em blocos na saída também.
 

Porque 'teste.png'?


Porque eu quis. Era um arquivo binário que tinha na minha pasta agora que eu fiz o programa. Mas o programa aceita parâmetros na linha de comando então copia de A pra B qualquer coisa. teste.png tem 109.080 bytes


Rodando o exemplo

65536
43544
Copiados 109080 bytes de 'teste.png' para 'copia.png'

O exemplo

#include <iostream>
#include <fstream>
using namespace std;

int main(int argc, char** argv)
{
    constexpr std::streamsize bloco = 65'536; // 64K
    char* buffer = new char[bloco]; 
    ifstream in;
    ofstream out;
    std::string entrada = "teste.png";
    std::string saida = "copia.png";
    if (argc > 2) saida = argv[2];
    if (argc > 1) entrada = argv[1];
    unsigned long total = 0;
    in.open( entrada, ios::binary | ios::in);
    if (!in)
    {
        cout << "Erro tentando abrir " << entrada;
        return -1;
    };  // if()

    out.open(saida, ios::binary | ios::out | ios::trunc );
    if (!out)
    {
        cout << "Erro tentando criar " << saida;
        in.close();
        return -2;
    };  // if()

    while (!in.eof())
    {
        in.read(buffer, bloco);
        if (in.gcount())
        {   // leu algo
            cout << in.gcount() << endl;
            total = total + (long) in.gcount();
            out.write(buffer, in.gcount());
        };  // if()
    };  // while()
    in.close();
    out.close();
    delete[] buffer;
    cout << "Copiados " << total << " bytes de '" <<
        entrada << "' para '" << saida << "'" << endl;
    return 0;
};

 

É só um exemplo, sem qualquer pretensão de eficiência e tal. Espero que ajude.

 

 

  • Obrigado 1
  • 2 semanas depois...
Postado

@arfneto

Ajudou muito sim, muito obrigado, era o que eu queria: um exemplo de leitura e gravação que funciona, na internet tem muita informação incompleta.

  Aí eu tentei modificar seu código para fazer o que eu queria: tratar os bytes e depois gravar, o que eu pretendo fazer: pegar cada byte do buffer (tipo buffer[0], buffer[1]... até chegar no último, transformar os bytes em Strings, modificar sua ordem conforme meu algoritmo, transformar de volta em char e finalmente gravar no arquivo.

  Problemas:

 1) ao ler os bytes do buffer só vem 7 bits, gravo com 7 bits mesmo ou tenho que acrescentar o último bit (seria 0 ou 1)?-> não pude testar porque está dando algo errado com meu código.

  2) Como eu converteria de string para char novamente, com 7 ou 8 bits?

 

Falta pouco para meu programa decolar, mas esse pouco está travando tudo (estou emaranhado nessa parte técnica).

 

O código que eu acrescentei:

 

Vou tentar de outras formas, mas nesse código que eu fiz por algum motivo não está gerando a string!


                                          //Meu algoritmo
            
            if (contador == 1) {
                for (aux = 7; aux > 0; aux--)
                {
                    if (buffer[1] % 2 == 0) {    //Essa é a posição do buffer do byte a ser convertido em binario
                        bin[aux] = 0;
                    }//fim do if
                    else {
                        bin[aux] = 1;
                        buffer[1] = buffer[1] / 2;    //Essa é a posição do buffer do byte a ser convertido em binario
                    }//fim do else
                }//fim do for
               
                inteiro = bin[7] + bin[6] * 2 + bin[5] * 4 + bin[4] * 8 + bin[3] * 16 + bin[2] * 32 + bin[1] * 64 + bin[0] * 128;  //o binario é transformado em inteiro
                while (inteiro > 0) {
                    binario = to_string(inteiro % 2) + binario;  //O binario é transformado em string
                    inteiro /= 2;


                }//fim do while
                printf_s("%s string", binario.c_str());//Binário na tela

            } //fim do primeiro if
                  contador++;
            

 

adicionado 46 minutos depois

@arfneto Deu certo transformar os bits do buffer em string, agora já consigo trata-los! A única dificuldade agora é transformar a string novamente em char! para gravar, e se só ter 7 bits tem algum problema.

Postado

@arfneto Estava estudando seu código, cheguei à conclusão que a parte que grava os bytes é essa:

out.write(buffer, in.gcount());

Aqui no caso ele grava o buffer da stream, mas eu conseguiria gravar bytes do meu próprio buffer (a informação que eu modifiquei)??

Postado
48 minutos atrás, kleberaugus disse:

Aqui no caso ele grava o buffer da stream, mas eu conseguiria gravar bytes do meu próprio buffer (a informação que eu modifiquei)??

 

Sim.

 

o primeiro parâmetro é o endereço, o segundo a quantia de bytes:

ostream& write (const char* s, streamsize n);

 

Postado

@arfneto

Acabei de conseguir o que queria aqui, não tenho nem palavras pra lhe agradecer!

A parte mais difícil eu venci, que era a parte técnica... faltou eu olhar a documentação e testar, mas seu código me abriu a mente!

Agora sim eu posso começar o trabalho, valeu!!!!!!!

  • Curtir 1

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!