Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   ofstream o rename fallan (https://www.clubdelphi.com/foros/showthread.php?t=91237)

aguml 08-12-2016 20:07:40

ofstream o rename fallan
 
Bueno la verdad es que no se me ocurria otro titulo. El caso es que estoy liado siguiendo aprendiendo cosas y estoy creando una mini clase la cual hace cosas basicas con archivos secuenciales pero el metodo Delete de mi clase me da problemas. Este es el codigo:
Código PHP:

int DatosPersonales::Delete(int id){
    
int retval = -1;
    
unsigned char *block;
    
long size_block_beg,size_block_end;
    
streampos pos;

    if(
filename != ""){
        
//Busco el ID a borrar del archivo
        
pos = (SearchFirst(id,NULL,false) * sizeof(DATOS)) - sizeof(DATOS);

        if(
pos >= 0){ //Si existe...
            //Abro el archivo para leer de el
            
ifstream f_infilename.c_str(), ios::binary );
            if(!
f_in.is_open()){
                
cout << "No se pudo crear el archivo " << filename << endl;
                return -
2;
            }
            
//Obtengo el tamaño de los bloques anterior y posterior al dato del id elegido
            
f_in.seekg0ios::end );
            
size_block_end f_in.tellg() - pos sizeof(DATOS);
            
f_in.seekg0ios::beg );
            
size_block_beg f_in.tellg() + pos;

            
//Creo un archivo auxiliar donde copiaré todo menos el dato del id elegido
            
ofstream f_out"aux.dat",ios::binary );
            if(!
f_out.is_open()){
                
cout << "No se pudo crear el archivo auxiliar." << endl;
                return -
2;
            }
            
//Si el tamaño del bloque anterior es mayor que 0 es porque hay datos antes y tengo
            //que meterlos en el archivo auxiliar
            
if(size_block_beg 0){
                
block = new unsigned char[size_block_beg];
                
f_in.read(block,size_block_beg);
                
f_out.write(block,size_block_beg);
                
delete[] block;
            }
            
//Si el tamaño del bloque posterior es mayor que 0 es porque hay datos despues y tengo
            //que meterlos en el archivo auxiliar
            
if(size_block_end 0){
                
f_in.seekgsizeof(DATOS), ios::cur );
                
block = new unsigned char[size_block_end];
                
f_in.read(block,size_block_end);
                
f_out.write(block,size_block_end);
                
delete[] block;
            }
            
//Cierro ambos archivos
            
f_in.close();
            
f_out.close();
            
//Elimino el archivo original y renombro el auxiliar al nombre del original
            
remove(string("_" filename).c_str());
            
rename(filename.c_str(), string("_" filename).c_str());
            
rename("aux.dat",filename.c_str());
            
retval=0;
        }
    }else{
        
retval=-3;
    }
    return 
retval;


No me da ningun aviso de que no se haya abierto bien f_out ni da ningun tipo de excepcion con el metodo read de este pero el archivo no aparece en el directorio del proyecto y a la hora de ejecutarse el rename ultimo, que es el que dejará este archivo con el nombre del original, no se renombra con lo que me quedo sin el archivo. No se que hago mal para que no aparezca el archivo aux.dat en el directorio del proyecto. Ya probé a poner la ruta completa pero tampoco funciona.
¿Pueden ayudarme?

ecfisa 09-12-2016 10:30:29

Hola.

Desconozco el por que del cálculo de los bloques para borrar un registro de manera secuencial. Pero, básicamente un borrado de ese tipo consiste en crear un archivo temporal, para luego recorrer el archivo original e ir copiando al temporal los elementos diferentes al que debe ser borrado.
Por último se borra el archivo original y se renombra al archivo temporal como el original.

Básicamente sería algo similar a este ejemplo:
Código PHP:

#include <fstream>
...
struct DatosPersonales {
  ...
  
DatosPersonales();
  
void deleteID( const int id );
  ...
private:
  
struct {
    
int  id;
    
char nombre[20];
    
char apellidos[30];
    
int  edad;
  } 
Datos;

  
charFILE_NAME;
  
charFILE_TEMP;
  ...
};

DatosPersonales::DatosPersonales()
{
  
FILE_NAME "original.dat";
  
FILE_TEMP "temporal.dat";
  ...
}

void DatosPersonales::deleteID( const int id )
{
  
std::fstream fsInFILE_NAMEstd::fstream::in );
  
std::fstream fsOutFILE_TEMPstd::fstream::out );

  while ( ! 
fsIn.eof() ) {
    
fsIn.readreinterpret_cast<char*>( &Datos), sizeofDatos ) );
    if ( !
fsIn.eof() && Datos.id != id )
      
fsOut.writereinterpret_cast<char*>( &Datos), sizeofDatos ) );
  }

  
fsIn.close();
  
fsOut.close();

  
std::removeFILE_NAME );
  
std::renameFILE_TEMPFILE_NAME );
}
... 

Uso:
Código PHP:

...
{
   
DatosPersonales dp;
   ...
   
dp.deleteID);
   ... 

Claro está que borrar de modo secuencial una estructura solo se justifica en calidad de prueba, ya que es significativamente mas eficiente hacerlo de forma aleatoria.

Saludos :)

aguml 09-12-2016 15:07:46

Lo de los bloques es para no tener que ir copiando estructura por estructura, o sea obtengo la posición del dato que quiero buscar y a partir de esa dirección obtengo el número de bytes que hay desde el inicio hasta esa posición y lo mismo para lo que hay después. Con eso hago solo dos write y me ahorro tener que recorrer todo el archivo leyendo y escribiendo dato a dato.
Lo que dices de "hacerlo de forma aleatoria" ¿que es eso?

ecfisa 09-12-2016 19:42:42

Hola.

En este enlace tenes el tema bastante bién explicado: Archivos de acceso aleatorio

Saludos :)

aguml 09-12-2016 22:50:28

Ya entendí aunque tiene algún que otro inconveniente ya que si quiero eliminar un id determinado y no están ordenados ya no sirve este método y si lo están pero no son todos correlativos también habría problemas. Para usarlo tendría que mostrar todos los registros y poner por ejemplo el contador de registros leídos delante de cada registro usando dicho contador para elegir el registro a borrar.
Sigo sin ver el porque no se crea el archivo auxiliar.

ecfisa 09-12-2016 23:03:48

Cita:

Empezado por aguml (Mensaje 511668)
...
Sigo sin ver el porque no se crea el archivo auxiliar.

Lamentablemente no puedo probar tu código por que carezco de algunas funciones y datos para hacerlo, pero si revisas el código del mensaje #2, verás que hace sin problemas esa taréa.
Es decir:
  1. Crea el archivo auxiliar
  2. Pasa los registros que no se eliminarán
  3. Elimina el archivo original
  4. Renombra el archivo auxiliar como el original
Si te pudiera resultar útil avisame y te adjunto los fuentes de la prueba.

Saludos :)

aguml 10-12-2016 13:50:58

Misterios de Windows. Cambié el nombre del archivo auxiliar de "aux.dat" a "temp.dat" y ya funciona. Sólo falla con el nombre de archivo "aux.dat". Eso me da que pensar que ha fallado algo en windows y al crear el archivo no permite hacerlo porque intente sobre escribirlo y al no existir pues... no se, son especulaciones. Luego cuando llegue intentare mover todo a otra carpeta y ver que pasa.


La franja horaria es GMT +2. Ahora son las 09:21:57.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi