HOWTO · C++

Como escrever em um arquivo em C++

Este artigo demonstra como escrever num ficheiro em C++. Aprenda sobre fluxos de ficheiros e os diferentes modos de abertura, e veja exemplos claros para gerir eficazmente as operações com ficheiros nos seus programas C++. Quer precise de acrescentar dados ou de substituir o conteúdo existente, este guia ajuda-o.

Nesta página

Use std::ofstream com o operador de inserção (<<) para escrever texto comum num ficheiro. Abra-o com std::ios::app para acrescentar dados no fim, ou use std::ios::trunc se quiser substituir o conteúdo existente. Para escrever um número conhecido de caracteres ou bytes, use a função-membro write de um fluxo; fwrite é a alternativa equivalente ao estilo de C.

Fluxos de ficheiro em C++

Os fluxos de ficheiro ligam um programa C++ a um ficheiro identificado por um nome. Inclua <fstream> e crie um std::ofstream para escrever; use std::fstream quando o mesmo fluxo precisar de permitir leitura e escrita. O operador de inserção é prático para texto formatado, e um carácter de nova linha na cadeia inicia outra linha no ficheiro. Verifique o estado do fluxo depois de o abrir e de escrever, pois um caminho aparentemente válido pode estar inacessível ou o dispositivo de armazenamento pode não estar disponível.

Execute este exemplo:

#include <fstream>
#include <iostream>

int main() {
    std::ofstream file("example.txt");
    if (!file) {
        std::cerr << "Could not open example.txt\n";
        return 1;
    }

    file << "Hello, C++!\n";
    file << "File output is ready.\n";
    file.close();
    if (!file) {
        std::cerr << "Could not finish writing example.txt\n";
        return 1;
    }

    std::cout << "Wrote example.txt\n";
    return 0;
}
Wrote example.txt

A mensagem é apresentada na consola; as duas linhas escritas através de file ficam guardadas em example.txt. Abra o ficheiro num editor de texto para verificar o conteúdo. Um std::ofstream apenas de saída, com as opções predefinidas, cria o ficheiro se a pasta que o contém existir e, normalmente, apaga o conteúdo anterior ao abri-lo.

Escrever em ficheiros com diferentes modos

O modo de abertura determina o que acontece aos dados existentes. std::ios::app posiciona cada escrita no fim do ficheiro, o que é útil para registos ou dados que devem ser acumulados. Se o ficheiro ainda não existir, abri-lo para escrita pode criá-lo, desde que o caminho e as permissões o permitam. O exemplo autónomo seguinte escreve uma linha no modo de acrescento; não precisa de um ficheiro example.txt preexistente.

#include <fstream>
#include <iostream>

int main() {
    std::ofstream file("example.txt", std::ios::app);
    if (!file) {
        std::cerr << "Could not open example.txt\n";
        return 1;
    }

    file << "A new log entry\n";
    file.close();
    if (!file) {
        std::cerr << "Could not finish writing example.txt\n";
        return 1;
    }
    return 0;
}

O caso de execução fornecido terminou com sucesso e não produziu saída na consola. O código escreve A new log entry, seguido de uma nova linha, em example.txt. Se o ficheiro já contiver dados, a nova linha é acrescentada depois deles.

Escrever e substituir conteúdo com ios::trunc

std::ios::trunc descarta o conteúdo anterior do ficheiro quando este é aberto. Abrir um std::ofstream para escrita sem std::ios::app tem, normalmente, o mesmo efeito de truncagem; especifique std::ios::trunc quando quiser tornar essa escolha explícita. Não use nenhuma destas formas se precisar de preservar os dados existentes.

#include <fstream>
#include <iostream>

int main() {
    std::ofstream file("example.txt", std::ios::trunc);
    if (!file) {
        std::cerr << "Could not open example.txt\n";
        return 1;
    }

    file << "Current report\n";
    file.close();
    if (!file) {
        std::cerr << "Could not finish writing example.txt\n";
        return 1;
    }
    return 0;
}

O caso de execução fornecido terminou com sucesso e não produziu saída na consola. O código escreve apenas Current report e uma nova linha em example.txt, substituindo o conteúdo anterior.

Escrever num ficheiro com fstream::write

Use a função-membro write do fluxo quando os dados já estiverem num buffer de caracteres e o respetivo comprimento for conhecido. A função recebe um ponteiro para caracteres e a quantidade de caracteres a escrever; não acrescenta um terminador nem uma nova linha. A quantidade é um tamanho de fluxo, pelo que passar data.size() escreve os caracteres guardados na cadeia sem incluir um carácter nulo final. Verifique o estado do fluxo após a chamada para detetar falhas de escrita. Consulte a documentação do cppreference sobre basic_ostream::write para conhecer a interface.

#include <fstream>
#include <iostream>
#include <string>

int main() {
    const std::string data = "C++ buffer data\n";
    std::fstream file("buffer.txt", std::ios::out | std::ios::trunc);
    if (!file) {
        std::cerr << "Could not open buffer.txt\n";
        return 1;
    }

    file.write(data.data(), static_cast<std::streamsize>(data.size()));
    if (!file) {
        std::cerr << "Could not write buffer.txt\n";
        return 1;
    }
    file.close();
    if (!file) {
        std::cerr << "Could not finish writing buffer.txt\n";
        return 1;
    }
    return 0;
}

O caso de execução fornecido terminou com sucesso e não produziu saída na consola. Escreve em buffer.txt os caracteres de data, incluindo a nova linha que faz parte da cadeia; não escreve um carácter nulo final.

A escrita de caracteres e a escrita de bytes diferem no facto de os dados serem ou não formatados. O operador de inserção converte os valores em texto, enquanto write e fwrite copiam os bytes do buffer sem os formatar. Copiar os bytes, por si só, não garante que cheguem inalterados ao ficheiro: um fluxo aberto em modo de texto pode continuar a traduzir os caracteres de nova linha nas plataformas que usam um fim de linha diferente, como o Windows, que converte \n em \r\n na escrita. Quando os bytes exatos importam, abra o fluxo em modo binário, por exemplo com std::ios::out | std::ios::binary | std::ios::trunc, ou passe "wb" em vez de "w" ao fopen, para que não ocorra nenhuma tradução.

Escrever num ficheiro com a função C fwrite

Para operações de entrada e saída ao estilo de C, fwrite recebe um ponteiro, o tamanho de cada elemento, o número de elementos e um FILE*. O valor devolvido é o número de elementos escritos, e não o número de bytes, a menos que cada elemento tenha tamanho um. Verifique essa quantidade, feche o ficheiro e verifique também o resultado de fclose, pois podem surgir erros de escrita em buffer durante o fecho.

#include <cstdio>
#include <cstring>
#include <iostream>

int main() {
    const char data[] = "C file output\n";
    const std::size_t size = std::strlen(data);
    std::FILE* file = std::fopen("c-output.txt", "w");
    if (file == nullptr) {
        std::cerr << "Could not open c-output.txt\n";
        return 1;
    }

    const std::size_t written = std::fwrite(data, 1, size, file);
    const int close_status = std::fclose(file);
    if (written != size || close_status != 0) {
        std::cerr << "Could not finish writing c-output.txt\n";
        return 1;
    }
    return 0;
}

O caso de execução fornecido terminou com sucesso e não produziu saída na consola. O código escreve em c-output.txt os caracteres de data, incluindo a nova linha. O modo "w" cria o ficheiro ou apaga o conteúdo anterior.

Conclusão

Para texto comum, use std::ofstream e <<. Escolha std::ios::app para preservar o conteúdo existente e acrescentar dados no fim, ou std::ios::trunc para o substituir. Use write para um buffer com comprimento conhecido e fwrite quando estiver a trabalhar com operações de entrada e saída ao estilo de C. Verifique o estado após abrir e escrever; verifique também os erros de fecho quando for necessário confirmar que os dados foram escritos por completo.

Perguntas frequentes

  1. Como posso saber se um ficheiro foi aberto? Verifique diretamente o fluxo (if (!file)) ou chame is_open() logo após a abertura. Trate a falha antes de tentar escrever.

  2. Como posso acrescentar dados sem substituir o conteúdo existente? Abra um fluxo de saída com std::ios::app. Cada escrita é encaminhada para o fim do ficheiro.

  3. O C++ cria um ficheiro que ainda não existe? Os fluxos de saída e fopen com o modo "w" podem criá-lo se a pasta que o contém existir e o processo tiver permissão. Se a pasta não existir ou não houver permissões suficientes, a abertura falha.

  4. Como posso escrever várias linhas? Insira caracteres de nova linha com << ou inclua-os no buffer passado a write. Nem write nem fwrite acrescentam terminadores de linha automaticamente.

  5. Devo fechar o ficheiro? Um fluxo de ficheiro é fechado quando é destruído, mas chamar explicitamente close() pode tornar claro quando a escrita terminou. Se for importante confirmar que os dados foram escritos, verifique o estado do fluxo depois do fecho. Para um FILE* de C, chame fclose e verifique o valor devolvido.