2010-07-05 8 views
7

Deseo que un archivo se elimine del disco solo cuando está cerrado. Hasta ese momento, otros procesos deberían poder ver el archivo en el disco y leer su contenido, pero eventualmente después del cierre del archivo, debería eliminarse del disco y dejar de estar visible en el disco para acceder a otros procesos.¿Cómo puedo eliminar un archivo cuando se cierra en C++ en Linux?

+6

¿Quiere decir que todo el proceso debería poder ver el ** nombre ** del archivo en su directorio?Porque si, como dices, lo que necesitas que vean son solo los ** contenidos **, entonces una 'rm' del nombre del archivo _hace_ los deja utilizables por todos los procesos que tienen el archivo abierto, y el archivo desaparece cuando el último proceso lo cierra para que no esté abierto en ningún proceso. –

+0

Sí, debe ver el nombre del archivo, de modo que cualquier proceso nuevo invocado después de la eliminación vea el archivo en el disco hasta que finalice el proceso original que eliminó el archivo. – WilliamKF

+1

Desde mi comprensión de la semántica del sistema de archivos Unix, esto no es posible, al menos no sin condiciones de carrera. Es posible que puedas hacer algo con un trabajo periódico ejecutando 'lsof', pero eso me parece una mala idea. ¿Qué estás realmente tratando de lograr? – Novelocrat

Respuesta

8

Abra el archivo, luego elimínelo mientras está abierto. Otros procesos podrán usar el archivo, pero tan pronto como se cierren todos los identificadores al archivo, se eliminará.

Editar: basado en los comentarios WilliamKF agregó más tarde, esto no logrará lo que quiere - mantendrá el archivo hasta que se cierren todos los identificadores, pero la entrada de directorio para el nombre de archivo desaparecerá tan pronto como llame al unlink/remove.

+0

Usando unlink()? – WilliamKF

+2

@WilliamKF: puede usar 'desvincular' o' eliminar'. –

+5

Lo sentimos, pero William dice que el nombre del archivo debe estar visible en el sistema de archivos. La estrategia "eliminar, pero mantenerlo abierto" no funcionará para eso; dejará el archivo allí, pero dado que el número de entradas de directorio que apuntan a él (de los cuales puede haber más de uno) es cero, no proceso que todavía no lo tiene abierto lo encontrará. (Tampoco los otros verán una entrada en el sistema de archivos.) –

0

No estoy seguro, pero podría probar remove, pero se parece más al estilo c.

Tal vez boost::filesystem::remove?

bool remove(const path & ph); 

Condición previa: ph.empty()

Devuelve: El valor de exists (ph) antes del establecimiento de la condición posterior.

Condición posterior: existe (ph)

Lanza: si ph.empty() || (existe (ph) & & is_directory (ph) & &! is_empty (ph)). Ver la lógica del camino vacío.

Nota: Los enlaces simbólicos son ellos mismos eliminados, en lugar de lo que señalan para ser eliminados.

Justificación: No tirar cuando existe (ph), porque no tirar:

funciona correctamente si el pH es una enlace simbólico colgado. Es levemente más fácil de usar para muchos casos de uso común . Es ligeramente más alto nivel- porque implica el uso de la semántica Condición posterior en lugar de la semántica de efectos, que se especifica en el algo menor nivel términos de interacciones con el sistema operativo . Sin embargo, existe una pequeña disminución en la seguridad de debido a que algunos errores se deslizarán por lo que de lo contrario habrían sido detectados. Por ejemplo, , un nombre de ruta mal escrito puede ir indetectable durante mucho tiempo.

La versión inicial de la biblioteca arrojó una excepción cuando la ruta no existía; se modificó para reflejar quejas de los usuarios.

Puede crear una clase contenedora que cuente las referencias, utilizando uno de los métodos anteriores para eliminar el archivo.

class MyFileClass{ 

    static unsigned _count; 
public: 
    MyFileClass(std::string& path){ 
    //open file with path 
    _count++; 
    } 

    //other methods 

    ~MyFileClass(){ 

     if (! (--_count)){ 

      //delete file 
     } 

    } 

    }; 

    unsigned MyFileClass::_count = 0; //elsewhere 
0

Uso unlink

#include <unistd.h> 

int unlink(const char *pathname); 

unlink() elimina un nombre de la sistema de archivos. Si ese nombre fue el último enlace a un archivo y ningún proceso tiene el archivo se abre, el archivo se borra y el espacio que estaba utilizando se hace disponible para su reutilización.

Si el nombre es el último enlace a un archivo pero cualquier proceso sigue teniendo el archivo abrir el archivo permanecerá en existencia hasta el descriptor de archivo pasado refiriéndose a que se cierre.

Si el nombre hace referencia a un enlace simbólico, se elimina el enlace.

Si el nombre se refiere a un socket, FIFO o dispositivo el nombre para que se retira pero los procesos que tengan por objeto abierto puede seguir utilizándolo.

2

Los archivos abiertos en Unix son contados por referencia. Cada open(2) incrementa el contador, cada close(2) lo disminuye. El contador es compartido por todos los procesos en el sistema.

Luego hay un link count para un archivo de disco. El archivo nuevo obtiene un recuento de uno. El recuento se incrementa mediante la llamada al sistema link(2). El unlink(2) lo disminuye. El archivo se elimina del sistema de archivos cuando este recuento se reduce a cero.

La única manera de lograr lo que pide es abrir el archivo en un proceso, luego unlink(2). Otros procesos podrán open(2) o stat(2) es entre open(2) y unlink(2). Suponiendo que el archivo tenía solo un enlace, se eliminará cuando todos los procesos que lo tienen abierto lo cierren.

0

creo que necesita para ampliar su noción de “cerrar el archivo” más allá de fclose o std::fstream::close a lo que usted tiene la intención de hacer. Eso podría ser tan simple como

class MyFile : public std::fstream { 
    std::string filename; 
public: 
    MyFile(const std::string &fname) : std::fstream(fname), filename(fname) {} 
    ~MyFile() { unlink(filename); } 
} 

o puede ser algo mucho más elaborado. Por lo que sé, incluso puede ser mucho más simple: si cierra archivos solo en uno o dos lugares en su código, lo mejor que puede hacer es simplemente unlink el archivo allí (o use boost :: filesystem :: remove, como Tom sugiere).

OTOH, si todo lo que quiere lograr es que los procesos iniciados en su proceso puedan usar el archivo, puede que no necesite mantenerlo en el disco. fork los procesos ed heredan los archivos abiertos. No se olvide de dup ellos, no sea que la búsqueda en el niño influya en la posición en el padre o viceversa.

Cuestiones relacionadas