Tenho um programa onde um usuário pode escrever (anexar) em um arquivo de texto escolhido para armazenar informações. Cada linha deve ter dois números e uma sequência de data (AAAA-MM-DD). Existem vários arquivos de texto diferentes nos quais o programa pode escrever, digamos "foo.txt", "bar.txt", "stroustrup.txt", e o conteúdo do arquivo pode ser parecido com este:
-18 30 2025-02-12
0 0 2025-02-01
-23 36 2025-02-27
Agora eu gostaria de adicionar uma espécie de função "desfazer", que exclui a última linha de um arquivo de texto escolhido, caso o usuário insira algo errado, por exemplo undo(const string& filename)
.
Eu sei que uma possibilidade é usar getline(file,string) continuamente, até chegar ao fim do arquivo, e escrever tudo, exceto a última entrada, em um novo arquivo, criando assim uma cópia com a linha final omitida. No entanto, sinto que deveria haver uma maneira melhor de fazer isso. Como 1. Eu teria que criar um novo arquivo, com um novo nome, para cada chamada do meu undo. E reescrever um arquivo inteiro apenas para me livrar de uma linha - uma que está sempre no final - parece um desperdício.
Usar funções seek() também é inapropriado, já que o objetivo é excluir entradas errôneas. Não posso pesquisar razoavelmente por uma string específica (já que o usuário pode inserir qualquer string boba no arquivo .txt antes de tentar desfazer).
Existe uma maneira organizada de fazer isso, ou seja, substituir a linha final por um espaço vazio ou "\n", sem precisar copiar e reescrever todo o outro conteúdo?
Na minha humilde opinião, a dificuldade é identificar a posição do arquivo onde a última linha começa. Não é uma tarefa simples porque os arquivos são projetados para serem anexados (por exemplo, uma busca binária em um arquivo é possível, mas não eficiente).
Recomendo ter um
std::vector<file-position-type>
. Para o arquivo inteiro, usestd::getline
para ler em uma linha de texto. Salve a posição do arquivo após ostd::getline
. Isso produzirá um contêiner de posições de arquivo do início de cada linha.Após o contêiner ser preenchido, você pode encontrar a posição do arquivo da última linha. Agora, você pode copiar o conteúdo do arquivo para um novo arquivo, parar quando atingir a última posição do arquivo. Ou você pode calcular o tamanho do arquivo original, menos a posição inicial da última linha de texto e "blocar cópia" de todos esses itens para um novo arquivo.
Se seu aplicativo criar o arquivo de dados, você poderá manter a posição inicial da última linha de texto, para não precisar construir o contêiner novamente.
Edição 1: Lembrando da última posição
Em vez de usar um contêiner, você pode manter a posição do arquivo do início da última linha de texto. Toda vez que você lê uma linha, você atualiza a posição anterior do arquivo. Não é necessário contêiner.
Edição 2: Linhas de texto de comprimento fixo
Se suas linhas de texto tiverem comprimento fixo, a localização do início da última linha de texto se torna um cálculo matemático. Obtenha o comprimento do arquivo. Subtraia o comprimento de uma linha de texto. Pronto.