#+title: Curso Básico da Linguagem C
#+subtitle: Aula 15: Abertura de arquivos para escrita
#+author: Blau Araujo
#+startup: show2levels
#+options: toc:3

*  Aula 15: Abertura de arquivos para escrita

[[https://youtu.be/vL8vy3krcKc][Vídeo desta aula]]

** Modos de abertura de arquivos

Em relação ao sentido do fluxo de dados, nós podemos realizar duas operações
com arquivos abertos: leitura e escrita. Com a função =fopen=, isso é definido
em seu segundo argumento através de uma /string de modo/:

| String | Modo    | Descrição                                                                                         |
|--------+---------+---------------------------------------------------------------------------------------------------|
| ="r"=    | Leitura | Abre o arquivo para leitura a partir de seu início. Se o arquivo não existir, causa um erro.      |
| ="w"=    | Escrita | Apaga os dados originais do arquivo para escrever novos. Se o arquivo não existir, ele é criado.  |
| ="a"=    | /Append/  | Abre o arquivo para acrescentar novos dados ao seu final. Se o arquivo não existir, ele é criado. |

Na chamada de sistema =open=, as strings de modo seriam equivalentes às /flags/:

- ="r"=:  =O_RDONLY=
- ="w"=: =O_WRONLY | O_CREAT | O_TRUNC=
- ="a"=: =O_WRONLY | O_CREAT | O_APPEND=

#+begin_quote
As /flags/ múltiplas são passadas como operações /OR bit-a-bit/.
#+end_quote

*** Modos complementares

Incluindo o caractere =+= ao final da string de modo, também será possível
realizar a operação oposta:

| String | Modo              | Descrição                                                                                                                           |
|--------+-------------------+-------------------------------------------------------------------------------------------------------------------------------------|
| ="r+"=   | Leitura e escrita | Posiciona o ponteiro interno no início do arquivo para leitura e escrita. Se o arquivo não existir, causa um erro.                  |
| ="w+"=   | Escrita e leitura | Apaga os dados originais do arquivo para escrever novos e ler o que for escrito. Se o arquivo não existir, ele é criado.            |
| ="a+"=   | /Append/ e leitura  | Posiciona o ponteiro interno no fim do arquivo para leitura e para acrescentar novos dados. Se o arquivo não existir, ele é criado. |

#+begin_quote
Nós voltaremos a este assunto na próxima aula, mas deve ser evidente que
precisaremos controlar o ponteiro interno do arquivo para realizar operações
de leitura e escrita em um mesmo /stream/.
#+end_quote

*** Modos texto e binário

Sistemas /Unix-like/ não fazem distinção entre arquivos texto e binários em
operações de entrada e saída (I/O). Portanto, o caractere =b=, que pode ser
incluído ao final ou entre os caracteres da string de modo, não terá efeito
e só precisaria ser utilizado no caso da possibilidade do programa ser
portado para outros sistemas.

** Modos de escrita

Em termos gerais, as etapas de trabalho com arquivos abertos para escrita ou
/append/ são os mesmos de quando falamos da leitura:

- Abertura do arquivo para obter um /stream/;
- Processamento dos dados;
- Fechamento do stream.

*** Abertura de um arquivo para escrita ("w")

Neste exemplo, o arquivo =linha.txt= será criado (ou truncado, se já existir)
para receber uma linha digitada pelo usuário no terminal:

#+begin_src c
// Abertura do arquivo para escrita...
char *file = "linha.txt";
FILE *stream = fopen(file, "w");
if (!stream) {
    perror("Erro na abertura do arquivo");
    return EXIT_FAILURE;
}

// Processamento...
char line[BUFSIZ];           // Buffer para receber a linha digitada.
fgets(line, BUFSIZ, stdin);  // Lê a digitação no terminal.
fprintf(stream, "%s", line)  // Copia a string no buffer para o arquivo.

// Fechamento do arquivo...
fclose(stream);
#+end_src

Assim, toda vez que o programa for executado, seu conteúdo será substituído
pelo que nós digitarmos (exceto na primeira vez, quando o arquivo for criado).

*** Abertura de um arquivo para append ("a")

Para que o arquivo =linha.txt= receba novas linhas a cada execução do exemplo
anterior, basta trocar a string de modo:

#+begin_src c
// Abertura do arquivo para append...
char *file = "linha.txt";
FILE *stream = fopen(file, "a");
if (!stream) {
    perror("Erro na abertura do arquivo");
    return EXIT_FAILURE;
}

// Processamento...
char line[BUFSIZ];           // Buffer para receber a linha digitada.
fgets(line, BUFSIZ, stdin);  // Lê a digitação no terminal.
fprintf(stream, "%s", line)  // Copia a string no buffer para o arquivo.

// Fechamento do arquivo...
fclose(stream);
#+end_src

** Notas gerais

- Enquanto o arquivo estiver aberto, nós podemos realizar diversas operações
  de escrita.
- No caso do modo ="w"=, o conteúdo anterior do arquivo só será truncado na
  sua abertura, não a cada escrita com o arquivo já aberto.
- Toda vez que algo é escrito no arquivo, seu ponteiro interno é posicionado
  no byte seguinte ao último byte escrito.
  
