Artigo original: File Handling in C — How to Open, Close, and Write to Files
Se você já escreveu o programa helloworld
em C antes, já sabe o básico sobre entrada e saída (I/O, input/output, em inglês) em um arquivo em C:
/* Um arquivo hello world simples em C. */
#include <stdlib.h>
// Importar as funções de IO.
#include <stdio.h>
int main() {
// Este printf é onde toda a mágica do IO de arquivos acontece!
// Legal, não é?
printf("Olá, mundo!\n");
return EXIT_SUCCESS;
}
A manipulação de arquivos é uma das partes mais importantes na programação. Em C, usamos um ponteiro de estrutura de um tipo de arquivo para declarar um arquivo:
FILE *fp;
C fornece várias funções integradas para realizar operações básicas de arquivos:
fopen()
- criar um arquivo ou abrir um arquivo existentefclose()
- fechar um arquivogetc()
- ler um caractere de um arquivoputc()
- escrever um caractere de um arquivofscanf()
- ler um conjunto de dados de um arquivofprintf()
- escrever um conjunto de dados em um arquivogetw()
- ler um número inteiro de um arquivoputw()
- escrever um número inteiro em um arquivofseek()
- definir a posição em um ponto desejadoftell()
- dar a posição atual no arquivorewind()
- definir a posição como o ponto inicial
Abrindo um arquivo
A função fopen()
é usada para criar um arquivo ou abrir um arquivo existente:
fp = fopen(const char filename,const char mode);
Existem vários modos de abertura de um arquivo:
r
- abre um arquivo no modo leituraw
- abre ou cria um arquivo de texto no modo de escritaa
- abre um arquivo no modo de inclusão (append)r+
- abre um arquivo nos modos de leitura e escritaa+
- abre um arquivo nos modos de leitura e escritaw+
- abre um arquivo nos modos de leitura e escrita
Aqui temos um exemplo de leitura de dados de um arquivo e de como escrever nele:
#include<stdio.h>
#include<conio.h>
main()
{
FILE *fp;
char ch;
fp = fopen("hello.txt", "w");
printf("Insira dados");
while( (ch = getchar()) != EOF) {
putc(ch,fp);
}
fclose(fp);
fp = fopen("hello.txt", "r");
while( (ch = getc(fp)! = EOF)
printf("%c",ch);
fclose(fp);
}
Você pode estar pensando, "Isso simplesmente imprime texto na tela. Como assim isso é entrada/saída de arquivos?"
A resposta não é óbvia para começar, precisando de um pouco de compreensão sobre como funciona o sistema UNIX. Em um sistema UNIX, tudo é tratado como um arquivo, ou seja, você pode ler e escrever neles.
Isso quer dizer que seu método printf, por exemplo, pode ser abstraído como um arquivo, já que tudo o que ele faz é escrever. Também é útil pensar nesses arquivos como streams, pois, como veremos mais tarde, é possível redirecioná-los com o shell.
O que isso tem a ver com o helloworld
e com a entrada/saída de arquivos?
Ao chamar printf
, você está simplesmente escrevendo em um arquivo especial, chamado stdout
, abreviação de standard output (saída padrão). stdout
representa a saída padrão, conforme decidido pelo seu shell, e que, geralmente, é o terminal. Isso explica o motivo de se estar imprimindo na tela.
Existem duas outras streams (ou seja, arquivo) disponíveis para você, stdin
e stderr
. stdin
representa a entrada padrão (standard input, em inglês), que o shell geralmente associa ao teclado. stderr
representa a saída de erro padrão (standard error), que o shell geralmente associa ao terminal.
Entrada/saída rudimentar de arquivos, ou como eu aprendi a montar os pipelines
Chega de teoria! Vamos logo escrever o código! O modo mais fácil de se escrever em um arquivo é redirecionar o stream de saída usando a ferramenta de redirecionamento de saída, >
.
Se quiser incluir (append, em inglês), você pode usar >>
:
# Isto terá como saída a tela...
./helloworld
# ...mas isto escreverá em um arquivo!
./helloworld > hello.txt
Sem surpresas, o conteúdo de hello.txt
será
Olá, mundo!
Vamos supor que há um outro programa chamado greet
, semelhante a helloworld
, que cumprimenta alguém que tenha um nome
que ele recebe:
#include <stdio.h>
#include <stdlib.h>
int main() {
// Inicializa um array para guardar o nome.
char nome[20];
// Ler uma string e salvá-la em nome.
scanf("%s", nome);
// Imprimir a saudação.
printf("Olá, %s!", nome);
return EXIT_SUCCESS;
}
Em vez de ler a partir do teclado, podemos redirecionar stdin
para que leia de um arquivo usando a ferramenta <
:
# Escreva um arquivo contendo um nome.
echo Kamala > name.txt
# O comando a seguir lerá um nome do arquivo e o imprimirá com a saudação na tela name from the file and print out the greeting to the screen.
./greet < name.txt
# ==> Olá, Kamala!
# Se você quisesse imprimir a saudação em um arquivo, poderia usar ">".
Observação: esses operadores de redirecionamento se encontram no bash
e em shells semelhantes.
O que ocorre de fato
Os métodos acima somente funcionam com os casos mais básicos. Se quiser fazer coisas maiores e melhores, provavelmente desejará trabalhar com os arquivos de dentro do próprio C em vez de usar o shell.
Para conseguir isso, use uma função chamada fopen
. Ela recebe dois parâmetros de string: o primeiro é o nome do arquivo e o segundo é o modo.
O modo, basicamente, são as permissões (r
para leitura, w
para escrita, a
para inclusão. Você também pode combiná-los. rw
, por exemplo, representaria poder ler e escrever no arquivo. Existem mais modos, mas esses são os mais comumente usados.
Depois de ter um ponteiro FILE
, você pode usar basicamente os mesmos comandos de entrada e saída que já usou, exceto pelo fato de que você precisa adicionar a eles o prefixo f
e de que o primeiro argumento será o ponteiro do arquivo. Por exemplo, a versão de arquivo de printf
é fprintf
.
Aqui temos um programa chamado greetings
(saudações, em inglês), que lê de um arquivo que contém uma lista de nomes e escreve as saudações em um outro arquivo:
#include <stdio.h>
#include <stdlib.h>
int main() {
// Cria os ponteiros de arquivos.
FILE *nomes = fopen("names.txt", "r");
FILE *saudar = fopen("greet.txt", "w");
// Conferir se está tudo certo.
if (!names || !greet) {
fprintf(stderr, "Erro ao abrir arquivo!\n");
return EXIT_FAILURE;
}
// Hora das saudações!
char nome[20];
// Basicamente, siga lendo até não haver mais nada para ler.
while (fscanf(nomes, "%s\n", nome) > 0) {
fprintf(saudar, "Olá, %s!\n", nome);
}
// Ao chegar ao final, imprima uma mensagem no terminal para informar ao usuário.
if (feof(nomes)) {
printf("Saudações concluídas!\n");
}
return EXIT_SUCCESS;
}
Supondo que names.txt
contenha os nomes abaixo:
Kamala
Logan
Carol
Após executar o arquivo greetings
, o arquivo greet.txt
terá:
Olá, Kamala!
Olá, Logan!
Olá, Carol!