Arquivos Binários Like C com Python

Quanto tempo hein?

Bom estive enrrolado pra caramba ultimamente, correria, trabalho, faculdade, livros, assuntos pessoais e etc.

Bem hoje vamos ver como gravar arquivos em C usando structs e como ler / gravar esses caras com Python.

Primeiramente vamos ver como gravar e ler um arquivo binário em C. Os comandos necessários serão:

  • fopen
  • fclose
  • fseek
  • ftell
  • fread
  • fwrite

fopen() – Tem a finalidade de abrir o arquivo e retornar um ponteiro do tipo FILE que possibilita a manipulação dos bytes. Recebe dois parâmetros sendo o primeiro parâmetro o  caminho para o arquivo. Ex: “C:\texto.txt”. O segundo parâmetro é uma String com o modo que você irá abrir o arquivo. Ex:

r” para somente leitura, “w” para gravação ( cria o arquivo / sobrescreve os dados anteriores )

a” adiciona os dados no final do arquivo , existem outras variações desses comandos utilizando o +. Ficando “r+“, “w+” e “a+” que não entrarei em detalhes.

fclose() – Tem a finalidade de fechar o arquivo e finalizar a manipulação do mesmo.

fseek() – Tem a finalidade de movimentar o ponteiro do tipo FILE, ou seja ele vai “andar” entre os bytes do arquivo. Ele recebe 3 parâmetros, o primeiro é o ponteiro do tipo FILE do arquivo que vamos manipular, o segundo é a quantidade de bytes que ele irá utilizar para se deslocar, e por último ele recebe uma constante identificando a referência para essa modificação que pode ser de 3 maneiras.

SEEK_SET fará a movimentação a partir do início do arquivo.

SEEK_CUR fará a movimentação a partir da posição atual do ponteiro FILE.

SEEK_END fará as movimentações a partir do final do arquivo.

ftell() – Tem a finalidade de retornar o byte que o ponteiro do tipo FILE está apontando. Recebe o ponteiro do tipo FILE como parâmetro.

 

fread() – Tem como finalidade realizar a leitura dos dados binários para uma estrutura ou ponteiros, variáveis, etc. (No exemplo utilizaremos uma struct). Recebe 4 parêmetros, sendo o primeiro o endereço que receberá o valor que será retornado pela leitura, o segundo é o tamanho / quantidade dos bytes a serem lidos, o próximo parâmetro é a quantidade de elementos que serão lidos, e por fim o ponteiro do tipo FILE.

fwrite() – Tem como finalidade realizar a gravação dos dados binários em uma sequencia de bytes no arquivo. Recebe 4 parêmetros, sendo o primeiro o endereço que passará os valores que serão gravados, o segundo é o tamanho / quantidade dos bytes a serem gravados, o próximo parâmetro é a quantidade de elementos que serão gravados, e por fim o ponteiro do tipo FILE.

Com essa base podemos começar com um exemplo simples de gravação e leitura com C, e uma estrutura simples.

 


#import <stdio.h>
#import <stdlib.h>
#import <string.h>

struct pessoa{
    int codigo;
    char nome[100];
};

int main(){
    FILE *arquivo = fopen("dados.dat","w");
    struct pessoa aux;
    //Processo de gravação
    if( arquivo != NULL ) {
        //arquivo conseguiu ser criado
        printf("Digite o codigo:");
        scanf("%i", &aux.codigo);//Lendo o codigo
        printf("Digite o nome:");
        scanf("%s", &aux.nome);//Lendo o nome
        //sizeof(struct pessoa)//Retorna o tamanho da estrutura em bytes
        fwrite(&aux, sizeof(struct pessoa), 1, arquivo);
        fclose(arquivo);//Fechando arquivo
        //Limpando os dados da variavel pessoa
        aux.codigo = 0;
        strcpy(aux.nome, "");//Grava o conteúdo vazio no aux.nome (tratativa necessária em C)
    }
    //Print da variável vazia
    printf(" %i  %s ", aux.codigo, aux.nome);
    printf("\n");//Quebra-Linha
    //Processo de Leitura
    arquivo = fopen("dados.dat", "r");
    if ( arquivo != NULL ){
        fread(&aux, sizeof(struct pessoa), 1, arquivo);
        //Notaram a semelhança com a gravação?
        printf(" %i  %s ", aux.codigo, aux.nome);
        fclose(arquivo);
    }
    return 1;
}

Caso queira testar o código em C sem um compilador e IDE pode utilizar esse link e colar o código.

PS: ftell e fseek são utilizados  quando se há mais de um registro para navegar entre os bytes.
Ex:


fseek(arquivo, 0, SEEK_END);// Movimentaria o ponteiro do arquivo para o final do arquivo

int tamanho = fteel();//Retornaria o tamanho em bytes (se executado após o comando acima)

fseek(arquivo, tamanho - sizeof(struct pessoa), SEEK_SET);//Iria voltar o ponteiro para a posição do último registro

//Nota-se também que não estou testando caso o arquivo esteja vazio, caso o arquivo tenha um registro o mesmo será o último

 

Bem depois de explicado a parte complicada utilizando C, vamos fazer a mesma implementação com Python

A única explicação que devo fazer é com relação a estrutura utilizada, temos códigos para cada tipo correspondente em C. Sendo eles:

Format C Type Python type Standard size Notes
x pad byte no value
c char string of length 1 1
b signed char integer 1 (3)
B unsigned char integer 1 (3)
? _Bool bool 1 (1)
h short integer 2 (3)
H unsigned short integer 2 (3)
i int integer 4 (3)
I unsigned int integer 4 (3)
l long integer 4 (3)
L unsigned long integer 4 (3)
q long long integer 8 (2), (3)
Q unsigned long long integer 8 (2), (3)
f float float 4 (4)
d double float 8 (4)
s char[] string
p char[] string
P void * integer (5), (3)

Existe também o detalhe quando se trabalha com várias plataformas diferentes e os arquivos deverão ser lidos por qualquer uma delas, que é o caso dos endian que não vou chegar a explicar, mas para mais detalhes clique aqui


# *-* coding:utf-8 *-*
import struct
from collections import namedtuple

# como temos um inteiro para o código ('i') e depois o array de chars de 100 posições ('100s')
formato = 'i100s'

#definindo a estrutura com namedtuple
Pessoa = namedtuple("Pessoa", "codigo nome")

tamanho_estrutura = struct.calcsize(formato) # Retorna o tamanho de um elemento no formato passado

#Gravando os dados
with open("dados.dat", "wb") as f:
    codigo = int(raw_input("Digite o codigo:"))
    nome = raw_input("Digite o nome:")
    pessoa = Pessoa(codigo=codigo, nome=str.encode(nome))
    f.write( struct.pack( formato, *pessoa )  )
    print(pessoa)

#Lendo os dados
with open("dados.dat", "rb") as f:
    dados = f.read()#Todos os bytes foram lidos
    codigo, nome = struct.unpack( formato, dados[0:tamanho_estrutura ] )# Lê do byte 0 até o tamanho do arquivo (primeiro elemento)
    nome = nome.split("\0")[0] # Como o C utiliza o \0 para terminar uma string no python precisamos tratar isso
    pessoa = Pessoa(codigo=codigo, nome=nome)
    print(pessoa)

Ps: se estiver utilizando Python3 troque raw_input por input

Espero que tenham gostado, e agora vocês podem brincar mais com os programas modificar, quem sabe só o programa em C vai gravar, e o programa em Python vai ler o arquivo, etc

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s