Compare commits

...

4 commits

Author SHA1 Message Date
60d0d0a598 exercícios da aula 16 2025-05-07 09:33:24 -03:00
1a86a63298 link da aula corrigido 2025-05-07 09:11:56 -03:00
add1c00268 link da aula 16 2025-05-07 08:55:26 -03:00
76a3f77882 conteúdo da aula 16 2025-05-07 08:54:19 -03:00
4 changed files with 304 additions and 2 deletions

View file

@ -37,6 +37,6 @@ qualquer distribuição.
- [[./aulas/13-read][Aula 13: Leitura da entrada padrão com chamadas de sistema]] ([[https://youtu.be/bW3Xox6LP_U][vídeo]]) ([[./exercicios/13/README.org][exercícios]])
- [[./aulas/14-rfiles][Aula 14: Abertura de arquivos para leitura]] ([[https://youtu.be/uh3UdYyzXRM][vídeo]]) ([[./exercicios/14/README.org][exercícios]])
- [[./aulas/15-wfiles][Aula 15: Abertura de arquivos para escrita]] ([[https://youtu.be/vL8vy3krcKc][vídeo]]) ([[./exercicios/15/README.org][exercícios]])
- [[./aulas/#][Aula 16: Abertura de arquivos para leitura e escrita]] ([[https://youtu.be/B42KIZfivsg][vídeo]]) ([[./exercicios/16/README.org][exercícios]])
- [[./aulas/16-rwfiles][Aula 16: Abertura de arquivos para leitura e escrita]] ([[https://youtu.be/B42KIZfivsg][vídeo]]) ([[./exercicios/16/README.org][exercícios]])

245
aulas/16-rwfiles/README.org Normal file
View file

@ -0,0 +1,245 @@
#+title: Curso Básico da Linguagem C
#+subtitle: Aula 16: Abertura de arquivos para leitura e escrita
#+author: Blau Araujo
#+startup: show2levels
#+options: toc:3
* Aula 16: Abertura de arquivos para leitura e escrita
[[https://youtu.be/B42KIZfivsg][Vídeo desta aula]]
** Modos de abertura para leitura e escrita
As strings de modos ="r"=, ="w"= e ="a"=, da função =fopen=, quando sucedidas do
caractere =+=, indicam a abertura do arquivo também para suas respectivas
operações contrarias:
| Modo | Leitura | Escrita | Truncar | Offset | Criar |
|------+---------+---------+---------+--------+-------|
| ="r"= | Sim | Não | Não | Início | Não |
| ="r+"= | Sim | Sim | Não | Início | Não |
| ="w"= | Não | Sim | Sim | Início | Sim |
| ="w+"= | Sim | Sim | Sim | Início | Sim |
| ="a"= | Não | Sim | Não | Fim | Sim |
| ="a+"= | Sim | Sim | Não | Fim | Sim |
De acordo com a tabela acima, nós precisamos observar alguns pontos
importantes:
- Se a string de modo iniciar com =w=, o arquivo sempre será truncado
na sua abertura.
- Se a string de modo iniciar com =a=, o ponteiro interno sempre será
posicionado no fim do arquivo na sua abertura.
- Se a string de modo iniciar com =r=, o ponteiro interno sempre será
posicionado no início do arquivo na sua abertura.
- Se não existir, o arquivo só será criado se a string de modo
iniciar com =w= ou =a=.
** Manipulação do ponteiro interno
O ponteiro interno do arquivo representa o número do byte que será lido
ou escrito no próximo acesso: ou seja, seu /offset/ (ou /ponto de partida/).
Isso é particularmente importante quando abrimos arquivos para ambas as
operações com as strings de modo ="r+"= ou ="a+"=, visto que o modo ="w+"=
truncará o conteúdo do arquivo.
*** A função =fseek=
As funções da família =fseek= (=stdio.h=) são utilizadas para posicionar
ou obter informações sobre o ponteiro interno do arquivo:
| Função | Descrição | Retorno |
|---------+-----------------------------------------------------------------------------------------+--------------------------------|
| =fseek= | Define a posição do ponteiro interno. | Sucesso: =0= (=int=) |
| =ftell= | Obtém a posição corrente do ponteiro interno. | Sucesso: número do byte (=long=) |
| =rewind= | Posiciona o ponteiro interno no byte =0=. | =void= |
| =fsetpos= | Interface para =fseek= referenciando a definição do /offset/ a partir do início do arquivo. | Sucesso: =0= (=int=) |
| =fgetpos= | Interface para =ftell= escrevendo o /offset/ obtido em um dado endereço. | Sucesso: =0= (=int=) |
*Notas:*
- Com a função =fseek=, o novo /offset/ é definido com uma expressão do tipo =long=.
- Com a função =fsetpos=, o novo /offset/ é definido em um ponteiro do tipo =fpos_t=.
- Com a função =fgetpos=, o /offset/ corrente é escrito em um ponteiro do tipo =fpos_t=.
#+begin_quote
A função =fseek= trabalha com /streams/, mas é possível manipular o ponteiro interno
a partir de descritores de arquivos com a chamada de sistema =lseek=.
#+end_quote
*** Pontos de origem de =fseek=
A função =fseek= recebe 3 argumentos:
- O /stream/ associado ao arquivo;
- A expressão do valor do /offset/ (tipo =long=);
- Um inteiro determinando o ponto de origem para a definição do novo /offset/.
Este é o seu protótipo na =glibc= (=stdio.h=):
#+begin_src c
int fseek(FILE *stream, long offset, int whence);
#+end_src
#+begin_quote
O termo /whence/ significa /"a partir de onde"/ e representa o ponto de origem
do deslocamento do ponteiro interno do arquivo.
#+end_quote
O terceiro argumento (=whence=) pode receber qualquer valor inteiro, mas
a =glibc= oferece três macros para os pontos de origem mais comuns:
- =SEEK_SET=: o início do arquivo;
- =SEEK_END=: o fim do arquivo;
- =SEEK_CUR=: o /offset/ corrente.
*** Abertura de arquivos com "r+"
Como o /offset/ inicial será o byte =0=, se a primeira operação for uma
escrita, os primeiros bytes do arquivo serão sobrescritos. Caso esta
não seja a intenção, será preciso deslocar o ponteiro interno para o
fim do arquivo:
#+begin_src c
// Abertura do arquivo para leitura e escrita...
char *file = "arquivo.txt";
FILE *stream = fopen(file, "r+");
// Posicionar offset no fim do arquivo...
fseek(stream, 0, SEEK_END);
// Rotinas de escrita...
#+end_src
Aqui, nós deslocamos o ponteiro interno em zero bytes a partir do fim do
arquivo (origem em =SEEK_END=).
*** Abertura de arquivos com "a+"
O /offset/ inicial será o fim do arquivo e, se quisermos começar a leitura
a partir de seu início, será preciso deslocar o ponteiro interno para lá:
#+begin_src c
// Abertura do arquivo para leitura e escrita...
char *file = "arquivo.txt";
FILE *stream = fopen(file, "r+");
// Posicionar offset no início do arquivo...
fseek(stream, 0, SEEK_SET);
// Rotinas de leitura...
#+end_src
Desta vez, nós deslocamos o ponteiro interno em zero bytes a partir do
início do arquivo (origem em =SEEK_SET=).
** Procedimentos úteis
Para encerrar esta aula (e o nosso curso), aqui estão alguns exemplos de
procedimentos gerais úteis envolvendo a manipulação de arquivos.
*** Quantidade de linhas
#+begin_src c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
// Abertura do arquivo para leitura...
char *file = "meuarquivo.txt";
FILE *stream = fopen(file, "r");
if (!stream) {
fprintf(stderr, "Erro ao abrir o arquivo!\n");
return EXIT_FAILURE;
}
// Contagem de linhas...
char buf[BUFSIZ]; // Buffer para ler blocos do arquivo (8192 bytes).
int lines = 0; // Total de linhas encontradas.
// Lê uma linha até encontrar \n, até BUFSIZ-1 ou até EOF...
while (fgets(buf, BUFSIZ, stream) != NULL) {
// Só conta uma linha se houver \n no buffer...
if (buf[strlen(buf) - 1] == '\n' ) lines++;
}
// Se a última linha não contiver \n, ela também será contada...
if (lines > 0 && buf[strlen(buf) - 1] != '\n') lines++;
// Fechamento do arquivo...
fclose(stream);
// Impressão do resultado...
printf("%d linhas", lines);
return EXIT_SUCCESS;
}
#+end_src
*** Obter o tamanho do arquivo
#+begin_src c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// Abertura do arquivo...
char *file = "meuarquivo.txt";
FILE *stream = fopen(file, "rb");
if (!stream) {
perror("Erro ao abrir o arquivo");
return EXIT_FAILURE;
}
// Posiciona o ponteiro de leitura no final do arquivo...
if (fseek(stream, 0, SEEK_END) != 0) {
perror("Erro ao deslocar o offset para o final");
fclose(stream);
return EXIT_FAILURE;
}
// Obtém o offset corrente (tamanho do arquivo em bytes)...
long fsize = ftell(stream);
if (fsize == -1L) {
perror("Erro ao obter o offset corrente");
fclose(stream);
return EXIT_FAILURE;
}
// Exibe o tamanho do arquivo...
printf("Tamanho do arquivo: %ld bytes\n", fsize);
// Fechamento do arquivo...
fclose(stream);
return EXIT_SUCCESS;
}
#+end_src
*** Testar se um arquivo está vazio (0 bytes)
#+begin_src c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// Abertura do arquivo...
char *file = "meuarquivo.txt";
FILE *stream = fopen(file, "r");
if (!stream) {
perror("Erro na abertura do arquivo");
return EXIT_FAILURE;
}
// is_empty recebe 1 se o arquivo estiver vazio...
int is_empty = (fseek(stream, 0, SEEK_END) == 0 && ftell(stream) == 0);
// Fechamento do arquivo...
fclose(stream);
// O programa terminará com sucesso (0) se o arquivo estiver vazio...
return !is_empty;
}
#+end_src

View file

@ -6,7 +6,7 @@
* Exercícios da aula 15: Abertura de arquivos para escrita
- [[../../aulas/14-wfiles/README.org][Anotações da aula]]
- [[../../aulas/15-wfiles/README.org][Anotações da aula]]
- [[https://youtu.be/vL8vy3krcKc][Vídeo]]
** 1. Programa 'nf' (new file)

57
exercicios/16/README.org Normal file
View file

@ -0,0 +1,57 @@
#+title: Curso Básico da Linguagem C
#+subtitle: Exercícios
#+author: Blau Araujo
#+startup: show2levels
#+options: toc:3
* Exercícios da aula 16: Abertura de arquivos para leitura e escrita
- [[../../aulas/16-rwfiles/README.org][Anotações da aula]]
- [[https://youtu.be/B42KIZfivsg][Vídeo]]
** 1. Contando e inserindo linhas
Dado o arquivo =lorem.txt=, abaixo:
#+begin_example
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Curabitur pretium tincidunt lacus. Nulla gravida orci a odio.
Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris.
Integer in mauris eu nibh euismod gravida. Duis ac turpis.
Integer vitae libero ac risus egestas placerat. Praesent eu lacus quam.
Morbi ac felis. Suspendisse ac metus gravida, cursus nunc eu, dictum risus.
#+end_example
Escreva um programa que determine quantas linhas ele tem e escreva esse resultado
no início deste mesmo arquivo segundo o formato abaixo:
#+begin_example
Este arquivo tinha X linhas, agora tem X+2 linhas...
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Curabitur pretium tincidunt lacus. Nulla gravida orci a odio.
Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris.
Integer in mauris eu nibh euismod gravida. Duis ac turpis.
Integer vitae libero ac risus egestas placerat. Praesent eu lacus quam.
Morbi ac felis. Suspendisse ac metus gravida, cursus nunc eu, dictum risus.
#+end_example
** 2. Desafio: Trocando palavras
Utilizando o mesmo arquivo anterior (na sua forma original), crie um programa que
substitua todas as ocorrências da palavra =gravida= por =>ACHEI<=, imprimindo no terminal
a quantidade de ocorrências e em que linhas e colunas do texto elas foram encontradas.
** 3. Desafio: O código Da Vinci
Utilizando, mais uma vez, o arquivo de exemplo na sua forma original, crie um
programa que reescreva seu conteúdo invertendo a ordem dos caracteres de cada linha,
como se estivéssemos vendo o texto em um espelho.