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

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]

[code]/*

  • 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 &lt; 3; i++)
	arquivo.write(reinterpret_cast&lt;char *&gt;(&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&lt;char *&gt;(&o), sizeof(Obj));

}

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

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

cout &lt;&lt; &quot;id: &quot; &lt;&lt; o.getId() &lt;&lt; &quot;\nvalue: &quot; &lt;&lt; o.getValue() &lt;&lt; std::endl;

}

int main() {
inicializar();

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

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

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

inicializar();

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

cout &lt;&lt; endl;
imprimirItem(0);
imprimirItem(1);
imprimirItem(2);

}

[/code]

     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”.

[quote=entanglement][code]
ofstream arquivo(NOME_DO_ARQUIVO, std::ios::ate);

 arquivo.seekp(o.getId() * sizeof(Obj)); 

[/code]

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”. [/quote]

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.

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.

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:

[code]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&lt;char *&gt;(&o), sizeof(Obj));
arquivo.clear();

}[/code]

[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:

[code]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&lt;char *&gt;(&o), sizeof(Obj));
arquivo.clear();

}[/code]

[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.”

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.

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]