Arquivos

Atualizado pela última vez em fevereiro de 2021.

Antes de falar sobre arquivos no contexto de memória persistente para a programação, é bom entender arquivos no contexto de informática. Se você não tiver um entendimento anterior do conceito de arquivos, recomendo a leitura desse texto, feito para o contexto da finada disciplina "Laboratório de Computação", que apresenta conceitos básicos, incluindo a identificação por seus nomes, que é bastante importante.

O conceito mais importante é que arquivos são sequências de valores, como um vetor e, tal qual um vetor, não podem haver buracos na sequência. A inserção e remoção de elementos em vetor são conceitos aplicáveis em arquivos, ou seja, você não pode sair aumentando ou diminuindo a quantidade de informações sem cuidado e provavelmente uma reorganização completa das outras informações do conjunto.

No contexto de programação, a necessidade de arquivos é bem direta: queremos poder guardar informações que ainda estarão à disposição do programa na próxima vez que ele executar.

Para programar usando arquivos é bom ter em mente que:

  1. O tempo necessário para trabalhar com informações em arquivos é muito maior que o tempo necessário para trabalhar com informações em memória RAM.
  2. A quantidade de memória RAM num computador é bem inferior à quantidade de memória secundária.

Ficar realizando operações repetidas ou sem utilidade real já era um problema importante antes dos arquivos, a importância disso aumenta bastante agora. Ler todo o arquivo para a memória RAM, processar e depois re-escrever as informações do arquivo não é uma estratégia viável. Pode ser que as informações do arquivo não caibam na memória RAM.

Arquivos texto versus arquivos binários

Podemos classificar os arquivos de acordo com o tipo de representação da informação que usam. Um arquivo é texto se a informação é guardada de texto (símbolos gráficos usados na escrita). Como o computador só trabalha com números, o texto precisa estar codificado em algum formato de representação de caracteres, geralmente, o UTF-8. Se a informação não está na forma de texto, então dizemos que o arquivo é binário.

Os arquivos binários podem representar uma estrutura de dados. Nesse caso, costumamos dizer que o arquivo binário é um arquivo tipado, porque ele guarda diversas informações de um mesmo tipo. Em IAlg, a única estrutura de dados apresentada é o vetor e portanto, um arquivo binário pode ser usado para representar um vetor. Em IAlg, costuma-se usar os termos arquivo binário e arquivo tipado com o mesmo significado.

Na linguagem C++, a única diferença entre os arquivos texto e tipados, é a forma como fazemos as operações de leitura de escrita. No primeiro caso, a leitura é feita numa repetição caractere a caractere até se decidir que não é mais necessário ler ou escrever caracteres. Os comandos são os mesmos que já se usava antes do assunto arquivos: << e >>. Para os arquivos tipados, serão lidos vários bytes "de uma vez" e se usa os comando write e read. Você pode ter encontrado alguém dizendo que existem diferenças na declaração da variável que representa o arquivo, como o uso da flag ios::binary, mas isso não é verdade. Aliás, o uso de flags na declaração de arquivos é quase sempre desnecessário e perigoso.

Se um programa guarda informações num arquivo texto, então a informação fica facilmente acessível para humanos, que podem usar qualquer programa editor de texto para ler ou modificar as informações armazenadas lá. Se as informações são guardadas num arquivo binário, então somente um programa com conhecimento prévio sobre a forma como as informações estão organizadas no arquivo poderá trabalhar com aquelas informações, geralmente apenas o próprio programa em questão. Por outro lado, guardar informações em arquivos texto dificulta a eficiência.

Diferenças em relação à eficiência

Se as informações são guardadas na forma de texto, a quantidade de espaço tende a ser altamente variável. Por exemplo: vamos supor que um programa vai guardar valores monetários num arquivo texto. A quantia 3.14 exige pelo menos 4 bytes (os quatro caracteres) para ser armazenada enquanto que a quantia 37493.62 exige pelo menos oito. Alterar esses valores num arquivo texto seria equivalente a alterar números dentro de uma string (vetor de caracteres), o que é bem mais complicado que alterar números num vetor de float. Para fazer alterações dessas quantias num vetor de float, basta fazer uma atribuição.

Imagine que você quer guardar notas de milhares de alunos num arquivo. Eventualmente a nota de alguém vai mudar e quando isso acontecer, não faz sentido ter que mexer nos dados dos outros milhares. Por isso, costumamos usar arquivos tipados, em que as alterações tendem a ser localizadas, como num vetor de float.

Problemas comuns na programação

Um dos problemas mais comuns na programação envolvendo arquivos é o uso de mais de uma variável para representar o mesmo arquivo ao mesmo tempo. Exemplo:

ifstream arq1("nome"); ... // comandos para ler informacoes de arq1 ofstream arq2("nome"); // arq2 e arq1 sao o mesmo arquivo ... // comandos para escrever informacoes em arq2

As variáveis que representam arquivos podem ser vistas como registros com informações que permitem o controle sobre as informações do arquivo propriamente dito. Ter mais de uma variável associada ao mesmo arquivo ao mesmo tempo produz comportamento indefinido pois as informações de controle podem ser atualizadas em uma sem ser atualizadas na outra, fazendo com que as variáveis representem um estado incorreto do arquivo. Uma forma pouco visível de produzir isso é fazer a passagem de parâmetros (do tipo arquivo) por cópia; várias linguagens de programação nem permitem a passagem de arquivos por cópia.

Para evitar isso, pode-se usar modularização (arquivos como variáveis locais de subprogramas), variáveis com escopo reduzido (declaradas dentro de outros comandos), ou até o mesmo o comando close.

Esta página é mantida por Bruno Schneider para a disciplina de IAlg