[Dúvida] Acesso a arquivo com ios::ate não abre e in|out o substitui (C++)

6 respostas
DavidUser

Utilizando o mesmo fluxo de arquivo para gravar e ler em um arquivo os modos de acesso funcionam corretamente, mas quando os fluxos de arquivos são diferente (são abertos e fechados para cada chamada de função) a flag de modo de acesso ate está truncando o conteúdo do arquivo oque não deveria acontecer.
[size=18]Oque está acontecendo? Como abrir o arquivo e modificar um valor sem truncar seu conteúdo?[/size]

/*
 * main.cpp
 *
 *  Created on: 23/08/2011
 *      Author: david
 */

#define NOME_DO_ARQUIVO "teste.t"

#include <fstream>
using std::ifstream;
using std::ofstream;

#include <iostream>
using std::cout;
using std::endl;

#include <cstring>

class Obj {
private:
	int id;
	char value[4];
public:
	Obj(int id = -1, char value[] = "null") {
		this->id = id;
		std::strcpy(this->value, value);
	}
	virtual ~Obj() {}

	int getId() const {
		return id;
	}

	const char * getValue() const {
		return value;
	}
};

void inicializar () {
	ofstream arquivo(NOME_DO_ARQUIVO);
	Obj o;

	for (int i = 0; i < 3; i++)
		arquivo.write(reinterpret_cast<char *>(&o), sizeof(Obj));
}

void inserir(Obj &o) {
	ofstream arquivo(NOME_DO_ARQUIVO, std::ios::ate);

	arquivo.seekp(o.getId() * sizeof(Obj));
	arquivo.write(reinterpret_cast<char *>(&o), sizeof(Obj));
}

void imprimirItem(int id) {
	ifstream arquivo(NOME_DO_ARQUIVO);

	arquivo.seekg(id * sizeof(Obj));
	Obj o;
	arquivo.read(reinterpret_cast<char *>(&o), sizeof(Obj));

	cout << "id: " << o.getId() << "\nvalue: " << o.getValue() << std::endl;
}

int main() {
	inicializar();

	Obj o1(0,"aa");
	Obj o2(1,"bb");
	Obj o3(2,"ccc");

	inserir(o3);
	inserir(o2);
	inserir(o1);

	imprimirItem(0);
	imprimirItem(1);
	imprimirItem(2);

	inicializar();

	inserir(o1);
	inserir(o2);
	inserir(o3);

	cout << endl;
	imprimirItem(0);
	imprimirItem(1);
	imprimirItem(2);
}

6 Respostas

E
ofstream arquivo(NOME_DO_ARQUIVO, std::ios::ate);  
   
     arquivo.seekp(o.getId() * sizeof(Obj));

Hum… você está dando um seekp, você está indo para o local correto?

http://www.cplusplus.com/reference/iostream/ios_base/openmode/ -> ate diz que é “at end”, não “append”.

DavidUser
entanglement:
ofstream arquivo(NOME_DO_ARQUIVO, std::ios::ate);  
   
     arquivo.seekp(o.getId() * sizeof(Obj));

Hum... você está dando um seekp, você está indo para o local correto?

http://www.cplusplus.com/reference/iostream/ios_base/openmode/ -> ate diz que é "at end", não "append".

Creio que sim já que utilizei o id dos objetos para definir a sua ordenação no arquivo de acesso aleatório.

O objetivo é sobrescrever o conteúdo da posição com o novo item.

DavidUser

Descobri que o arquivo não pode ser aberto com o modo ate, mas não entendo a causa já que o arquivo esta em disco e não há proteções quanto a leitura e escrita.

DavidUser

Fiz a troca do modo de abertura de ate para in|out mas não faço a mínima ideia do porque funcionou, o correto no meu entendimento era abrir com ate já que oque eu quero realizar é uma atualização no documento e pelo que entendo o out deveria truncar o conteúdo do arquivo por completo. :shock:

void inserir(Obj &o) {
	fstream arquivo(NOME_DO_ARQUIVO, std::ios::in|std::ios::out);

	arquivo.seekp(o.getId() * sizeof(Obj));
	arquivo.write(reinterpret_cast<char *>(&o), sizeof(Obj));
	arquivo.clear();
}

[size=18][color=red]Preciso de ajuda pois não entendi como funcionou.[/color][/size]

Ah! E mais estranhamente o mesmo funciona com objetos ofstream que só deveriam utilizar de flags de saida:

void inserir(Obj &o) {
	ofstream arquivo(NOME_DO_ARQUIVO, std::ios::in|std::ios::out);

	arquivo.seekp(o.getId() * sizeof(Obj));
	arquivo.write(reinterpret_cast<char *>(&o), sizeof(Obj));
	arquivo.clear();
}

[size=24]Como isso é possível!? Entendi o conceito de forma errada?[/size][color=blue] [/color]

"Me parece razoavel a idéia de não truncar o conteúdo do texto por completo se estiver no modo in e de truncar o conteúdo contido com out, a combinação tem sentido mas não devia substituir o ate ou no caso do in ser usado para um objeto stream de saída."

ViniGodoy

in indica que você irá escrever no arquivo, e out que você quer ler do arquivo.
A posição é dada pelo ponteiro de escrita, que você sempre está movimentando com os seeks. Não vejo pq não deveria funcionar com in e out.

O arquivo será truncado apenas se você especificar também o modo std::ios::trunc

Para fazer apend, use std::ios::app e não ate.

DavidUser

Na realidade eu queria utilizar o ate mesmo, objetivo era de alterar um arquivo aleatoriamente, mas quando utilizo a flag ate não é possível abrir o arquivo, o único modo que altera o ponto específico do arquivo sem alterar os demais é com a combinação in|out, mesmo com uma instância da ofstream que não deveria servir para entrada de dados, este é meu problema de entendimento.

ate = abre o arquivo movendo os ponteiros de stream’s para o fim do arquivo.
out = abre o arquivo para gravação.
in = abre o arquivo para leitura.
trunc = descarta o conteúdo do arquivo considerando o tamanho 0.

O objetivo é abrir o arquivo e sobrescrever apenas um bloco de bytes que inicia onde o ponteiro é alterado e vai até o tamanho do objeto por completo,

assim uma simples abertura com out deveria servir para o propósito mas na realidade o conteúdo que vem antes da posição em que ocorre a gravação acaba sendo truncado,

o único modo de abertura de arquivo que não trunca o conteúdo anterior a posição e somente sobrescreve o bloco é a combinação in|out.
[color=red]
[size=24]Porque com a abertura para a gravação out eu não consigo sobrescrever um bloco do arquivo sem truncar o restante?[/color][/size]

Criado 23 de agosto de 2011
Ultima resposta 24 de set. de 2011
Respostas 6
Participantes 3