file.delete () retorna false mesmo que File.Exists (), file.canRead (), file.canWrite (), file.canExecute () todos return true

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

  •  13-09-2019
  •  | 
  •  

Pergunta

Eu estou tentando excluir um arquivo, depois de escrever algo nele, com FileOutputStream. Este é o uso I código para escrever:

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 vê, eu flush e fechar o fluxo, mas quando eu tento apagar, file.delete() retorna falso.

Eu verifiquei antes da eliminação para ver se existe o arquivo e: file.exists(), file.canRead(), file.canWrite(), file.canExecute() todo o retorno verdadeiro. Só depois de chamar esses métodos tento file.delete() e retorna falso.

Existe algo que eu fiz de errado?

Foi útil?

Solução 2

Foi muito estranho o truque que funcionou. A coisa é quando eu li previamente o conteúdo do arquivo, eu usei BufferedReader. Após a leitura, eu fechei o buffer.

Enquanto isso eu mudei e agora estou lendo o conteúdo usando FileInputStream. Também depois de terminar a leitura eu fechar o fluxo. E agora ele está trabalhando.

O problema é que eu não tenho explicação para isso.

Eu não sei BufferedReader e FileOutputStream incompatível.

Outras dicas

Outro bug em Java. Eu raramente encontrá-los, apenas o segundo na minha carreira de 10 anos. Esta é a minha solução, como os outros. Eu tenho System.gc() usada inferior. Mas aqui, no meu caso, é absolutamente crucial. Esquisito? YES!

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

Eu tentei esta coisa simples e parece estar funcionando.

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

Ele funciona para mim.

Se isto não funcionar, tente executar o aplicativo Java com sudo se no Linux e como administrador quando nas janelas. Só para ter certeza Java tem direitos para alterar as propriedades do arquivo.

Antes de tentar apagar / renomear qualquer arquivo, você deve garantir que todos os leitores ou escritores (por ex: BufferedReader / InputStreamReader / BufferedWriter). Estão bem fechados

Quando você tenta ler / escrever os seus dados de / para um arquivo, o arquivo é realizada pelo processo e não liberado até que as completa a execução do programa. Se você quiser executar as operações de exclusão / renomear antes de terminar o programa, então você deve usar o método close() que vem com as classes java.io.*.

Como Jon Skeet comentou, você deve fechar o arquivo no finally {...} bloco, para garantir que ele está sempre fechada. E, em vez de engolir as exceções com o e.printStackTrace, simplesmente não pegar e adicionar a exceção para a assinatura do método. Se você não pode, por qualquer motivo, pelo menos, fazer isso:

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

Agora, a pergunta número # 2:

E se você fizer isso:

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

Você seria capaz de excluir o arquivo?

Além disso, os arquivos são descartados quando eles estão fechados. Eu uso IOUtils.closeQuietly (...), então eu uso o método flush para garantir que o conteúdo do arquivo estão lá antes de eu tentar fechá-lo (não IOUtils.closeQuietly não lançar exceções). Algo parecido com isto:

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

Assim que eu sei que o conteúdo do arquivo estão lá. Como normalmente importa para mim que o conteúdo do arquivo é escrito e não se o arquivo pode ser fechado ou não, isso realmente não importa se o arquivo foi fechada ou não. No seu caso, como é importante, eu recomendaria fechando o arquivo de si mesmo e tratar todas as exceções de acordo.

Não há nenhuma razão que você não deve ser capaz de excluir este arquivo. Gostaria de olhar para ver quem tem um poder sobre esse arquivo. Em unix / linux, você pode usar o utilitário lsof para verificar qual processo tem um bloqueio no arquivo. No Windows, você pode usar o Process Explorer.

para lsof, é tão simples como dizer:

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

para o Process Explorer, você pode usar o Menu Find e digite o nome do arquivo para mostrar-lhe o punho que você irá apontar para o processo bloqueando o arquivo.

Aqui está um código que faz o que eu acho que você precisa fazer:

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();
}

Ele funciona muito bem no OS X. Eu não testei-o em janelas, mas eu suspeito que ele deve funcionar no Windows também. Eu também vou admitir vendo algum comportamento inesperado no Windows w.r.t. manipulação de arquivos.

Se você estiver trabalhando em Eclipse IDE, que pode significar que você não tem perto o arquivo no lançamento anterior do aplicativo. Quando eu tive a mesma mensagem de erro ao tentar excluir um arquivo, que foi o motivo. Parece, Eclipse IDE não feche todos os arquivos após o término de um aplicativo.

Esperemos que isto irá ajudar. Me deparei com problema semelhante onde eu não poderia excluir meu arquivo após meu código java fez uma cópia do conteúdo para a outra pasta. Após uma extensa googling, eu declarou explicitamente cada operação de arquivo único variáveis ??relacionadas e chamou o método close () de cada objeto operação de arquivo, e configurá-los para NULL. Então, há uma função chamada System.gc (), que vai limpar o arquivo i / o mapeamento (não tenho certeza, eu só dizer o que é dado na web sites).

Aqui está o meu código de exemplo:

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();
    }
}

a resposta é quando você carrega o arquivo, você precisa aplicar o método "close", em qualquer linha de código, trabalha para me

Houve um problema de vez em ruby ??onde os arquivos em janelas precisava de um "fsync" para ser realmente capaz de se virar e re-ler o arquivo depois de escrevê-lo e fechá-lo. Talvez esta seja uma manifestação semelhante (e se assim for, acho que um bug do Windows, na verdade).

Nenhuma das soluções listadas aqui trabalhou na minha situação. Minha solução foi usar um loop while, a tentativa de excluir o arquivo, com um 5 segundo limite (configurável) para a segurança.

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--;
}

Usando o ciclo acima funcionou sem ter que fazer qualquer recolha de lixo manual ou ajuste da corrente para nula, etc.

O problema pode ser que o arquivo ainda é visto como aberto e bloqueado por um programa; ou talvez seja um componente de seu programa que tinha sido aberto no, então você tem que garantir que você use o método dispose() para resolver esse problema. ou seja JFrame frame; .... frame.dispose();

Você tem que fechar todas do bloco córregos ou uso try-with-recurso

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;
}

Se file.delete () está enviando falsa, então na maioria dos casos, o seu punho BufferedReader não será fechado. Apenas perto e parece trabalhar para mim normalmente.

Eu tive o mesmo problema no Windows. Eu costumava ler o arquivo em linha scala por linha com

Source.fromFile(path).getLines()

Agora eu lê-lo como um todo, com

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

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

que fecha o arquivo corretamente depois de ler e agora

new File(path).delete

obras.

Para Eclipse / NetBeans

Reinicie o IDE e executar o código novamente este é apenas enganar trabalho para mim depois de uma hora longa luta.

Aqui está o meu código:

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

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

Output:

Excluir

Outro caso de canto que isso poderia acontecer:. Se você ler / escrever um arquivo JAR através de um URL e mais tarde tentar excluir o mesmo arquivo dentro da mesma sessão 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!

A razão é que o arquivo JAR interna lógica de manipulação de Java, tende a entradas JarFile de cache:

// 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();
            }
        }
    }
}

E cada JarFile (sim, a estrutura ZipFile subjacente) iria realizar um identificador para o arquivo, desde o momento da construção até close() é invocado:

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;

Há uma boa explicação sobre esta questão NetBeans .


Aparentemente, há duas maneiras de "consertar" o seguinte:

  • Você pode desativar o cache de arquivo JAR - para o URLConnection atual, ou para todos os URLConnections futuros (globalmente) na sessão JVM atual:

    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 ATENÇÃO!] Você pode limpar manualmente o JarFile do cache quando você é feito com ele. O sun.net.www.protocol.jar.JarFileFactory gerenciador de cache é um pacote-privadas, mas um pouco de magia reflexão pode fazer o trabalho para você:

    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.
    

Por favor nota: Tudo isso é baseado em Java 8 base de código (1.8.0_144); Eles não podem trabalhar com outras versões / posteriores.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top