Acesso Aleatório em ArquivosINF01202
Prof. Lucas Mello Schnorr
1 / 17
Sumário
Em C (lidar com o conteúdo de arquivos)
I Habituais funções de abertura, leitura, escrita, fechamento
I Retornar rewind
I Reposicionar fseek
I Dizer ftell
Em C (lidar com arquivos)
I Renomear rename e remover remove
I Outras funções de stdio.h
2 / 17
Cabeçote de leitura/gravação
Slide 7 INF 01202
Leitura/Gravação em arquivos
• A leitura ou gravação de um stream de/para o arquivo causam um deslocamento da posição corrente do arquivo, em relação ao momento anterior à operação de entrada ou saída de dados.
• A posição posterior corresponde à posição do início da operação é deslocada pela adição do número de bytes lidos ou gravados, ou seja, a posição corrente fica sendo o byte imediatamente posterior ao último processado (leitura ou gravação).
Cortesia: Prof. Claudio Jung
3 / 17
Rebobinar rewind (rebobina a posição do cabeçote)
Protótipo
void rewind(FILE *stream);
A função rewind seta o indicador de posição (o cabeçote deleitura/gravação) apontado por stream para o início do arquivo.
Exemplo
FILE *arquivo;
arquivo = fopen("atletas.bin", "r");
fread(&atletas, sizeof(atleta_t), natletas, arquivo);
rewind(arquivo);
4 / 17
Rebobinar rewind (rebobina a posição do cabeçote)
Protótipo
void rewind(FILE *stream);
A função rewind seta o indicador de posição (o cabeçote deleitura/gravação) apontado por stream para o início do arquivo.
Exemplo
FILE *arquivo;
arquivo = fopen("atletas.bin", "r");
fread(&atletas, sizeof(atleta_t), natletas, arquivo);
rewind(arquivo);
4 / 17
Reposicionar fseek (mudar a posição do cabeçote)Protótipo
int fseek(FILE *stream, long offset, int whence);
A função fseek de�ne a posição do cabeçote de leitura do stream. Anova posição, medidas em bytes, é obtida adicionando offset bytes paraa posição especi�cada por whence.
whence Signi�cado
SEEK_SET deslocamento o�set em relação ao início do arquivoSEEK_CUR deslocamento o�set em relação à posição atual do arquivoSEEK_END deslocamento o�set em relação ao �nal do arquivo
Exemplo
FILE *arquivo;
arquivo = fopen("atletas.bin", "r");
fseek(arquivo, 4, SEEK_CUR);
fseek(arquivo, -sizeof(atleta_t), SEEK_END);
fseek(arquivo, 0, SEEK_SET);
5 / 17
Reposicionar fseek (mudar a posição do cabeçote)Protótipo
int fseek(FILE *stream, long offset, int whence);
A função fseek de�ne a posição do cabeçote de leitura do stream. Anova posição, medidas em bytes, é obtida adicionando offset bytes paraa posição especi�cada por whence.
whence Signi�cado
SEEK_SET deslocamento o�set em relação ao início do arquivoSEEK_CUR deslocamento o�set em relação à posição atual do arquivoSEEK_END deslocamento o�set em relação ao �nal do arquivo
Exemplo
FILE *arquivo;
arquivo = fopen("atletas.bin", "r");
fseek(arquivo, 4, SEEK_CUR);
fseek(arquivo, -sizeof(atleta_t), SEEK_END);
fseek(arquivo, 0, SEEK_SET);
5 / 17
Reposicionar fseek (mudar a posição do cabeçote)Protótipo
int fseek(FILE *stream, long offset, int whence);
A função fseek de�ne a posição do cabeçote de leitura do stream. Anova posição, medidas em bytes, é obtida adicionando offset bytes paraa posição especi�cada por whence.
whence Signi�cado
SEEK_SET deslocamento o�set em relação ao início do arquivoSEEK_CUR deslocamento o�set em relação à posição atual do arquivoSEEK_END deslocamento o�set em relação ao �nal do arquivo
Exemplo
FILE *arquivo;
arquivo = fopen("atletas.bin", "r");
fseek(arquivo, 4, SEEK_CUR);
fseek(arquivo, -sizeof(atleta_t), SEEK_END);
fseek(arquivo, 0, SEEK_SET);5 / 17
Revelar ftell (revela a posição do cabeçote)
Protótipo
long ftell(FILE *stream);
A função obtém o valor atual da posição do cabeçote de leitura/gravaçãoapontado por stream.
Exemplo
FILE *arquivo;
arquivo = fopen("atletas.bin", "r");
fseek(arquivo, 0, SEEK_END);
printf("Posição atual: %ld\n", ftell(arquivo));
6 / 17
Revelar ftell (revela a posição do cabeçote)
Protótipo
long ftell(FILE *stream);
A função obtém o valor atual da posição do cabeçote de leitura/gravaçãoapontado por stream.
Exemplo
FILE *arquivo;
arquivo = fopen("atletas.bin", "r");
fseek(arquivo, 0, SEEK_END);
printf("Posição atual: %ld\n", ftell(arquivo));
6 / 17
Funções de manipulação externa de arquivos
Protótipos
int rename(const char *oldpath, const char *newpath);
int remove(const char *pathname);
Outras funções de stdio.h
I Procure no DuckDuckGo: man stdio
7 / 17
Funções de manipulação externa de arquivos
Protótipos
int rename(const char *oldpath, const char *newpath);
int remove(const char *pathname);
Outras funções de stdio.h
I Procure no DuckDuckGo: man stdio
7 / 17
Acesso não sequencial no arquivo
Slide 11 INF 01202
Acesso Randômico
Acesso a pontos de um arquivo, sem percorrer sequencialmente o conteúdo que antecede o conteúdo desejado.
Motivações: • a posição desejada de leitura ou escrita pode
não ser coincidente com a posição corrente do arquivo válida em um certo momento.
• A posição corrente de leitura ou escrita pode ser alterada para qualquer posição do arquivo.
Cortesia: Prof. Claudio Jung
8 / 17
Exemplo #1: InsereNoFim-AindaMelhorResolvendo o problema de uma maneira mais elegante:
1. Ler a quantidade de atletas no início do arquivo2. fseek para o �m do arquivo3. Escrever o novo atleta4. rewind (reboninar para o início do arquivo)5. Escrever a nova quantidade de atletas
InsereNoFinal-AindaMelhor.c
#include <stdio.h>#include "GeraSalva-Nomes.h"#include "GeraSalva.h"int main() {
FILE *arquivo = NULL;int natletas = 0;atleta_t atleta = {0};gera_nome_aleatorio(atleta.nome, 20);atleta.idade = gera_idade_aleatoria(18, 25);atleta.altura = gera_altura_aleatoria(180, 185);printf("%s, %d, %d\n",
atleta.nome, atleta.idade, atleta.altura);
//1.arquivo = fopen(FATLETAS, "r+");if (arquivo){fread(&natletas, sizeof(int), 1, arquivo);
}else{
printf("Impossível abrir arquivo ""[%s] para leitura/escrita. ""Fatal.\n", FATLETAS);
return 0;}
//2.fseek(arquivo, 0L, SEEK_END);
//3.fwrite(&atleta, sizeof(atleta_t), 1, arquivo);fflush(arquivo);
//4.rewind(arquivo);natletas++;fwrite(&natletas, sizeof(int), 1, arquivo);fclose(arquivo);return 0;
}
9 / 17
Exemplo #1: InsereNoFim-AindaMelhorResolvendo o problema de uma maneira mais elegante:
1. Ler a quantidade de atletas no início do arquivo2. fseek para o �m do arquivo3. Escrever o novo atleta4. rewind (reboninar para o início do arquivo)5. Escrever a nova quantidade de atletas
InsereNoFinal-AindaMelhor.c
#include <stdio.h>#include "GeraSalva-Nomes.h"#include "GeraSalva.h"int main() {
FILE *arquivo = NULL;int natletas = 0;atleta_t atleta = {0};gera_nome_aleatorio(atleta.nome, 20);atleta.idade = gera_idade_aleatoria(18, 25);atleta.altura = gera_altura_aleatoria(180, 185);printf("%s, %d, %d\n",
atleta.nome, atleta.idade, atleta.altura);
//1.arquivo = fopen(FATLETAS, "r+");if (arquivo){
fread(&natletas, sizeof(int), 1, arquivo);}else{
printf("Impossível abrir arquivo ""[%s] para leitura/escrita. ""Fatal.\n", FATLETAS);
return 0;}
//2.fseek(arquivo, 0L, SEEK_END);
//3.fwrite(&atleta, sizeof(atleta_t), 1, arquivo);fflush(arquivo);
//4.rewind(arquivo);natletas++;fwrite(&natletas, sizeof(int), 1, arquivo);fclose(arquivo);return 0;
}
9 / 17
Exemplo #1: Compilação e Testes
rm -f InsereNoFinal-AindaMelhor
gcc -Wall -g \
e/rev-a34/GeraSalva-Nomes.c \
e/rev-a34/InsereNoFinal-AindaMelhor.c \
-o e/rev-a34/InsereNoFinal-AindaMelhor
10 / 17
Exemplo #2: Cria um arquivo de índice
Um programa que varre o arquivo de atletas atletas.bin, criando umoutro arquivo chamado index.bin que terá o nome do atleta seguido deum valor long que contenha a posição daquele atleta no arquivo.
Nova estrutura de dados index_t, com dois campos
typedef struct {
char nome[32];
long posicao;
} index_t;
Programa CriaIndex, com os seguintes módulos
I Index, funções para preencher index_t a partir de um atleta_t
I Programa, abre atletas.bin e cria o arquivo index.bin.
11 / 17
Exemplo #2: Cria um arquivo de índice
Um programa que varre o arquivo de atletas atletas.bin, criando umoutro arquivo chamado index.bin que terá o nome do atleta seguido deum valor long que contenha a posição daquele atleta no arquivo.
Nova estrutura de dados index_t, com dois campos
typedef struct {
char nome[32];
long posicao;
} index_t;
Programa CriaIndex, com os seguintes módulos
I Index, funções para preencher index_t a partir de um atleta_t
I Programa, abre atletas.bin e cria o arquivo index.bin.
11 / 17
Exemplo #2: Cria um arquivo de índice
Um programa que varre o arquivo de atletas atletas.bin, criando umoutro arquivo chamado index.bin que terá o nome do atleta seguido deum valor long que contenha a posição daquele atleta no arquivo.
Nova estrutura de dados index_t, com dois campos
typedef struct {
char nome[32];
long posicao;
} index_t;
Programa CriaIndex, com os seguintes módulos
I Index, funções para preencher index_t a partir de um atleta_t
I Programa, abre atletas.bin e cria o arquivo index.bin.
11 / 17
(#2) Index: Cabeçalho e ImplementaçãoIndex.h
#ifndef INDEX_H
#define INDEX_H
#include <stdio.h>
#include "GeraSalva.h"
#define FINDEX "index.bin"
typedef struct {
char nome[32];
long posicao;
} index_t;
index_t cria_index (atleta_t *a, long posicao);
#endif
Index.c
#include "Index.h"
index_t cria_index (atleta_t *a, long posicao) {
index_t ret;
strncpy(ret.nome, a->nome, 32);
ret.posicao = posicao;
return ret;
}
12 / 17
(#2) Index: Cabeçalho e ImplementaçãoIndex.h
#ifndef INDEX_H
#define INDEX_H
#include <stdio.h>
#include "GeraSalva.h"
#define FINDEX "index.bin"
typedef struct {
char nome[32];
long posicao;
} index_t;
index_t cria_index (atleta_t *a, long posicao);
#endif
Index.c
#include "Index.h"
index_t cria_index (atleta_t *a, long posicao) {
index_t ret;
strncpy(ret.nome, a->nome, 32);
ret.posicao = posicao;
return ret;
}
12 / 17
(#2) Programa: Implementação
CriaIndex.c
#include "Index.h"int main() {
atleta_t atleta;index_t index;
// Abre o arquivo dos atletas para leituraFILE *arq0 = fopen(FATLETAS, "r");if (!arq0) {
printf("Impossível de abrir arquivo [%s] ""para leitura. Fatal.\n", FATLETAS);
return 0;}
// Abre o arquivo dos índices para escritaFILE *arq1 = fopen(FINDEX, "w");if (!arq1) {printf("Impossível de abrir arquivo [%s] "
"para escrita. Fatal.\n", FINDEX);return 0;
}
// Ignora os 4 bytes iniciais com fseekfseek(arq0, sizeof(int), SEEK_CUR);
// Enquanto o arquivo não chegar ao fimwhile(!feof(arq0)){
// Salva a posiçãolong posicao = ftell(arq0);
// Le os dados de um atletafread(&atleta, sizeof(atleta_t), 1, arq0);
// Cria o índice correspondenteindex = cria_index(&atleta, posicao);
// Escreve o índice no arquivo de saídafwrite(&index, sizeof(index_t), 1, arq1);
}fclose(arq0);fclose(arq1);return 0;
}
Compilação e testes
rm -f CriaIndex
gcc -Wall -g e/rev-a34/Index.c e/rev-a34/CriaIndex.c -o e/rev-a34/CriaIndex
13 / 17
(#2) Programa: Implementação
CriaIndex.c
#include "Index.h"int main() {
atleta_t atleta;index_t index;
// Abre o arquivo dos atletas para leituraFILE *arq0 = fopen(FATLETAS, "r");if (!arq0) {
printf("Impossível de abrir arquivo [%s] ""para leitura. Fatal.\n", FATLETAS);
return 0;}
// Abre o arquivo dos índices para escritaFILE *arq1 = fopen(FINDEX, "w");if (!arq1) {printf("Impossível de abrir arquivo [%s] "
"para escrita. Fatal.\n", FINDEX);return 0;
}
// Ignora os 4 bytes iniciais com fseekfseek(arq0, sizeof(int), SEEK_CUR);
// Enquanto o arquivo não chegar ao fimwhile(!feof(arq0)){
// Salva a posiçãolong posicao = ftell(arq0);
// Le os dados de um atletafread(&atleta, sizeof(atleta_t), 1, arq0);
// Cria o índice correspondenteindex = cria_index(&atleta, posicao);
// Escreve o índice no arquivo de saídafwrite(&index, sizeof(index_t), 1, arq1);
}fclose(arq0);fclose(arq1);return 0;
}
Compilação e testes
rm -f CriaIndex
gcc -Wall -g e/rev-a34/Index.c e/rev-a34/CriaIndex.c -o e/rev-a34/CriaIndex13 / 17
Exemplo #3: Atualiza a idade de um atletaUm programa que atualiza a idade de um determinado atleta, cujo nomee idade corrigida foram lidos do teclado. O nome deve ser procurado noarquivo index.bin para obter sua posição no arquivo atletas.bin. Emseguida, o arquivo atletas.bin deve ser atualizado com a idadecorrigida.
Passos
1. Abrir arquivos index.bin e atletas.bin
2. Ler procurado e sua nova_idade corrigida
3. Procurar o procurado no index.bin
4. Se encontrar, obter a posição do procurado no atletas.bin
5. Posicionar cabeçote de leitura para posição encontrada
6. Ler o registro
7. Con�rmar que realmente encontramos o registro
8. Atualizar campo idade com nova_idade
9. Reposicionar cabeçote de leitura para posição encontrada
10. Escrever o registro atualizado
14 / 17
Exemplo #3: Atualiza a idade de um atletaUm programa que atualiza a idade de um determinado atleta, cujo nomee idade corrigida foram lidos do teclado. O nome deve ser procurado noarquivo index.bin para obter sua posição no arquivo atletas.bin. Emseguida, o arquivo atletas.bin deve ser atualizado com a idadecorrigida.Passos
1. Abrir arquivos index.bin e atletas.bin
2. Ler procurado e sua nova_idade corrigida
3. Procurar o procurado no index.bin
4. Se encontrar, obter a posição do procurado no atletas.bin
5. Posicionar cabeçote de leitura para posição encontrada
6. Ler o registro
7. Con�rmar que realmente encontramos o registro
8. Atualizar campo idade com nova_idade
9. Reposicionar cabeçote de leitura para posição encontrada
10. Escrever o registro atualizado14 / 17
(#3) Atualiza: Implementação
Atualiza.c
#include "Index.h"#include "GeraSalva.h"int main() {
atleta_t atleta = {0};index_t index = {0};char procurado[32] = {0};int nova_idade = 0;// 1. Abre o arquivo dos atletas para atualizaçãoFILE *arq0 = fopen(FATLETAS, "r+");if (!arq0) {
printf("Impossível de abrir arquivo [%s] ""para atualização. Fatal.\n", FATLETAS);
return 0;}// 1. Abre o arquivo dos índices para leituraFILE *arq1 = fopen(FINDEX, "r");if (!arq1) {printf("Impossível de abrir arquivo [%s] "
"para leitura. Fatal.\n", FINDEX);return 0;
}// 2. Le o procurado e sua idade corrigidaprintf("Nome do procurado: ");fgets(procurado, 32, stdin);procurado[strlen(procurado)-1] = '\0';printf("Nova idade do procurado [%s]: ", procurado);scanf("%d", &nova_idade);printf("Atualizar [%s] com a idade [%d]!\n",
procurado, nova_idade);
// 3, 4. Enquanto o arquivo não chegar ao fimint encontrei = 0;while(!feof(arq1) && encontrei == 0){
// Le os dados de um index_tfread(&index, sizeof(index_t), 1, arq1);if (strcmp(index.nome, procurado) == 0){
encontrei = 1;}
}fclose(arq1);if (encontrei == 0){
printf("Nome não encontrado no índice. Fatal.\n");return 0;
}// 5. Vamos posiciar a cabeça de leiturafseek(arq0, index.posicao, SEEK_SET);// 6. Lerfread(&atleta, sizeof(atleta_t), 1, arq0);// 7. Confirmar que é bem o atleta que estamos procurandoif (strcmp(atleta.nome, index.nome) != 0){
printf("Erro, o indice está corrompido.\n");return 0;
}// 8. Atualizar a idade (em memória)atleta.idade = nova_idade;// 9. Reposicionar na posição corretafseek(arq0, index.posicao, SEEK_SET);// 10. Escreverfwrite(&atleta, sizeof(atleta_t), 1, arq0);fclose(arq0);return 0;
}15 / 17
(#3) Compilação e testes
rm -f Atualiza
gcc -Wall -g e/rev-a34/Atualiza.c -o e/rev-a34/Atualiza
Vamos gerar a base e criar índices:
./GeraSalva
./CriaIndex
Atualizar a idade do muvucofasido para 31.
16 / 17
Exercício #1: Calcular estatísticas
Faça um programa de computador que leia atletas.bin e calcule aidade mínima, idade máxima e idade média dentre todos os atletasenvolvidos. Faça o mesmo (ao mesmo tempo) para a altura dos atletas.
Implemente este algoritmo
1. Posicione no início do primeiro atleta (4 bytes do início do arquivo)
2. Enquanto o arquivo não terminar
2.1 Avance até a posição da idade (sabendo que o nome ocupa 32 bytes)2.2 Leia a idade2.3 Atualize estatísticas da idade2.4 Leia a altura2.5 Atualize estatísticas da altura
3. Apresente as estatísticas
E lembre-se:
I A idade média e a altura média são números reais.
I Utilize o programa GeraSalva para criar atletas.bin
17 / 17
Exercício #1: Calcular estatísticas
Faça um programa de computador que leia atletas.bin e calcule aidade mínima, idade máxima e idade média dentre todos os atletasenvolvidos. Faça o mesmo (ao mesmo tempo) para a altura dos atletas.
Implemente este algoritmo
1. Posicione no início do primeiro atleta (4 bytes do início do arquivo)
2. Enquanto o arquivo não terminar
2.1 Avance até a posição da idade (sabendo que o nome ocupa 32 bytes)2.2 Leia a idade2.3 Atualize estatísticas da idade2.4 Leia a altura2.5 Atualize estatísticas da altura
3. Apresente as estatísticas
E lembre-se:
I A idade média e a altura média são números reais.
I Utilize o programa GeraSalva para criar atletas.bin
17 / 17