Diferenças
Aqui você vê as diferenças entre duas revisões dessa página.
Ambos lados da revisão anterior Revisão anterior | |||
c:arquivos_binarios [2023/08/01 20:10] – edição externa 127.0.0.1 | c:arquivos_binarios [2023/08/15 14:52] (atual) – maziero | ||
---|---|---|---|
Linha 1: | Linha 1: | ||
+ | ====== Arquivos binários ====== | ||
+ | |||
+ | {{ progc_arquivos_binarios.mkv |Video desta aula}} | ||
+ | |||
+ | Todos os arquivos contêm sequências de bytes, mas costuma-se dizer que um arquivo é " | ||
+ | |||
+ | Em C, um arquivo binário é visto como uma sequência de blocos de mesmo tamanho. O tamanho dos blocos depende do tipo de informação armazenada no arquivo. Por exemplo, um arquivo de números reais '' | ||
+ | |||
+ | {{ binary-files.png |Blocos em arquivos binários}} | ||
+ | |||
+ | <note important> | ||
+ | Lembre-se que o SO só armazena a sequência de bytes, sem considerar nem registrar o tamanho dos blocos. **Cabe à aplicação** definir o tamanho de bloco que deseja usar em cada arquivo. | ||
+ | </ | ||
+ | |||
+ | ==== Leitura/ | ||
+ | |||
+ | A linguagem C oferece funções para ler e escrever blocos de bytes em arquivos, que efetuam a cópia desses bytes da memória para o arquivo ou vice-versa. | ||
+ | |||
+ | A funções a seguir permitem ler/ | ||
+ | |||
+ | Lê até '' | ||
+ | |||
+ | <code c> | ||
+ | size_t fread (void* data, size_t size, size_t count, FILE* stream) | ||
+ | </ | ||
+ | |||
+ | Escreve até '' | ||
+ | |||
+ | <code c> | ||
+ | size_t fwrite (const void* data, size_t size, size_t count, FILE* stream) | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | Essas funções também podem ser usadas para ler/ | ||
+ | </ | ||
+ | |||
+ | ==== Exemplo de uso ==== | ||
+ | |||
+ | Este exemplo manipula um arquivo binário '' | ||
+ | |||
+ | <code c escreve.c> | ||
+ | // Escreve N valores reais aleatórios em um arquivo, em formato binário | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | #define ARQUIVO " | ||
+ | #define NUMVAL 10 | ||
+ | |||
+ | int main (int argc, char *argv[]) | ||
+ | { | ||
+ | FILE* arq ; | ||
+ | int i, ret ; | ||
+ | float value[NUMVAL] ; | ||
+ | |||
+ | // abre o arquivo em modo " | ||
+ | arq = fopen (ARQUIVO, " | ||
+ | if (!arq) | ||
+ | { | ||
+ | perror ("Erro ao abrir arquivo" | ||
+ | exit (1) ; | ||
+ | } | ||
+ | |||
+ | // inicia gerador de números aleatórios | ||
+ | srand (clock()) ; | ||
+ | |||
+ | // gera NUMVAL valores aleatórios reais | ||
+ | for (i = 0; i < NUMVAL; i++) | ||
+ | value[i] = random() / 100000.0 ; | ||
+ | |||
+ | // escreve os valores gerados no final do arquivo | ||
+ | ret = fwrite (value, sizeof (float), NUMVAL, arq) ; | ||
+ | if (ret) | ||
+ | printf (" | ||
+ | else | ||
+ | printf ("Erro ao gravar...\n" | ||
+ | |||
+ | // fecha o arquivo | ||
+ | fclose (arq) ; | ||
+ | return (0) ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <code c lista.c> | ||
+ | // Lista o conteúdo de um arquivo que contém números reais em formato binário | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | #define ARQUIVO " | ||
+ | |||
+ | int main (int argc, char *argv[]) | ||
+ | { | ||
+ | FILE* arq ; | ||
+ | float value ; | ||
+ | |||
+ | // abre o arquivo em modo leitura | ||
+ | arq = fopen (ARQUIVO, " | ||
+ | if (!arq) | ||
+ | { | ||
+ | perror ("Erro ao abrir arquivo" | ||
+ | exit (1) ; | ||
+ | } | ||
+ | |||
+ | // lê e imprime os valores contidos no arquivo | ||
+ | fread (& | ||
+ | while (! feof (arq)) | ||
+ | { | ||
+ | printf (" | ||
+ | fread (& | ||
+ | } | ||
+ | |||
+ | // fecha o arquivo | ||
+ | fclose (arq) ; | ||
+ | return (0) ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <code c ordena.c> | ||
+ | // Lê os números reais de um arquivo binário, os ordena e os escreve de volta no arquivo | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | #define ARQUIVO " | ||
+ | #define MAXVAL 100000 | ||
+ | |||
+ | float value[MAXVAL] ; | ||
+ | int num_values ; | ||
+ | |||
+ | int main (int argc, char *argv[]) | ||
+ | { | ||
+ | FILE* arq ; | ||
+ | int i, j, menor ; | ||
+ | float aux ; | ||
+ | |||
+ | // abre o arquivo em leitura/ | ||
+ | arq = fopen (ARQUIVO, " | ||
+ | if (!arq) | ||
+ | { | ||
+ | perror ("Erro ao abrir arquivo" | ||
+ | exit (1) ; | ||
+ | } | ||
+ | |||
+ | // lê números do arquivo no vetor | ||
+ | num_values = fread (value, sizeof (float), MAXVAL, arq) ; | ||
+ | printf (" | ||
+ | |||
+ | // ordena os números (por seleção) | ||
+ | for (i = 0; i < num_values-1; | ||
+ | { | ||
+ | // encontra o menor elemento no restante do vetor | ||
+ | menor = i ; | ||
+ | for (j = i+1; j < num_values; j++) | ||
+ | if (value[j] < value[menor]) | ||
+ | menor = j ; | ||
+ | |||
+ | // se existe menor != i, os troca entre si | ||
+ | if (menor != i) | ||
+ | { | ||
+ | aux = value[i] ; | ||
+ | value[i] = value[menor] ; | ||
+ | value[menor] = aux ; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // retorna o ponteiro ao início do arquivo | ||
+ | rewind (arq) ; | ||
+ | |||
+ | // escreve números do vetor no arquivo | ||
+ | fwrite (value, sizeof (float), num_values, arq) ; | ||
+ | |||
+ | // fecha o arquivo | ||
+ | fclose (arq) ; | ||
+ | return (0) ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | No arquivo '' | ||
+ | </ | ||
+ | |||
+ | ===== Posicionamento no arquivo ===== | ||
+ | |||
+ | Para cada arquivo aberto em uma aplicação, | ||
+ | |||
+ | Por default, as operações em um arquivo em C ocorrem em posições sucessivas dentro do arquivo: cada leitura (ou escrita) corre **após** a leitura (ou escrita) precedente, até atingir o final do arquivo. Essa forma de acesso ao arquivo é chamada de **acesso sequencial**. | ||
+ | |||
+ | Por vezes uma aplicação precisa ler ou escrever em posições específicas de um arquivo, ou precisa voltar a ler uma posição do arquivo que já percorreu anteriormente. Isso ocorre frequentemente em aplicações que manipulam arquivos muito grandes, como vídeos ou bases de dados. Para isso é necessária uma forma de **acesso direto** a posições específicas do arquivo. | ||
+ | |||
+ | Em C, o acesso direto a posições específicas de um arquivo é feita através de funções de **posicionamento de ponteiro**, que permitem alterar o valor do ponteiro de posição do arquivo, antes da operação de leitura/ | ||
+ | |||
+ | <note important> | ||
+ | Todas as funções de manipulação do ponteiro de arquivo consideram as **posições em bytes** a partir do início do arquivo, nunca em número de blocos. | ||
+ | </ | ||
+ | |||
+ | As funções mais usuais para acessar o ponteiro de posição de um arquivo em C são indicadas a seguir. | ||
+ | |||
+ | Ajusta posição do ponteiro no //stream// indicado: | ||
+ | |||
+ | <code c> | ||
+ | int fseek (FILE* stream, long int offset, int whence) | ||
+ | </ | ||
+ | |||
+ | O ajuste é definido por '' | ||
+ | |||
+ | <code c> | ||
+ | // posiciona o ponteiro de " | ||
+ | fseek (arq, 1000, SEEK_SET) ; // 1000 bytes após o início | ||
+ | fseek (arq, -300, SEEK_END) ; // 300 bytes antes do fim | ||
+ | fseek (arq, -500, SEEK_CUR) ; // 500 bytes antes da posição atual | ||
+ | </ | ||
+ | |||
+ | Reposiciona o ponteiro no início (posição 0) do //stream// indicado: | ||
+ | |||
+ | <code c> | ||
+ | void rewind (FILE* stream) | ||
+ | </ | ||
+ | |||
+ | Informa a posição corrente de leitura/ | ||
+ | |||
+ | <code c> | ||
+ | long int ftell (FILE* stream) | ||
+ | </ | ||
+ | |||
+ | ===== Outras funções ===== | ||
+ | |||
+ | Para truncar (" | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // usando o nome do arquivo, sem abri-lo | ||
+ | int truncate (const char *path, off_t length); | ||
+ | |||
+ | // usando um descritor UNIX (fd) | ||
+ | int ftruncate (int fd, off_t length); | ||
+ | </ | ||
+ | |||
+ | Para obter as propriedades (metadados) de um arquivo: | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // usando o nome do arquivo, sem abri-lo | ||
+ | int stat (const char *pathname, struct stat *statbuf); | ||
+ | |||
+ | // usando um descritor UNIX (fd) | ||
+ | int fstat (int fd, struct stat *statbuf); | ||
+ | </ | ||
+ | |||
+ | As informações sobre o arquivo serão depositadas pelo núcleo na estrutura '' | ||
+ | |||
+ | <code c> | ||
+ | struct stat | ||
+ | { | ||
+ | dev_t | ||
+ | ino_t | ||
+ | mode_t | ||
+ | nlink_t | ||
+ | uid_t | ||
+ | gid_t | ||
+ | dev_t | ||
+ | off_t | ||
+ | blksize_t st_blksize; | ||
+ | blkcnt_t | ||
+ | struct timespec st_atim; | ||
+ | struct timespec st_mtim; | ||
+ | struct timespec st_ctim; | ||
+ | #define st_atime st_atim.tv_sec | ||
+ | #define st_mtime st_mtim.tv_sec | ||
+ | #define st_ctime st_ctim.tv_sec | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | ===== Exercícios ===== | ||
+ | |||
+ | - Escreva três programas C separados para: | ||
+ | - escrever um arquivo com n (n é um número aleatório > 100) inteiros '' | ||
+ | - ler o arquivo de inteiros em um vetor, ordenar o vetor e reescrever o arquivo; | ||
+ | - escrever na tela os primeiros 10 números e os últimos 10 números contidos no arquivo. | ||
+ | - Utilize stat ou fstat para recuperar o tamanho do arquivo | ||
+ | |||
+ | Mais exercícios no capítulo 11 da {{apostila_c_-_nce.pdf|apostila do NCE/UFRJ}}. | ||