File.Delete () restituisce false, anche se File.Exists (), file.canRead (), file.canWrite (), file.canExecute () tutto restituiscono true
-
13-09-2019 - |
Domanda
Sto cercando di eliminare un file, dopo aver scritto qualcosa in esso, con FileOutputStream
. Questo è il codice che uso per la scrittura:
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();
}
}
Come si vede, Arrossisco e chiudere il flusso, ma quando provo a cancellare, file.delete()
restituisce false.
Ho controllato prima della cancellazione, per vedere se il file esiste, e: file.exists()
, file.canRead()
, file.canWrite()
, file.canExecute()
restituiscono tutte vere. Subito dopo si chiamano questi metodi provo file.delete()
e restituisce falso.
C'è qualcosa che ho fatto di sbagliato?
Soluzione 2
E 'stato abbastanza strano il trucco che ha funzionato. Il fatto è che quando ho già letto il contenuto del file, ho usato BufferedReader
. Dopo la lettura, ho chiuso il buffer.
Nel frattempo ho cambiato e adesso sto leggendo il contenuto utilizzando FileInputStream
. Anche dopo aver terminato la lettura chiudo il flusso. E ora si sta lavorando.
Il problema è che non ho la spiegazione per questo.
Non so BufferedReader
e FileOutputStream
incompatibili.
Altri suggerimenti
Un altro bug in Java. Raramente li trovo, solo il mio secondo nella mia carriera di 10 anni. Questa è la mia soluzione, come altri hanno detto. Ho usato inferi System.gc()
. Ma qui, nel mio caso, è assolutamente cruciale. Strano? SÌ!
finally
{
try
{
in.close();
in = null;
out.flush();
out.close();
out = null;
System.gc();
}
catch (IOException e)
{
logger.error(e.getMessage());
e.printStackTrace();
}
}
Ho provato questa cosa semplice e sembra funzionare.
file.setWritable(true);
file.delete();
Funziona per me.
Se questo non funziona tenta di eseguire l'applicazione Java con sudo se su Linux e come amministratore quando sulle finestre. Giusto per assicurarsi che Java ha il diritto di modificare le proprietà del file.
Prima di provare a cancellare / rinominare qualsiasi tipo di file, è necessario assicurarsi che tutti i lettori o scrittori (per es: BufferedReader
/ InputStreamReader
/ BufferedWriter
). Siano ben chiusi
Quando si tenta di leggere / scrivere i dati da / a un file, il file viene tenuto dal processo e non rilasciato fino a quando l'esecuzione del programma viene completata. Se si desidera eseguire la cancellazione / rinomina operazioni prima che il programma termina, quindi è necessario utilizzare il metodo close()
che viene fornito con le classi java.io.*
.
Come ha commentato Jon Skeet, si dovrebbe chiudere il file nel blocco finally {...}, al fine di garantire che è sempre chiuso. E, invece di deglutire le eccezioni con l'e.printStackTrace, semplicemente non catturare e aggiungere l'eccezione per la firma del metodo. Se non è possibile, per qualsiasi motivo, almeno fare questo:
catch(IOException ex) {
throw new RuntimeException("Error processing file XYZ", ex);
}
Ora, domanda numero # 2:
Che cosa succede se si esegue questa operazione:
...
to.close();
System.out.println("Please delete the file and press <enter> afterwards!");
System.in.read();
...
Vuoi essere in grado di eliminare il file?
Inoltre, i file vengono scaricati quando sono chiusi. Io uso IOUtils.closeQuietly (...), per cui uso il metodo flush al fine di garantire che il contenuto del file ci sono prima di provare per chiuderla (IOUtils.closeQuietly non genera eccezioni). Qualcosa di simile a questo:
...
try {
...
to.flush();
} catch(IOException ex) {
throw new CannotProcessFileException("whatever", ex);
} finally {
IOUtils.closeQuietly(to);
}
Quindi so che il contenuto del file sono lì. Come è solito importante per me che il contenuto del file sono scritte e non se il file potrebbe essere chiusa o no, in realtà non importa se il file è stato chiuso o meno. Nel tuo caso, come è importante, mi sento di raccomandare la chiusura del file di se stessi e il trattamento di eventuali eccezioni secondo.
Non v'è alcuna ragione per cui non si dovrebbe essere in grado di eliminare questo file. Vorrei guardare per vedere chi ha una presa su questo file. In Unix / Linux, è possibile utilizzare l'utility lsof per controllare quale processo ha un blocco sul file. In Windows, è possibile utilizzare Process Explorer.
per lsof, è semplice come dire:
lsof /path/and/name/of/the/file
per Process Explorer è possibile utilizzare il menu Trova e immettere il nome del file per mostrarvi la maniglia che si punta al processo di blocco del file.
Un po 'di codice che fa quello che penso che devi fare:
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();
}
Funziona bene su OS X. Non ho ancora testato su Windows ma ho il sospetto che dovrebbe funzionare anche su Windows. Io ammettere anche vedendo alcuni comportamenti imprevisti in Windows w.r.t. la gestione dei file.
Se si sta lavorando in Eclipse IDE, che potrebbe significare che non hai chiudere il file nel lancio precedente dell'applicazione. Quando ho avuto lo stesso messaggio di errore a cercare di eliminare un file, che era la ragione. Sembra, Eclipse non chiude tutti i file dopo la cessazione di un'applicazione.
Speriamo che questo vi aiuterà. Mi sono imbattuto in un problema simile in cui non ho potuto cancellare il mio file dopo il mio codice Java ha fatto una copia del contenuto in un'altra cartella. Dopo ampia googling, ho dichiarato in modo esplicito ogni singolo variabili relativa operazione di file e chiamato il metodo close () di ciascun oggetto un'operazione di file, e impostarle su null. Poi, c'è una funzione chiamata System.gc (), che sarà chiarire il file I / O mapping (non sono sicuro, ho solo detto ciò che è dato sui siti web).
Ecco il mio codice di esempio:
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 risposta è quando si carica il file, è necessario applicare il metodo "close", in ogni riga di codice, lavora per me
C'è stato un problema, una volta in Ruby in cui i file in Windows bisogno di un "fsync" per essere effettivamente in grado di girarsi e ri-leggere il file dopo averlo scritto e chiusura. Forse questa è una manifestazione simile (e se sì, penso che un bug di Windows, in realtà).
Nessuna delle soluzioni elencate qui lavorato nella mia situazione. La mia soluzione era quella di utilizzare un ciclo while, il tentativo di eliminare il file, con un 5 secondo limite (configurabile) per la sicurezza.
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--;
}
Uso ciclo precedente lavorato senza dover fare qualsiasi raccolta rifiuti manuale o modificando il flusso a zero, ecc.
Il problema potrebbe essere che il file è ancora visto come aperto e bloccato da un programma; o forse si tratta di un componente dal vostro programma che era stato aperto in, in modo da avere per assicurarsi di utilizzare il metodo dispose()
per risolvere il problema.
cioè JFrame frame;
....
frame.dispose();
È necessario chiudere tutti i corsi d'acqua o utilizzare try-with-risorsa blocco
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 () sta inviando falso quindi nella maggior parte dei casi il vostro maniglia BufferedReader non verrà chiuso. Proprio vicino e sembra funzionare per me normalmente.
Ho avuto lo stesso problema su Windows. Ho usato per leggere il file in linea scala per riga con
Source.fromFile(path).getLines()
Ora ho letto nel suo complesso con
import org.apache.commons.io.FileUtils._
// encoding is null for platform default
val content=readFileToString(new File(path),null.asInstanceOf[String])
che chiude il file in modo corretto dopo aver letto e ora
new File(path).delete
opere.
Per Eclipse / NetBeans
Riavviare l'IDE ed eseguire il codice ancora una volta questo è solo il lavoro trucco per me, dopo lunga lotta un'ora.
Qui è il mio codice:
File file = new File("file-path");
if(file.exists()){
if(file.delete()){
System.out.println("Delete");
}
else{
System.out.println("not delete");
}
}
Output:
Elimina
Un altro caso d'angolo che questo potrebbe accadere:. Se si legge / scrive un file JAR attraverso un URL
e poi cercare di eliminare lo stesso file all'interno della stessa sessione 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!
Il motivo è che la logica di gestione di Java file JAR interno, tende a memorizzare nella cache le voci 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();
}
}
}
}
E ogni JarFile
(piuttosto, la struttura ZipFile
sottostante) terrebbe una maniglia per il file, fin dal momento della costruzione fino a quando viene richiamato 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;
C'è una buona spiegazione su questo NetBeans problema .
A quanto pare ci sono due modi per "sistemare" in questo modo:
-
È possibile disattivare il file JAR caching - per il
URLConnection
corrente, o per tuttiURLConnection
s futuri (a livello mondiale) nella sessione corrente JVM: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);
-
[HACK ATTENZIONE!] È possibile eliminare manualmente il
JarFile
dalla cache quando si è fatto con esso. La cache direttoresun.net.www.protocol.jar.JarFileFactory
è il pacchetto-privato, ma una certa magia riflessione può ottenere il lavoro fatto per voi: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: Tutto questo si basa su Java 8 codebase (1.8.0_144
); essi potrebbero non funzionare con altre versioni / successive.