mirror of
https://gitlab.com/blau_araujo/cblc.git
synced 2025-05-09 10:16:35 -03:00
conteúdo da aula 14
This commit is contained in:
parent
fd25b0d1f0
commit
38d909ad07
1 changed files with 200 additions and 0 deletions
200
aulas/14-rfiles/README.org
Normal file
200
aulas/14-rfiles/README.org
Normal file
|
@ -0,0 +1,200 @@
|
|||
#+title: Curso Básico da Linguagem C
|
||||
#+subtitle: Aula 14: Abertura de arquivos para leitura
|
||||
#+author: Blau Araujo
|
||||
#+startup: show2levels
|
||||
#+options: toc:3
|
||||
|
||||
* Aula 14: Abertura de arquivos para leitura
|
||||
|
||||
[[https://www.youtube.com/watch?v=uh3UdYyzXRM][Vídeo desta aula]]
|
||||
|
||||
Em sistemas /Unix-like/, um /arquivo/ é qualquer abstração de recursos de entrada
|
||||
e saída representada como /fluxos de dados/ (/streams/) acessados por meio de
|
||||
operações padronizadas, independentemente de seu conteúdo ou finalidade.
|
||||
|
||||
Neste sentido, existem sete tipos de arquivos:
|
||||
|
||||
- Diretórios
|
||||
- Arquivos regulares (ou comuns)
|
||||
- Ligações simbólicas
|
||||
- Dispositivos especiais caractere
|
||||
- Dispositivos especiais de bloco
|
||||
- Arquivos de pipe (ou FIFO)
|
||||
- Sockets
|
||||
|
||||
Quando queremos acessar um arquivo, seja de que tipo for, nós precisamos que
|
||||
o sistema disponibilize vários recursos, como:
|
||||
|
||||
- Um /descritor de arquivo/ (/file descriptor/): um número inteiro que identifica
|
||||
de forma única o arquivo aberto no contexto do processo.
|
||||
- Uma tabela de descritores do processo: uma estrutura que associa os descritores
|
||||
de arquivos a entradas na tabela global de arquivos abertos.
|
||||
- A tabela global de arquivos abertos (/file table/): que armazena informações
|
||||
como a posição atual de leitura/gravação e as flags de acesso.
|
||||
- A tabela de /inodes/: que contém os metadados do arquivo, como permissões,
|
||||
o "dono" do arquivo, o tipo do arquivo e o ponteiro para os dados no disco.
|
||||
- Os /buffers/ do sistema: usados para otimizar acesso ao conteúdo do arquivo
|
||||
acumulando dados temporariamente na memória.
|
||||
|
||||
Na linguagem C, tudo isso é abstraído como o tipo =FILE *=, que é um ponteiro para
|
||||
a estrutura de dados (uma /struct/) disponibilizada para cada operação de acesso
|
||||
ao /fluxo de dados/ (/stream/) que irá representar o arquivo.
|
||||
|
||||
Resumindo:
|
||||
|
||||
- No sistema, arquivos são abstrações de recursos de entrada e saída
|
||||
representados como /fluxos de dados/;
|
||||
- Na linguagem C, os fluxos de dados, bem como os recursos que eles representam,
|
||||
são abstraídos com o tipo =FILE *= (ponteiro para =FILE=).
|
||||
|
||||
#+begin_quote
|
||||
O tipo =FILE *= é definido na biblioteca padrão (cabeçalho =stdio.h=).
|
||||
#+end_quote
|
||||
|
||||
** Diferença entre streams e descritores de arquivos
|
||||
|
||||
*** Descritores de arquivos (tipo =int=)
|
||||
|
||||
- São expressos como inteiros (tipo =int=).
|
||||
- Visíveis em =/proc/PID/fd=.
|
||||
- Identificam arquivos em chamadas de sistema (=open=, =close=, =read=, =write=, etc).
|
||||
- Representam diretamente uma entrada na tabela de arquivos abertos do processo.
|
||||
|
||||
*** Streams (tipo ponteiro para =FILE=)
|
||||
|
||||
- São abstrações de todos os recursos abertos para operações com arquivos.
|
||||
- Utilizados em funções da biblioteca padrão (=fopen=, =fclose=, =fgets=, =fprintf=, etc).
|
||||
- Utilizam descritores de arquivos para interagir com o sistema.
|
||||
- Envolvem acumulação (/buffering/) na memória do processo.
|
||||
|
||||
** Procedimento geral de acesso a arquivos para leitura
|
||||
|
||||
Geralmente, as operações com arquivos envolvem três etapas: abertura,
|
||||
processamento e fechamento.
|
||||
|
||||
*** Abertura
|
||||
|
||||
- Disponibilização dos recursos para acesso ao arquivo.
|
||||
- Definição do tipo de operação (escrita, /append/ e/ou leitura).
|
||||
- Com a chamada de sistema =open=, recebemos um descritor de arquivos.
|
||||
- Com a função =fopen=, recebemos um ponteiro para =FILE= (/stream/).
|
||||
- Com =fopen=, um ponteiro nulo (=NULL=) será retornado no caso de erros.
|
||||
- Com =open=, o retorno será =-1= no caso de erros.
|
||||
- Com ambas as funções, a variável =errno= receberá a identificação do erro.
|
||||
|
||||
#+begin_quote
|
||||
Neste curso, nós utilizaremos apenas a função =fopen=.
|
||||
#+end_quote
|
||||
|
||||
Exemplo:
|
||||
|
||||
#+begin_src c
|
||||
char *file = "arquivo.txt";
|
||||
FILE *stream = fopen(file, "r");
|
||||
#+end_src
|
||||
|
||||
Aqui, o arquivo =arquivo.txt=, se existir no diretório corrente, será aberto
|
||||
para leitura (modo de abertura ="r"=). Se tudo correr bem, nós teremos o
|
||||
fluxo de dados =stream= para manipular o arquivo.
|
||||
|
||||
Para tratar eventuais erros, nós podemos fazer algo assim:
|
||||
|
||||
#+begin_src c
|
||||
char *file = "arquivo.txt";
|
||||
FILE *stream = fopen(file, "r");
|
||||
if (!stream) {
|
||||
perror("Erro ao abrir o arquivo");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#+end_src
|
||||
|
||||
#+begin_quote
|
||||
A função =perror= imprime, na saída padrão de erros (=stderr=), a descrição
|
||||
do último erro atribuído à variável =errno=. A string, passada como argumento,
|
||||
será utilizada como prefixo da mensagem impressa.
|
||||
#+end_quote
|
||||
|
||||
*** Processamento
|
||||
|
||||
É quando nós realizamos alguma operação com o arquivo, como ler seu conteúdo,
|
||||
escrever algo nele, obter seu tamanho em bytes, reposicionar seu ponteiro
|
||||
interno, etc. Por exemplo, nós podemos abrir o arquivo =/etc/shells= para ler
|
||||
e imprimir todo seu conteúdo:
|
||||
|
||||
#+begin_src c
|
||||
char *file = "/etc/shells";
|
||||
|
||||
// Abertura do arquivo...
|
||||
FILE *stream = fopen(file, "r");
|
||||
if (!stream) {
|
||||
perror("Erro ao abrir o arquivo");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Processamento...
|
||||
char line[BUFSIZ]; // Buffer para acumular cada linha lida
|
||||
while (fgets(line, BUFSIZ, stream)) {
|
||||
printf("%s", line);
|
||||
}
|
||||
#+end_src
|
||||
|
||||
Aqui, =fgets= lerá o conteúdo do arquivo associado a =stream= (=/etc/shells=) até
|
||||
encontrar uma quebra de linha ou chagar a =BUFSIZ-1= bytes.
|
||||
|
||||
#+begin_quote
|
||||
A macro =BUFSIZ= é definida em =stdio.h= e expande o valor =8192= (8kB).
|
||||
#+end_quote
|
||||
|
||||
De um modo ou de outro, a estrutura de dados associada a =stream= registrará
|
||||
a quantidade de bytes que já foram lidos para que, no caso de um acesso
|
||||
subsequente, a leitura continue a partir do byte seguinte -- isso é o que
|
||||
chamamos de /ponteiro interno do arquivo/.
|
||||
|
||||
#+begin_quote
|
||||
O ponteiro interno do arquivo pode ser obtido e manipulado com as funções
|
||||
=fseek=, =ftell= e =rewind=.
|
||||
#+end_quote
|
||||
|
||||
Consequentemente, enquanto =fgets= não retornar =NULL= (no caso de um erro ou
|
||||
do fim do arquivo), o conteúdo do buffer =line= será impresso e o arquivo
|
||||
será lido novamente a partir da nova posição de seu ponteiro interno.
|
||||
|
||||
*** Fechamento
|
||||
|
||||
- Liberação dos recursos disponibilizados na abertura.
|
||||
- Tratamento adequado para os dados pendentes.
|
||||
- Possibilita a verificação de erros de fechamento.
|
||||
- Com =close= ou =fclose=, o retorno será =0= em caso de sucesso.
|
||||
- Com =close=, o retorno será =-1= em caso de erro.
|
||||
- Com =fclose=, o retorno será =EOF= em caso de erro (que também tem valor =-1=).
|
||||
- Com ambas as funções, a variável =errno= receberá a identificação do erro.
|
||||
|
||||
#+begin_quote
|
||||
Os arquivos abertos são fechados com o fim do processo, mas é sempre
|
||||
preferível fechá-los explicitamente para garantir a integridade dos
|
||||
dados e evitar vulnerabilidades (como o vazamento de recursos).
|
||||
#+end_quote
|
||||
|
||||
Para fechar o arquivo do nosso exemplo:
|
||||
|
||||
#+begin_src c
|
||||
char *file = "/etc/shells";
|
||||
|
||||
// Abertura do arquivo...
|
||||
FILE *stream = fopen(file, "r");
|
||||
if (!stream) {
|
||||
perror("Erro ao abrir o arquivo");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Processamento...
|
||||
char line[BUFSIZ]; // Buffer para acumular cada linha lida
|
||||
while (fgets(line, BUFSIZ, stream)) {
|
||||
printf("%s", line);
|
||||
}
|
||||
|
||||
// Fechamento do arquivo...
|
||||
fclose(stream);
|
||||
#+end_src
|
||||
|
||||
|
Loading…
Add table
Reference in a new issue