file.delete() devuelve falso aunque file.exists(), file.canRead(), file.canWrite(), file.canExecute() devuelven verdadero

StackOverflow https://stackoverflow.com/questions/991489

  •  13-09-2019
  •  | 
  •  

Pregunta

Estoy intentando eliminar un archivo, después de escribir algo en él, con FileOutputStream.Este es el código que uso para escribir:

private void writeContent(File file, String fileContent) {
    FileOutputStream to;
    try {
        to = new FileOutputStream(file);
        to.write(fileContent.getBytes());
        to.flush();
        to.close();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

Como se ve, descargo y cierro el flujo, pero cuando intento eliminarlo, file.delete() devuelve falso.

Verifiqué antes de eliminarlo para ver si el archivo existe y: file.exists(), file.canRead(), file.canWrite(), file.canExecute() todos devuelven verdadero.Justo después de llamar a estos métodos intento file.delete() y devuelve falso.

¿Hay algo que he hecho mal?

¿Fue útil?

Solución 2

Fue bastante extraño que el truco funcionó. La cosa es que cuando he leído previamente el contenido del archivo, solía BufferedReader. Después de leer, cerré la memoria intermedia.

Mientras tanto cambié y ahora estoy leyendo el contenido mediante FileInputStream. También después de terminar la lectura cierro la corriente. Y ahora que está funcionando.

El problema es que no tengo la explicación para esto.

No sé BufferedReader y FileOutputStream ser incompatibles.

Otros consejos

Otro fallo en Java. Pocas veces las encuentro, sólo la segunda en mi carrera de 10 años. Esta es mi solución, como otros han mencionado. Tengo inferior utilizado System.gc(). Pero aquí, en mi caso, es absolutamente crucial. ¿Extraño? SÍ!

finally
{
    try
    {
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
        System.gc();
    }
    catch (IOException e)
    {
        logger.error(e.getMessage());
        e.printStackTrace();
    }
}

He intentado esta cosa sencilla y parece estar funcionando.

file.setWritable(true);
file.delete();

A mí me funciona.

Si esto no funciona, intente ejecutar la aplicación Java con sudo si en Linux y como administrador cuando en las ventanas. Sólo para asegurarse de Java tiene derechos para cambiar las propiedades del archivo.

Antes de intentar eliminar / cambiar el nombre de cualquier archivo, debe asegurarse de que todos los lectores o escritores (por ejemplo: BufferedReader / InputStreamReader / BufferedWriter). Estén bien cerradas

Cuando intenta leer / escribir datos desde / a un archivo, el archivo se lleva a cabo mediante el procedimiento y no se libera hasta que se completa la ejecución del programa. Si desea realizar el borrado / cambiar el nombre de las operaciones antes de que termine el programa, entonces usted debe utilizar el método close() que viene con las clases java.io.*.

Como se comentó Jon Skeet, debe cerrar el archivo en el bloque finally {...}, para asegurarse de que siempre está cerrado. Y, en lugar de tragar las excepciones con el e.printStackTrace, simplemente no coger y añadir la excepción a la firma del método. Si no puede por cualquier razón, por lo menos hacer esto:

catch(IOException ex) {
    throw new RuntimeException("Error processing file XYZ", ex);
}

Ahora, número de la pregunta # 2:

¿Qué pasa si usted hace esto:

...
to.close();
System.out.println("Please delete the file and press <enter> afterwards!");
System.in.read();
...

¿Sería capaz de borrar el archivo?

Además, los archivos se vacían cuando están cerradas. Yo uso IOUtils.closeQuietly (...), así que utilizo el método de descarga para asegurar que el contenido del archivo están allí antes de tratar de cerrarla (IOUtils.closeQuietly no lanza excepciones). Algo como esto:

...
try {
    ...
    to.flush();
} catch(IOException ex) {
    throw new CannotProcessFileException("whatever", ex);
} finally {
    IOUtils.closeQuietly(to);
}

Así que sé que los contenidos del archivo están ahí. Ya que por lo general me importa que el contenido del archivo se escriben y no si el archivo están cerradas o no, realmente no importa si el archivo fue cerrado o no. En su caso, ya que importa, yo recomendaría cerrar el archivo usted mismo y tratar las excepciones de acuerdo.

No hay razón para que no debería ser capaz de eliminar este archivo. Me gustaría ver a ver quién tiene un alto en este archivo. En Unix / Linux, puede utilizar la utilidad lsof para comprobar qué proceso tiene un bloqueo en el archivo. En las ventanas, puede utilizar el explorador de procesos.

para lsof, es tan simple como decir:

lsof /path/and/name/of/the/file

Process Explorer puede utilizar el menú de búsqueda e introduzca el nombre del archivo que le muestre el mango que te orientará en el proceso de cierre el archivo.

Aquí hay un código que hace lo que yo creo que tiene que hacer:

FileOutputStream to;

try {
    String file = "/tmp/will_delete.txt";
    to = new FileOutputStream(file );
    to.write(new String("blah blah").getBytes());
    to.flush();
    to.close();
    File f = new File(file);
    System.out.print(f.delete());
} catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

Funciona bien en OS X. No lo he probado en las ventanas, pero sospecho que debería funcionar también en Windows. Voy a admitir también viendo un comportamiento inesperado en Windows w.r.t. El manejo de ficheros.

Si está trabajando en Eclipse IDE, que podría significar que no has cierre el archivo en el lanzamiento anterior de la aplicación. Cuando tuve el mismo mensaje de error al intentar eliminar un archivo, que era la razón. Parece, Eclipse IDE no cierra todos los archivos después de la terminación de una aplicación.

Esperamos que esto ayudará. Me encontré con un problema similar en el que no pude borrar mi archivo después de mi código java hizo una copia del contenido a la otra carpeta. Después de una extensa búsqueda en Google, I declaró explícitamente las variables relacionadas con cada operación de archivos individuales y se llama el método close () de cada operación objeto de archivo, y los puso a NULL. Entonces, hay una función llamada System.gc (), que aclarará el archivo de E / S de asignación (no estoy seguro, yo sólo digo lo que se da en los sitios web).

Aquí está mi código de ejemplo:

public void start() {
    File f = new File(this.archivePath + "\\" + this.currentFile.getName());
    this.Copy(this.currentFile, f);

    if(!this.currentFile.canWrite()){
        System.out.println("Write protected file " +
           this.currentFile.getAbsolutePath());

        return;
    }


    boolean ok = this.currentFile.delete();
    if(ok == false){
        System.out.println("Failed to remove " + this.currentFile.getAbsolutePath());
        return;
    }
}

private void Copy(File source, File dest) throws IOException {
    FileInputStream fin;
    FileOutputStream fout;
    FileChannel cin = null, cout = null;
    try {
        fin = new FileInputStream(source);
        cin = fin.getChannel();
        fout = new FileOutputStream(dest);
        cout = fout.getChannel();

        long size = cin.size();
        MappedByteBuffer buf = cin.map(FileChannel.MapMode.READ_ONLY, 0, size);

        cout.write(buf);
        buf.clear();
        buf = null;

        cin.close();
        cin = null;

        fin.close();
        fin = null;

        cout.close();
        cout = null;

        fout.close();
        fout = null;

        System.gc();

    } catch (Exception e){
        this.message = e.getMessage();
        e.printStackTrace();
    }
}

la respuesta es cuando se carga el archivo, es necesario aplicar el método de "cerrar", en cualquier línea de código, que funciona para mí

Hubo un problema de una vez en rubí donde los archivos en las ventanas necesitan un "fsync" para ser realmente capaces de dar la vuelta y volver a leer el archivo después de haberlo escrito y cerrándola. Tal vez esto es una manifestación similar (y si es así, creo que un error de Windows, en realidad).

Ninguna de las soluciones aquí enumeradas trabajado en mi situación. Mi solución fue utilizar un bucle while, tratando de eliminar el archivo, con 5 segundo límite (configurable) para la seguridad.

File f = new File("/path/to/file");

int limit = 20; //Only try for 5 seconds, for safety
while(!f.delete() && limit > 0){
    synchronized(this){
        try {
            this.wait(250); //Wait for 250 milliseconds
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    limit--;
}

Utilizando el bucle de arriba trabajaron sin tener que hacer ningún manual de recolección de basura o el establecimiento de la corriente a nulo, etc.

El problema podría ser que el archivo sigue siendo visto como abierto y bloqueado por un programa; o tal vez es un componente de su programa que había sido abierta en, así que hay que asegurarse de que usa el método dispose() para resolver ese problema. es decir JFrame frame; .... frame.dispose();

Hay que cerrar todas las corrientes o usar try-con-recursos bloque

static public String head(File file) throws FileNotFoundException, UnsupportedEncodingException, IOException
{
    final String readLine;
    try (FileInputStream fis = new FileInputStream(file);
            InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
            LineNumberReader lnr = new LineNumberReader(isr))
    {
        readLine = lnr.readLine();
    }
    return readLine;
}

Si File.delete () está enviando false entonces en la mayoría de los casos no se cerrará el mango BufferedReader. Sólo cerca y parece que funciona para mí normalmente.

Tuve el mismo problema en Windows.Solía ​​leer el archivo en Scala línea por línea con

Source.fromFile(path).getLines()

Ahora lo leo completo con

import org.apache.commons.io.FileUtils._

// encoding is null for platform default
val content=readFileToString(new File(path),null.asInstanceOf[String])

que cierra el archivo correctamente después de leerlo y ahora

new File(path).delete

obras.

  

para Eclipse / NetBeans

Reiniciar el IDE y ejecute el código de nuevo esto es sólo el trabajo truco para mí después de una hora larga lucha.

Aquí está mi código:

File file = new File("file-path");
if(file.exists()){
  if(file.delete()){
     System.out.println("Delete");
  }
  else{

       System.out.println("not delete");
  }
}

Salida:

Eliminar

Otro caso esquina que esto podría suceder:. Si lee / escribe un archivo JAR a través de un URL y luego intenta eliminar el mismo archivo en la misma sesión JVM

File f = new File("/tmp/foo.jar");
URL j = f.toURI().toURL();

URL u = new URL("jar:" + j + "!/META-INF/MANIFEST.MF");
URLConnection c = u.openConnection();

// open a Jar entry in auto-closing manner
try (InputStream i = c.getInputStream()) {

    // just read some stuff; for demonstration purposes only
    byte[] first16 = new byte[16];
    i.read(first16);
    System.out.println(new String(first16));
}

// ...

// i is now closed, so we should be good to delete the jar; but...
System.out.println(f.delete());     // says false!

La razón es que el archivo JAR interna lógica de manejo de Java, tiende a almacenar en caché entradas JarFile:

// inner class of `JarURLConnection` that wraps the actual stream returned by `getInputStream()`

class JarURLInputStream extends FilterInputStream {
    JarURLInputStream(InputStream var2) {
        super(var2);
    }

    public void close() throws IOException {
        try {
            super.close();
        } finally {

            // if `getUseCaches()` is set, `jarFile` won't get closed!

            if (!JarURLConnection.this.getUseCaches()) {
                JarURLConnection.this.jarFile.close();
            }
        }
    }
}

Y cada JarFile (más bien, la estructura subyacente ZipFile) celebraría un identificador para el archivo, desde el momento de la construcción hasta que se invoca close():

public ZipFile(File file, int mode, Charset charset) throws IOException {
    // ...

    jzfile = open(name, mode, file.lastModified(), usemmap);

    // ...
}

// ...

private static native long open(String name, int mode, long lastModified,
                                boolean usemmap) throws IOException;

Hay una buena explicación sobre este problema NetBeans .


Al parecer hay dos maneras de "fijar" la siguiente:

  • Puede desactivar el almacenamiento en caché de archivos JAR - para el URLConnection actual, o para todas las futuras URLConnections (a nivel mundial) en la sesión de JVM actual:

    URL u = new URL("jar:" + j + "!/META-INF/MANIFEST.MF");
    URLConnection c = u.openConnection();
    
    // for only c
    c.setUseCaches(false);
    
    // globally; for some reason this method is not static,
    // so we still need to access it through a URLConnection instance :(
    c.setDefaultUseCaches(false);
    
  • [CORTE ADVERTENCIA!] Puede purgar manualmente el JarFile de la caché cuando haya terminado con él. El administrador de caché es sun.net.www.protocol.jar.JarFileFactory paquete-privado, pero un poco de magia reflexión puede hacer el trabajo para usted:

    class JarBridge {
    
        static void closeJar(URL url) throws Exception {
    
            // JarFileFactory jarFactory = JarFileFactory.getInstance();
            Class<?> jarFactoryClazz = Class.forName("sun.net.www.protocol.jar.JarFileFactory");
            Method getInstance = jarFactoryClazz.getMethod("getInstance");
            getInstance.setAccessible(true);
            Object jarFactory = getInstance.invoke(jarFactoryClazz);
    
            // JarFile jarFile = jarFactory.get(url);
            Method get = jarFactoryClazz.getMethod("get", URL.class);
            get.setAccessible(true);
            Object jarFile = get.invoke(jarFactory, url);
    
            // jarFactory.close(jarFile);
            Method close = jarFactoryClazz.getMethod("close", JarFile.class);
            close.setAccessible(true);
            //noinspection JavaReflectionInvocation
            close.invoke(jarFactory, jarFile);
    
            // jarFile.close();
            ((JarFile) jarFile).close();
        }
    }
    
    // and in your code:
    
    // i is now closed, so we should be good to delete the jar
    JarBridge.closeJar(j);
    System.out.println(f.delete());     // says true, phew.
    

Nota: Todo esto se basa en Java 8 código base (1.8.0_144); que pueden no funcionar con otras versiones posteriores /.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top