Buscar

[NEW] Resumo_Arquivo

Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original

Resumo Arquivo:
*********************************************************************************
OBS: Essa matéria cai somente na P3!
*********************************************************************************
- O que é um arquivo?
Sempre que vc ler a palavra "Arquivo" nos enunciados, é só imaginar um simples bloco de texto que armazena várias informações.
Sim! Esse bloco de resumo também é um exemplo de arquivo! :D
------------------------------------//----------------------------------------
- Como se declara um Arquivo?
Primeiro passo é declarar um ponteiro para arquivo:
EX: FILE *in;
 FILE *out;
FILE é o tipo da variável, assim como int, float, etc.
Percebeu que até então nunca declaramos um ponteiro dessa forma? :) 
OBS: Ponteiro em Prog 1 só é usado em funções auxiliares e >> Somente << em passagem de parâmetro!
Mas...Tá aí, a primeira e >>ÚNICA<< exceção! >> Somente << na declaração de Arquivos!
Pra facilitar pense da seguinte forma: Considere o ponteiro como se fosse uma ligação entre o seu programa e o bloco de notas, ou seja, o ponteiro "aponta" para o bloco de notas.
Dessa forma, podemos fazer leituras ou escrever nesse arquivo, mas antes é necessário criar essa ligação!
-------------------------------------//--------------------------------------
- Modos de abertura: 
Todo arquivo que criamos podemos abrir em modo de leitura >> OU << em modo de gravação. 
OBS: Existe um terceiro modo chamado Append que serve ao mesmo tempo pra ler e escrever, mas não é permitido usar em prova!
- Mas por que usar "in" e "out" como nome de ponteiro? 
Eu recomendo que vc use sempre FILE *in para arquivos de >> Leitura << e FILE *out para arquivos de >> Gravação <<!
 
Os professores costumam usar "entrada" e "saida" ou simplesmente "fp" pra ambos os casos, mas eu não recomendo! Usar o mesmo nome pra ambos os casos é pedir pra se confundir e errar!
 
Por exemplo, imagina que temos um arquivo que já está todo preenchido com dados, mas ao invés de abrir o arquivo no modo leitura, sem querer abrimos no modo gravação. Quando isso acontece, todos os dados que estavam no arquivo são perdidos! Esse é um dos erros mais graves em P3! Cuidado! 
E além disso é mais simples e prático usar in/out do que entrada/saida! :D
-----------------------------------//-----------------------------------------
- Como abrir um arquivo? 
Usando a função fopen. Ela recebe dois parâmetros, o percurso do arquivo no HD e o modo de abertura: "r" (Read) para leitura ou "w" (Write) para gravação.
Ex: Abrir para leitura o arquivo NOTAS.txt: 
#include <stdio.h>
#include <stdlib.h>
int main (void){
 FILE *in = fopen ("NOTAS.txt", "r");
 if(!in){
 puts("Erro ao abrir o arquivo!");
 exit(1);
 } 
 fclose(in);
 return 0;
}
Como se trata de um arquivo pra leitura: Primeiro declaramos o ponteiro FILE *in e logo em seguida já podemos chamar a função fopen passando seus 2 parâmetros. O percurso do arquivo e o modo de abertura que nesse caso é "r" pra leitura!
A função fopen retorna a "Ligação" entre o programa e o bloco de notas e se caso houver algum erro na criação dessa "ligação", ela retorna >> NULL << ! 
E como nessa parte >> FILE *in = fopen(...) << estamos fazendo uma atribuição, o retorno da função fopen é armazenado no ponteiro in !
OBS: Não precisa se preocupar em entender o funcionamento da função fopen! Funções desse tipo só serão estudadas em Prog 2! O que é realmente importante entender é que em caso de erro na abertura do arquivo, in será NULL!
----------------------------------------//-------------------------------------
- Percurso de um arquivo: (Parâmetro da fopen) 
FILE *in = fopen ("NOTAS.txt", "r");
Notou que só usei o nome do arquivo no lugar do percurso?
É possível colocar só o nome do arquivo ao invés do percurso completo, mas isso >> SÓ << vai funcionar se o arquivo estiver dentro da mesma pasta que o seu projeto no Visual Studio! (Percurso padrão) 
E como no desespero da prova existe o risco de acabar colocando o arquivo no lugar errado. Então eu sempre recomendo especificar o percurso completo!
É só ir na pasta onde está o arquivo, selecionar com o botão direito do mouse e clicar em propriedades: Vai aparecer um trecho que começa com >> C:\ << 
Esse é o começo do percurso! :)
OBS: Normalmente os arquivos da P3 ficam nesse percurso: >> C:\Prova << 
Mas percebeu que o percurso não está completo? Ainda falta colocar o nome do arquivo que queremos abrir! E logo em seguida criar uma Macro pra simplificar.
#define IN "C:\Prova\NOTAS.txt" 
Mas ainda falta um pequeno detalhe, precisamos trocar >> TODOS << os contra-barra >> \ << do percurso pela barra >> / <<
- Mas por que isso? :O 
Imagina que o nome do arquivo está todo em minúsculo: notas.txt
E criamos a macro: #define IN "C:\Prova\notas.txt" 
Aparentemente tudo ok né? :D
Mas...infelizmente vai dar algum erro misterioso, o que será? 
Já que a macro é uma frase entre aspas, vamos tentar jogar isso na printf pra ver o que acontece: 
printf("C:\Prova\notas.txt");
Será exibido na tela:
C:\Prova
otas.txt
Wait, cadê o n em notas.txt!? E o printf pulou uma linha do nada! WHAT!? :o
printf("C:\Prova \n otas.txt"); 
OBS: Reconhece aquele >> \n << de algum lugar? :D
Por isso recomendo sempre trocar todos os contra-barras do percurso pela barra comum pra não ter risco! :)
Agora sim! Podemos finalmente criar a macro do percurso. Recomendo usar >> IN << se for percurso de arquivo pra leitura e >> OUT << se for arquivo de gravação!
OBS: Lembrando que >> TODA << macro que criamos deve ser em Maiúsculo pra não ter risco do programa confundir com alguma variável comum! 
#define IN "C:/Prova/NOTAS.txt"
#define OUT "C:/Prova/RESULTADO.txt"
Agora o percurso de cada arquivo já está sendo representado pela palavra IN ou OUT!
E agora como vamos escrever o parâmetro do percurso quando abrir o arquivo?
FILE *in = fopen(IN , "r");
FILE *out = fopen(OUT, "w");
OBS: Lembrando que a palavra IN substitui o percurso >>TODO<< que definimos lá no começo do programa, por isso não precisamos colocar as aspas, pois já estão no #define!
 
*******************************************************************************
Regra Importante: 
Após abrir qualquer arquivo, seja pra leitura ou gravação, é >> OBRIGATÓRIO << verificar se houve algum erro na abertura do arquivo!
if(in == NULL){
 puts("Erro ao abrir o arquivo!");
 exit(1);
}
OBS: Muito cuidado pra não confundir com >> *in << que representa o conteúdo do ponteiro! Precisamos verificar se >> in << é igual a NULL, ou seja, se o ponteiro em si é NULL! 
Nesse caso, num programa que depende da leitura/gravação do arquivo, faz sentido prosseguir? x.x
Não! É por isso que temos que usar a função >> exit << para encerrar o programa completamente. Imagine como se fosse uma saída de emergência em caso de erro.
OBS: A função exit também pertence ao protótipo <stdlib.h> e encerra o programa inteiro, como se fosse uma saída de emergência! Ela recebe um número inteiro como parâmetro, pode ser qualquer número, recomendo sempre usar >> 1 << pra facilitar.
OBS2: Não esqueça de colocar o #include <stdlib.h> no começo do programa! Senão a função exit não vai funcionar! E além disso, a macro NULL não será reconhecida!
*******************************************************************************
- De onde vem esse NULL? :o
OBS: A partir daqui recomendo nem piscar! :D 
Vamos por partes: Lembra que uma palavra com todas as letras maiúsculas é na verdade uma macro?
OBS: Nunca ouviu falar em Macro? Recomendo que "Pause" esse resumo e dê uma olhada no trecho "Como utilizar macro em vetores?" no "Resumo_Vetor"! :)
A explicação mais completa é a seguinte: Dentro do protótipo da <stdlib.h> tem a seguinte macro: #define NULL 0
Então já sabemos que durante
a compilação do programa, todo lugar onde tiver escrito NULL será substituído pelo valor zero!
Então na verdade: if(in == NULL) é exatamente o mesmo que if(in == 0)
OBS: Zero é um endereço de memória que >> Somente << o Sistema Operacional tem permissão pra acessar! Então qualquer ponteiro que "aponta" pra esse endereço, é um ponteiro inválido! Por isso a macro NULL é usada pra representar erro na abertura do arquivo!
------------------------------------//-----------------------------------------
- Atalho na prevenção de erro: (Opcional)
Podemos usar if(!in) ao invés de if(in == NULL) 
Qualquer condição em C retorna >> Zero << se for >> Falsa << ou um valor >> Diferente de zero << se for >> Verdadeira <<!
Escrever if(in == 0) é exatamente o mesmo que if(!in)
OBS: A exclamação >> ! << significa >> NOT <<! 
if(!in) significa em outras palavras: Se a condição >> Não << é verdadeira (Ou seja, igual a zero!), então executa o bloco do if.
if(in) significa em outras palavras: Se a condição é Verdadeira (Ou seja, diferente de zero!), então executa o bloco do if.
OBS: Não entendeu absolutamente nada dessa explicação? Eu avisei pra não piscar, não foi? :D
Mas sem problemas! Esse atalho é totalmente opcional! Recomendo que decore urgentemente uma dessas formas! :)
-------------------------------------//----------------------------------------
- Como abrir mais de um arquivo na mesma função?
#include <stdio.h>
#include <stdlib.h>
#define IN "C:/Prova/NOTAS.txt"
#define OUT "C:/Prova/RESULTADO.txt"
int main (void){
 FILE *in, *out;
 FILE *in = fopen (IN, "r");
 if(!in){
 puts("Erro ao abrir o arquivo!");
 exit(1);
 }
 FILE *out = fopen (OUT, "w");
 if(!out){
 puts("Erro ao abrir o arquivo!");
 exit(1);
 }
 fclose(in);
 fclose(out);
 return 0;
} 
Primeiro declara todos os ponteiros de arquivo e depois abre um de cada vez!
OBS: É bom saber disso, mas não precisa se preocupar tanto, porque em quase todas as provas é obrigatório organizar/dividir o programa em várias funções (Programa Modularizado), ou seja, uma função pra ler o arquivo e outra pra gravar. 
 
----------------------------------//-----------------------------------------
- Como fazer leitura em arquivo? (Usando While)
Usando a função >> fscanf << que é idêntica a função scanf! A única diferença é que ela recebe um parâmetro a mais: O nome da ligação do arquivo. (O ponteiro in)
Ex: Faça um programa que leia o arquivo NOTAS.txt que contém 3 notas por linha e exiba a média de cada aluno: 
#define IN "C:/Prova/NOTAS.txt"
int main (void){
 float n1, n2, n3;
 
 FILE *in = fopen(IN, "r");
 if(!in){
 puts("Erro ao abrir o arquivo!");
 exit(1);
 }
OBS: Como o enunciado só pede pra exibir a média de cada aluno, podemos resolver tudo isso com uma única repetição 'While'! Por isso nesse caso >> NÃO << tem necessidade de armazenar as notas em vetor!
 while(fscanf(in, "%f%f%f",&n1, &n2, &n3) == 3){
 printf("Media do aluno: %.1f\n", (n1+n2+n3)/3));
 }
 fclose(in);
 return 0;
}
A função fscanf é só esse trecho aqui:
fscanf(in, "%f%f%f",&n1, &n2, &n3)
O primeiro parâmetro é a ligação que criamos no começo (FILE *in) e após isso, é absolutamente idêntico ao scanf!
OBS: A função fscanf sempre retorna a >> Quantidade << de elementos lidos! Então como cada aluno possui 3 notas, a cada leitura feita, o fscanf precisa retornar o número 3! 
Então a repetição while é basicamente a seguinte: 
while(fscanf(in, "%f%f%f",&n1, &n2, &n3) == 3){
Em outras palavras: >>Enquanto<< o fscanf conseguir ler 3 valores....executa o que tiver no bloco entre chaves. 
Se caso o fscanf retornar qualquer valor diferente de 3, a repetição será encerrada, assim como a leitura do arquivo! 
OBS: Como o enunciado deixou claro que o arquivo contém sempre 3 notas por linha, se caso o fscanf não retornar o valor 3 quer dizer que o arquivo chegou no fim!
----------------------------------//------------------------------------------
- Como fazer leitura em arquivo? (Usando 'for')
Ex: Faça uma função que recebe como parâmetro um vetor e leia o arquivo NOTAS.txt que contém uma nota por linha e retorne a quantidade de alunos lidos:
Considere que a turma possui >> No Máximo << 30 alunos. 
OBS: Lembrando que como é uma nota por linha, então cada linha do arquivo é referente a um aluno! 
E como são >> No Máximo << 30 alunos, vamos usar a macro: #define MAX 30
OBS2: Lembrando que escrever >> float *notas << no parâmetro é exatamente o mesmo que >> float notas[] <<!
int le_arquivo (float *notas){
 int i;
 
 FILE *in = fopen(IN, "r");
 if(!in){
 puts("Erro ao abrir o arquivo!");
 exit(1);
 }
 
 for(i=0; i<MAX && fscanf(in, "%f", &notas[i]) == 1 ; i++);
 
 fclose(in);
 return i;
}
Como só precisamos preencher o vetor e retornar a quantidade de alunos lidos, podemos usar o próprio contador >> i << pra representar a quantidade de alunos! Isso já facilita bastante, pois o contador 'i' já faz parte do 'for'! :)
E além disso, percebe que nesse caso não tem necessidade de colocar nada no bloco entre chaves do 'for'? 
Pois já conseguimos resolver tudo que foi pedido na mesma linha de declaração do 'for'! Nesse caso, ao invés de deixar o bloco vazio é só colocar >> ; << no fim!
OBS: Quando o enunciado especifica a quantidade Máxima de algo, é >>Obrigatório<< colocar a condição (i < MAX)! Apesar da condição de retorno da fscanf já ser suficiente pra encerrar a leitura no fim do arquivo. Mas imagina se esse mesmo arquivo armazenasse 60 linhas, sem essa condição, vamos acabar acessando posições inválidas do vetor!
OBS2: Recomendo usar sempre o 'for' quando a leitura envolver vetores ou quando precisamos descobrir a quantidade de algo! (alunos nesse caso) 
Tirando esses casos recomendo usar while!
------------------------------------//-----------------------------------------
- Como fazer gravação em arquivo?
Usando a função >> fprintf << que é idêntica a função printf! A única diferença é que ela recebe um parâmetro a mais, o ponteiro de "ligação" do arquivo. 
Ex: Temos um vetor já preenchido com 10 notas e queremos gravar essas notas no arquivo RESULTADO.txt (Uma nota em cada linha) e o enunciado pede que vc siga o modelo abaixo.
Exemplo de como fica o arquivo RESULTADO.txt após rodar o programa (com 4 notas):
Notas:
8.3
7.5
9.2
5.7
OBS: No enunciado de >>TODA<< P3 vem uma tabela de exemplo do resultado esperado! Ou seja, o seu programa deve exibir exatamente naquele formato do exemplo!
Primeiro passo é abrir o arquivo RESULTADO.txt para gravação:
#define OUT "C:/Prova/RESULTADO.txt"
#define MAX 10
 
int main(void){
 float notas[MAX];
 FILE *out = fopen(OUT, "w");
 if(!out){
 puts("Erro ao abrir o arquivo!"):
 exit(1);
 }
 preenche_vetor(notas, MAX);
//Após abrir o arquivo e como já temos o vetor preenchido, é só chamar a função fprintf pra escrever os dados no arquivo.
 fprintf(out, "Notas:\n\n");
 for(i=0;i<MAX;i++){
 fprintf(out, "%.1f\n",notas[i]);
 }
 fclose(out);
 return 0;
}
Da mesma forma como fazemos pra imprimir na tela um vetor, é o mesmo esquema pra gravar no arquivo! Também vamos precisar usar uma repetição 'for' pra passar por todas as posições do vetor.
Mas cuidado! Percebeu que a mensagem "Notas:" só aparece uma >> ÚNICA << vez e no começo do exemplo? 
Por isso temos que chamar a função fprintf >>ANTES<< de começar a gravar os valores do vetor! Ou seja, antes da repetição 'for'! Se colocar dentro do 'for' a mensagem "Notas: " será exibida 10 vezes!
OBS: Como na P3 precisamos sempre deixar tudo de acordo com o modelo do enunciado, então precisamos pular >> 2 << linhas >> Antes << de imprimir
os valores do vetor! fprintf(out, "Notas:\n\n") 
E como no exemplo é exibido uma nota em cada linha, só precisamos usar um único >> \n << no fprintf dentro da repetição!
fprintf(out, "%.1f\n",notas[i]);
OBS: O resultado do exemplo exibe os valores do vetor com uma única casa decimal!
Então é só usar >> %.1f << que representa a quantidade de casas decimais que vão ser exibidas!
------------------------------------//----------------------------------------
- Como fechar um arquivo?
Usando a função fclose.
Ex: fclose(in); 
Ela recebe como parâmetro o ponteiro de ligação do arquivo.
É >> Obrigatório << fechar todos os arquivos >>ANTES<< de encerrar o programa! O ideal é assim que vc terminar de usar um arquivo, já chama a função fclose pra fechar. Se caso esquecer, perde alguns décimos e é algo super simples, então cuidado!
Em toda questão que envolve arquivo, assim que terminar, recomendo verificar se fechou todos os arquivos antes de passar pra próxima questão! 
------------------------------------//-----------------------------------------
- Observação Importante:
A leitura em arquivo é sempre >> SEQUENCIAL <<!!!
FILE *in = fopen(IN, "r");
Após abrir um arquivo, o ponteiro in "aponta" pro começo do arquivo! Ou seja, o primeiro valor da primeira linha! E a única forma de avançar com esse ponteiro é lendo cada um de seus valores >> Em ordem! <<
EX: Faça um programa que leia o arquivo CONCURSO.txt que contém em cada linha: Código do candidato, nota final e a nota mínima de cada um dos 5 cursos escolhidos pelo candidato. (Em ordem de preferência)
Caso o candidato seja aprovado num dos cursos, exiba uma mensagem parabenizando.
Arquivo CONCURSO.txt:
120 8.0 7.5 6.0 7.0 6.5 8.5 (Primeira linha / Primeiro Candidato)
121 7.0 6.0 5.5 6.5 8.5 8.0 (Segunda linha / Segundo Candidato)
Vamos analisar a situação do primeiro candidato: 
Como sua nota é 8.0 e a nota mínima exigida pelo primeiro curso escolhido é 7.5 
Então acabamos de descobrir que ele passou no primeiro curso! E agora já podemos ler as informações do segundo candidato? Simples assim? :o
NÃO! Muito cuidado! Como a leitura em arquivo é >> Sequencial << a única forma de avançar no arquivo é lendo todos os dados em ordem >> Um por Um <<! 
Por isso que a única forma de avançar o arquivo até o começo das informações do segundo candidato é lendo as 4 notas restantes do primeiro candidato! >>Todos<< os valores que restaram na primeira linha! 
Como seria esse trecho em código? (O arquivo já está aberto para leitura)
while(fscanf(in, "%d%f",&cod, &nota) == 2){
	qtd = 0;
 achou = 0;
	for(i=0;i<5;i++){
	 fscanf(in, "%f",&min);
 qtd++;
 if(nota >= min){
 achou = 1;
		 printf("Candidato %d - Parabens!\n", cod);
		 for(i=qtd;i<5;i++){
		 fscanf(in, "%f",&min);
 }
	 }
	}
 if(achou == 0) printf("Candidato %d - Nao foi aprovado!",cod);
}
Primeiro passo é ler o código e a nota do candidato e logo em seguida criar uma repetição 'for' pra ler a nota mínima de cada um dos 5 cursos e ir comparando com a nota do candidato.
Mas percebe que assim que descobrimos o curso que o candidato foi aprovado, não precisamos mais testar nada e podemos simplesmente avançar o arquivo? :)
Esse 'for' serve especialmente pra avançar no arquivo:
for(i=qtd;i<5;i++){
 fscanf(in, "%f",&min);
}
Mas pra fazer isso, precisamos saber quantas notas já lemos, por isso é necessário criar um contador pra ir somando a quantidade de notas lidas, pois dessa forma, usando >> i = qtd; << podemos continuar a leitura daí em diante!
E a variável auxiliar 'achou' indica se um candidato não foi aprovado em nenhum curso. Inicializamos ela com o valor zero e trocamos esse valor pra 1 (Ou qualquer valor diferente de zero) >> Somente se << o candidato for aprovado num dos cursos! 
if(achou == 0) printf("Candidato %d - Nao foi aprovado!",cod);
OBS: Nesses casos sempre vamos precisar criar uma repetição 'for' pra ir lendo o que sobrou e com isso, avançar no arquivo! E como vamos precisar de um contador e uma variável auxiliar para >> CADA << candidato, é necessário inicializar ambas assim que ler as informações de um novo candidato! (No começo do while!)
OBS: A única forma de "resetar" a leitura do arquivo para o começo é fechando com a função fclose e abrindo novamente!
--------------------------------------//--------------------------------------

Teste o Premium para desbloquear

Aproveite todos os benefícios por 3 dias sem pagar! 😉
Já tem cadastro?

Outros materiais