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.txtSem 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
CarolApós executar o arquivo greetings, o arquivo greet.txt terá:
Olá, Kamala!
Olá, Logan!
Olá, Carol!