C Arquivos (fopen e fclose)
Tudo o que os seus programas guardaram até agora morava em variáveis, e as variáveis somem quando o programa termina. A lista de compras da Ana, as notas da turma, o estoque da lojinha: rodou de novo, começou do zero. Para uma informação sobreviver, ela precisa ir para um arquivo no disco. Nesta aula você vai aprender os dois gestos que começam e terminam todo trabalho com arquivos em C: abrir com fopen e fechar com fclose. Ler e escrever de verdade ficam para as próximas aulas, Ler Arquivos e Escrever Arquivos.
- O que é o tipo
FILE *e por que você nunca mexe dentro dele. - Como abrir um arquivo com
fopene por que sempre conferir se voltouNULL. - Como fechar com
fclose, e o que acontece quando você esquece ou fecha duas vezes. - Os modos de abertura:
"r","w","a", os com+, obe o"wx"do C11. - Em que pasta o arquivo é criado, e a diferença entre caminho relativo e absoluto.
Todos os programas desta aula foram compilados com o gcc 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/c, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -o programa. A aula usa ponteiros e o NULL; se precisar, reveja Ponteiro Nulo.
A ideia: pegar um caderno na estante
Pense num caderno guardado na estante. Para anotar alguma coisa, a Ana:
- pega o caderno e abre na página certa (para ler do começo, ou na primeira página em branco, para continuar);
- lê ou escreve;
- fecha o caderno e põe de volta na estante, para não amassar e para o próximo encontrar no lugar.
Em C é igual. O fopen pega e abre o arquivo; as funções das próximas aulas leem e escrevem; o fclose fecha. E, como na vida real, pode acontecer de o caderno não estar na estante: o programa precisa estar preparado para isso.
| Com o caderno | Em C |
|---|---|
| Pegar e abrir | FILE *arq = fopen("recado.txt", "w"); |
| Dizer se é para ler, escrever do zero ou continuar | o modo: "r", "w", "a" |
| O dedo marcando a página onde você está | o FILE *, que guarda a posição |
| "O caderno não está na estante" | fopen devolve NULL |
| Fechar e guardar | fclose(arq); |
1. O primeiro arquivo
Este programa cria o arquivo recado.txt e escreve uma linha nele:
#include <stdio.h>
int main(void) {
FILE *arq = fopen("recado.txt", "w");
if (arq == NULL) {
printf("Não consegui criar recado.txt\n");
return 1;
}
fputs("Comprar pão e leite.\n", arq);
fclose(arq);
printf("Recado gravado!\n");
return 0;
}
- #include <stdio.h>
- O mesmo cabeçalho do
printf:stdioquer dizer "standard input/output", entrada e saída padrão. Tudo o que é de arquivo de texto está nele. - FILE *arq
- Uma variável do tipo ponteiro para
FILE. OFILE(assim mesmo, em maiúsculas) é uma struct da biblioteca com tudo o que ela precisa para cuidar do arquivo aberto. Você só guarda o ponteiro e o entrega às funções. O nomearqé escolha sua (muita gente usafoufp). - fopen("recado.txt", "w")
- "file open", abrir arquivo. O 1º argumento é o nome (ou caminho) do arquivo; o 2º é o modo, um texto entre aspas duplas.
"w"(de write, escrever) cria o arquivo, ou apaga o que havia nele, e deixa pronto para escrita. - if (arq == NULL)
- Se não deu para abrir, o
fopendevolveNULL. É obrigatório conferir: usar umNULLcomo arquivo derruba o programa (veja "Quando dá errado"). - return 1;
- Termina avisando ao sistema que algo falhou (qualquer número diferente de 0).
- fputs("…", arq)
- "file put string", pôr um texto no arquivo. É como o
printf, mas vai para o arquivo em vez da tela. A aula Escrever Arquivos mostra todas as formas. - fclose(arq)
- "file close", fechar o arquivo. Termina de gravar o que estava pendente e devolve os recursos ao sistema. Depois dele,
arqnão pode mais ser usado.
$ gcc -std=c23 -Wall -Wextra recado.c -o recado $ ./recado Recado gravado! $ ls -l recado.txt -rw-rw-r-- 1 ana ana 22 out 17 11:32 recado.txt $ cat recado.txt Comprar pão e leite.
O arquivo apareceu na pasta, com 22 bytes, e o cat mostra o que tem dentro. São 20 letras visíveis, mas o ã ocupa 2 bytes em UTF-8 (aula Acentos e UTF-8) e o \n do fim também conta: 22. O programa terminou, mas o recado ficou: rode cat recado.txt amanhã e ele ainda estará lá.
2. Quando o arquivo não abre
Agora o contrário: abrir para ler ("r", de read) um arquivo que ainda não existe.
#include <stdio.h>
int main(void) {
FILE *arq = fopen("diario.txt", "r");
if (arq == NULL) {
printf("Não consegui abrir diario.txt\n");
return 1;
}
printf("Abri o diário!\n");
fclose(arq);
return 0;
}
$ gcc -std=c23 -Wall -Wextra abrir.c -o abrir $ ./abrir Não consegui abrir diario.txt $ echo $? 1
O "r" nunca cria nada: se o arquivo não existe, o fopen devolve NULL, e o nosso if cuidou disso. O echo $? mostra o código com que o programa terminou: o 1 do return 1.
Dizer o motivo: perror
"Não consegui abrir" é pouco. O arquivo não existe? Existe, mas é proibido? Quando o fopen falha, ele deixa o motivo anotado, e a função perror ("print error", mostrar o erro) escreve esse motivo depois do texto que você passar:
#include <stdio.h>
int main(void) {
FILE *arq = fopen("diario.txt", "r");
if (arq == NULL) {
perror("diario.txt");
return 1;
}
char linha[100];
if (fgets(linha, sizeof linha, arq) != NULL) {
printf("Primeira linha: %s", linha);
}
fclose(arq);
return 0;
}
$ gcc -std=c23 -Wall -Wextra abrir2.c -o abrir2 $ ./abrir2 diario.txt: No such file or directory
No such file or directory = "arquivo ou diretório inexistente". Esse texto vem do sistema, em inglês (a aula errno e perror explica por que, e como saber o motivo dentro do programa). O fgets lê uma linha do arquivo, como você já fez com o teclado na aula Ler uma Linha: a aula Ler Arquivos mostra os detalhes.
NULL
No such file or directory: o arquivo (ou a pasta do caminho) não existe, ou o nome está errado. Maiúsculas contam:Diario.txtnão édiario.txt.Permission denied: o arquivo existe, mas você não tem permissão para o que pediu (por exemplo, escrever num arquivo "só leitura").Is a directory: o nome é de uma pasta, e não de um arquivo.Too many open files: o programa abriu arquivos demais sem fechar (seção 5).
3. Os modos de abertura
O segundo argumento do fopen diz o que você quer fazer com o arquivo. Os três principais são "r", "w" e "a", e a diferença entre "w" e "a" é a que mais pega iniciante. Veja dois programas iguais, que só mudam o modo:
#include <stdio.h>
int main(void) {
FILE *arq = fopen("diario.txt", "w");
if (arq == NULL) {
perror("diario.txt");
return 1;
}
fputs("Abri a loja às 8h.\n", arq);
fclose(arq);
return 0;
}
O modo_a.c é a mesma coisa, com "a" (de append, acrescentar) no lugar do "w". A Ana rodou cada um duas vezes:
$ gcc -std=c23 -Wall -Wextra modo_w.c -o modo_w $ gcc -std=c23 -Wall -Wextra modo_a.c -o modo_a $ ./modo_w $ ./modo_w $ cat diario.txt Abri a loja às 8h. « duas vezes "w": só uma linha $ ./modo_a $ ./modo_a $ cat diario.txt Abri a loja às 8h. Abri a loja às 8h. Abri a loja às 8h. « mais duas com "a": acrescentou no fim $ ./abrir2 Primeira linha: Abri a loja às 8h.
O "w" apaga o arquivo inteiro na hora em que abre, antes mesmo de você escrever qualquer coisa. Rodar duas vezes deixou uma linha só. O "a" mantém o que já existia e escreve sempre no fim. E agora que o diario.txt existe, o abrir2 consegue ler a primeira linha.
| Modo | Para | Se o arquivo existe | Se não existe |
|---|---|---|---|
"r" | Ler | Lê do começo | Falha (NULL) |
"w" | Escrever | Apaga tudo e começa vazio | Cria |
"a" | Acrescentar | Mantém e escreve no fim | Cria |
"r+" | Ler e escrever | Mantém; começa no início | Falha (NULL) |
"w+" | Escrever e ler | Apaga tudo | Cria |
"a+" | Ler e acrescentar | Mantém; a escrita vai sempre para o fim | Cria |
"wx" C11 | Criar um arquivo novo | Falha (NULL): não apaga nada | Cria |
…com b: "rb", "wb", "ab", "r+b" | Arquivo binário | Igual ao modo sem b; veja Arquivos Binários | |
Os modos com + leem e escrevem no mesmo arquivo; para isso é preciso mudar de posição no meio do caminho, e a aula fseek e ftell mostra como. No dia a dia, você vai usar quase sempre os três primeiros.
Missão: a caixa tem duas abas: o programa lista.c e o arquivo lista.txt, com três itens. O programa deveria acrescentar leite e mostrar a lista inteira, mas rode e veja: os três itens antigos sumiram. Troque o modo do primeiro fopen para que a lista mostre arroz, feijão, café e leite.
#include <stdio.h>
int main(void) {
/* 1) acrescenta um item à lista */
FILE *arq = fopen("lista.txt", "w");
if (arq == NULL) {
perror("lista.txt");
return 1;
}
fputs("leite\n", arq);
fclose(arq);
/* 2) mostra a lista inteira */
arq = fopen("lista.txt", "r");
if (arq == NULL) {
perror("lista.txt");
return 1;
}
char linha[100];
while (fgets(linha, sizeof linha, arq) != NULL) {
printf("- %s", linha);
}
fclose(arq);
return 0;
}
arroz feijão café
#include <stdio.h>
int main(void) {
/* 1) acrescenta um item à lista */
FILE *arq = fopen("lista.txt", "a");
if (arq == NULL) {
perror("lista.txt");
return 1;
}
fputs("leite\n", arq);
fclose(arq);
/* 2) mostra a lista inteira */
arq = fopen("lista.txt", "r");
if (arq == NULL) {
perror("lista.txt");
return 1;
}
char linha[100];
while (fgets(linha, sizeof linha, arq) != NULL) {
printf("- %s", linha);
}
fclose(arq);
return 0;
}
A linha em branco no fim da aba lista.txt é o \n que termina o café: sem ela, o leite ficaria grudado (caféleite). No editor, a pasta dos arquivos volta ao estado das abas a cada Rodar: por isso o leite aparece uma vez só, mesmo se você rodar várias vezes. No seu computador, cada execução acrescentaria mais um.
C11 "wx": criar sem apagar
O "w" apaga sem perguntar. Às vezes é exatamente o que você não quer: um programa que cria o arquivo de configuração na primeira vez não deveria destruir a configuração que o usuário já ajustou. O x (de exclusive, exclusivo) junto do w faz o fopen falhar se o arquivo já existe:
#include <stdio.h>
int main(void) {
FILE *arq = fopen("config.txt", "wx");
if (arq == NULL) {
perror("config.txt");
return 1;
}
fputs("volume=5\n", arq);
fclose(arq);
printf("Criei config.txt\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra modo_x.c -o modo_x $ ./modo_x Criei config.txt $ ./modo_x config.txt: File exists « na segunda vez, não apagou nada $ cat config.txt volume=5
File exists = "o arquivo existe". O x só vale junto de w: "wx", "wbx" ou "w+x". No editor do guia funciona igual.
4. Em que pasta o arquivo fica?
Um nome sozinho, como "recado.txt", é um caminho relativo: ele é procurado (ou criado) na pasta de trabalho, que é a pasta em que você estava no terminal quando rodou o programa. Não é a pasta do .c, nem a do executável. Veja a Ana rodando o mesmo recado de outra pasta:
$ cd .. « sobe para /home/ana $ c/recado « o programa continua em ~/c Recado gravado! $ ls recado.txt c/recado.txt c/recado.txt recado.txt « um recado novo, criado em /home/ana
O recado.txt foi criado em /home/ana, onde a Ana estava, e não em /home/ana/c, onde o programa mora. Esse é o motivo número um do "mas o arquivo está ali!": o programa está procurando em outra pasta. Acontece muito em IDEs como VS Code e Code::Blocks, que rodam o programa a partir de uma pasta diferente da do código.
Para não depender da pasta de trabalho, use um caminho absoluto, que começa com / e diz o endereço completo. Este programa testa quatro jeitos de chegar ao mesmo arquivo:
#include <stdio.h>
void tentar(const char *caminho) {
FILE *arq = fopen(caminho, "r");
if (arq == NULL) {
perror(caminho);
return;
}
printf("%s: abriu!\n", caminho);
fclose(arq);
}
int main(void) {
tentar("recado.txt");
tentar("/home/ana/c/recado.txt");
tentar("~/c/recado.txt");
tentar("../c/recado.txt");
return 0;
}
$ gcc -std=c23 -Wall -Wextra caminho.c -o caminho $ ./caminho recado.txt: abriu! /home/ana/c/recado.txt: abriu! ~/c/recado.txt: No such file or directory ../c/recado.txt: abriu! $ cd ~ $ c/caminho recado.txt: No such file or directory /home/ana/c/recado.txt: abriu! ~/c/recado.txt: No such file or directory ../c/recado.txt: No such file or directory
| Caminho | O que significa | Resultado |
|---|---|---|
"recado.txt" | Relativo: na pasta de trabalho | Abriu em ~/c; de ~, não achou. |
"/home/ana/c/recado.txt" | Absoluto: o endereço completo | Abriu das duas pastas. |
"~/c/recado.txt" | O ~ é um atalho do terminal, não do C | Nunca abre: o fopen procura uma pasta chamada ~. |
"../c/recado.txt" | Relativo: .. é a pasta de cima | De ~/c, sobe para ~ e entra em c: abriu. De ~, procurou /home/c. |
No editor do guia, a pasta de trabalho é /home/ana, e é lá que ficam as abas que não são .c.
No Windows, os caminhos usam a barra invertida: C:\Users\ana\notas.txt. Mas dentro de uma string em C, a \ começa um escape (como \n), então escreva "C:\\Users\\ana\\notas.txt" ou, mais simples, use a barra normal, que o Windows também aceita: "C:/Users/ana/notas.txt". O erro de esquecer está em "Quando dá errado".
5. Por que fechar: fclose
O programa terminou e o arquivo ficou lá: então para que o fclose? Por dois motivos.
Motivo 1: o que ainda não foi gravado
O fputs não escreve no disco a cada chamada. Ele junta o texto numa área de espera na memória, o buffer, e só manda para o disco de vez em quando, em blocos (é muito mais rápido assim). O fclose manda o que sobrou no buffer. Quando o programa termina normalmente (com return no main ou exit), o C fecha sozinho os arquivos esquecidos, mas se o programa morre no meio (uma falha de segmentação, por exemplo), o que estava no buffer se perde. A aula Escrever Arquivos mostra isso acontecendo e o fflush, que esvazia o buffer sem fechar.
Motivo 2: o sistema tem um limite de arquivos abertos
Cada arquivo aberto ocupa um lugar numa lista do sistema, e essa lista tem tamanho. Este programa abre o mesmo arquivo sem parar, sem nunca fechar:
#include <stdio.h>
int main(void) {
int abertos = 0;
while (1) {
FILE *arq = fopen("recado.txt", "r");
if (arq == NULL) {
perror("fopen");
break;
}
abertos++; /* abre e nunca fecha */
}
printf("Consegui abrir %d vezes.\n", abertos);
return 0;
}
$ ulimit -n « o limite deste terminal 1024 $ gcc -std=c23 -Wall -Wextra abertos.c -o abertos $ ./abertos fopen: Too many open files Consegui abrir 1021 vezes.
Too many open files = "arquivos abertos demais". O limite era 1024, e três lugares já estavam ocupados desde o começo: o teclado e a tela (veja o quadro abaixo). Num programa pequeno, você nunca vai chegar perto. Num programa que roda o dia inteiro e abre um arquivo a cada pedido da lojinha, esquecer o fclose é questão de tempo para tudo parar. No editor do guia não há esse limite: com o recado.txt numa aba, o programa acima ficaria abrindo sem parar até o editor interrompê-lo, depois de 15 segundos.
fopen, escreva logo o fclose correspondente, e só depois preencha o meio. Em todos os caminhos de saída: se uma função tem um return no meio, o arquivo precisa ser fechado antes dele também.
Todo programa C começa com três FILE * prontos, declarados no stdio.h: stdin (a entrada, normalmente o teclado), stdout (a saída, a tela) e stderr (a saída de erros, também a tela, que é onde o perror escreve). Por isso fputs("Olá\n", stdout); faz o mesmo que printf("Olá\n");, e o fgets(linha, 100, stdin) lê do teclado. Você não abre nem fecha esses três (aula stdin, stdout e stderr).
Formas de abrir para escrever: qual usar
| Você quer… | Modo | Exemplo |
|---|---|---|
| Ler um arquivo que deve existir | "r" | Carregar a lista de compras. |
| Gerar o arquivo do zero a cada vez | "w" | O relatório de vendas do dia, refeito toda noite. |
| Ir juntando linhas, sem perder as antigas | "a" | Um diário, um registro (log) de pedidos. |
| Criar só se ainda não existir | "wx" C11 | A configuração padrão na primeira vez. |
| Mudar um pedaço no meio do arquivo | "r+" (ou "r+b") | Corrigir a nota de um aluno (aula fseek). |
| Guardar os bytes da memória | "wb" / "rb" | O "save" de um jogo (aula Arquivos Binários). |
Quando dá errado
Falha de segmentação: não conferiu o NULL
#include <stdio.h>
int main(void) {
FILE *arq = fopen("diario.txt", "r");
char linha[100];
fgets(linha, sizeof linha, arq);
printf("%s", linha);
fclose(arq);
return 0;
}
$ gcc -std=c23 -Wall -Wextra semteste.c -o semteste $ rm diario.txt $ ./semteste Falha de segmentação (imagem do núcleo gravada) ./semteste
O que aconteceu: sem o diario.txt, o fopen devolveu NULL, e o fgets tentou ler de um ponteiro nulo. O compilador não avisa nada: o erro só aparece ao rodar, e só no dia em que o arquivo faltar. No editor do guia, a mesma falha termina com o código 139.
Como resolver: todo fopen é seguido de if (arq == NULL) { perror(…); return 1; }, sem exceção.
$ ./pasta relatorios/maio.txt: No such file or directory $ mkdir relatorios $ ./pasta Relatório criado.
O que aconteceu: o programa fez fopen("relatorios/maio.txt", "w"). O "w" cria o arquivo, mas não cria pastas: se relatorios não existe, falha.
Como resolver: crie a pasta antes (no terminal, com mkdir), ou grave na pasta de trabalho. O C padrão não tem uma função para criar pastas; no Linux existe a mkdir do <sys/stat.h>, que não é assunto desta aula.
$ chmod 444 diario.txt « deixa o arquivo "só leitura" $ ./modo_w diario.txt: Permission denied $ chmod 644 diario.txt « devolve a permissão de escrita
O que aconteceu: "permissão negada". O arquivo existe, mas está marcado como só leitura, e o "w" pediu para escrever. O mesmo acontece ao tentar criar arquivos em pastas do sistema, como /etc.
Como resolver: grave numa pasta sua (dentro de /home/ana), ou confira as permissões com ls -l.
$ gcc -std=c23 -Wall -Wextra aspas.c -o aspas
aspas.c: In function ‘main’:
aspas.c:4:37: error: passing argument 2 of ‘fopen’ makes pointer from integer without a cast [-Wint-conversion]
4 | FILE *arq = fopen("recado.txt", 'r');
| ^~~
| |
| int
In file included from aspas.c:1:
/usr/include/stdio.h:272:44: note: expected ‘const char * restrict’ but argument is of type ‘int’
272 | const char *__restrict __modes)
| ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
O que aconteceu: 'r', com aspas simples, é um caractere (um número, para o C; veja Caracteres). O modo precisa ser um texto, com aspas duplas. A nota mostra o que o fopen esperava: const char *, um texto. O Clang do editor diz incompatible integer to pointer conversion passing 'int' to parameter of type 'const char *'.
Como resolver: fopen("recado.txt", "r"), com aspas duplas.
$ gcc -std=c23 -Wall -Wextra windows.c -o windows
windows.c: In function ‘main’:
windows.c:4:47: error: incomplete universal character name \U
4 | FILE *arq = fopen("C:\Users\ana\notas.txt", "r");
| ^
O que aconteceu: numa string, \U começa um escape que espera o código de um caractere Unicode, e sers não é um código. O \a e o \n do caminho também seriam escapes (um bipe e uma quebra de linha!). O Clang do editor diz \U used with no following hex digits.
Como resolver: dobre as barras ("C:\\Users\\ana\\notas.txt") ou use a barra normal ("C:/Users/ana/notas.txt").
double free: fechou duas vezes
$ gcc -std=c23 -Wall -Wextra fecha2.c -o fecha2
fecha2.c: In function ‘main’:
fecha2.c:11:5: warning: pointer ‘arq’ used after ‘fclose’ [-Wuse-after-free]
11 | fclose(arq);
| ^~~~~~~~~~~
fecha2.c:9:5: note: call to ‘fclose’ here
9 | fclose(arq);
| ^~~~~~~~~~~
$ ./fecha2
Fechei uma vez.
free(): double free detected in tcache 2
Abortado (imagem do núcleo gravada) ./fecha2
O que aconteceu: o fclose devolve ao sistema a memória do FILE. O segundo fclose tentou devolver de novo uma memória que já não era do programa (double free, "liberar duas vezes"; veja malloc e free), e a biblioteca do Linux abortou o programa. O gcc até avisou na compilação: "ponteiro usado depois do fclose". No editor do guia, o segundo fclose passa calado e o programa termina normalmente, o que não quer dizer que esteja certo.
Como resolver: feche cada arquivo uma única vez. Se o mesmo ponteiro pode ser fechado em lugares diferentes, faça arq = NULL; depois do fclose e confira antes de fechar.
Referência rápida
| Escrita | O que faz |
|---|---|
FILE *arq; | Uma variável para um arquivo aberto. |
arq = fopen("nome.txt", "r"); | Abre para ler; NULL se não conseguir. |
fopen(nome, "w") | Cria, ou apaga e recomeça, para escrever. |
fopen(nome, "a") | Abre para acrescentar no fim; cria se não existir. |
fopen(nome, "wx") | C11: cria só se não existir. |
if (arq == NULL) { perror(nome); return 1; } | A conferência obrigatória depois de todo fopen. |
fclose(arq); | Grava o que falta e fecha. Uma vez só por arquivo. |
"recado.txt" / "/home/ana/c/recado.txt" | Caminho relativo (pasta de trabalho) / absoluto. |
stdin, stdout, stderr | Os três FILE * que já nascem abertos. |
Exercícios
1. O tipo
Complete a declaração da variável que guarda um arquivo aberto:
2. O modo do diário
Complete o modo para acrescentar uma linha no fim do diário, sem apagar as anteriores:
3. A conferência
Complete a condição que descobre se o fopen falhou:
4. O arquivo vendas.txt tem 50 linhas. O que sobra dele depois de fopen("vendas.txt", "w") seguido de fclose, sem escrever nada?
5. A Ana está em /home/ana e roda c/recado, que faz fopen("recado.txt", "w"). Onde o arquivo é criado?
6. Por que fopen("~/notas.txt", "r") devolve NULL, mesmo com o arquivo em /home/ana/notas.txt?
Missão final: gravar e ler o recado
Missão: escreva os dois fopen que faltam. O primeiro abre recado.txt para escrever; o segundo abre o mesmo arquivo para ler. Confira o NULL depois de cada um (com perror e return 1) e feche o arquivo depois de cada parte. A saída deve ser Li do arquivo: Comprar pão e leite.
#include <stdio.h>
int main(void) {
FILE *arq;
/* 1) abra recado.txt para escrever e confira o NULL */
fputs("Comprar pão e leite.\n", arq);
/* feche o arquivo */
/* 2) abra recado.txt para ler e confira o NULL */
char linha[100];
if (fgets(linha, sizeof linha, arq) != NULL) {
printf("Li do arquivo: %s", linha);
}
/* feche o arquivo */
return 0;
}
#include <stdio.h>
int main(void) {
FILE *arq;
/* 1) abra recado.txt para escrever e confira o NULL */
arq = fopen("recado.txt", "w");
if (arq == NULL) {
perror("recado.txt");
return 1;
}
fputs("Comprar pão e leite.\n", arq);
fclose(arq);
/* 2) abra recado.txt para ler e confira o NULL */
arq = fopen("recado.txt", "r");
if (arq == NULL) {
perror("recado.txt");
return 1;
}
char linha[100];
if (fgets(linha, sizeof linha, arq) != NULL) {
printf("Li do arquivo: %s", linha);
}
fclose(arq);
return 0;
}
Rode o código inicial antes de mexer: o compilador avisa que arq é usado sem valor, e o programa cai. É o mesmo problema do NULL não conferido, só que pior: ali nem houve um fopen.
Resumo
- Arquivos guardam informação depois que o programa termina. Todo trabalho começa com
fopene termina comfclose. FILE *arq = fopen(nome, modo);devolveNULLquando não consegue abrir. Confira sempre, e useperrorpara mostrar o motivo."r"lê (o arquivo precisa existir),"w"apaga e escreve,"a"acrescenta no fim,"wx"(C11) só cria se não existir. O+permite ler e escrever; obé para binário.- Um nome sem
/no começo é procurado na pasta de trabalho, a do terminal. O~não funciona nofopen. fclosegrava o que ficou no buffer e libera o lugar do arquivo; feche cada arquivo uma vez só.stdin,stdoutestderrsão arquivos que já nascem abertos.