Próbuję usunąć plik po zapisaniu w nim czegoś za pomocą FileOutputStream
. Oto kod, którego używam do pisania:
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();
}
}
Jak widać, opróżniam i zamykam strumień, ale kiedy próbuję usunąć, file.delete()
zwraca fałsz.
Sprawdziłem przed usunięciem, aby sprawdzić, czy plik istnieje i: file.exists()
, file.canRead()
, file.canWrite()
, file.canExecute()
wszystko return true. Zaraz po wywołaniu tych metod próbuję file.delete()
zwrócić wartość false.
Czy jest coś, co zrobiłem źle?
java
file
fileoutputstream
Jenny Smith
źródło
źródło
Odpowiedzi:
Kolejny błąd w Javie. Rzadko je znajduję, tylko drugi w mojej 10-letniej karierze. To jest moje rozwiązanie, jak wspominali inni. Użyłem nether
System.gc()
. Ale tutaj, w moim przypadku, jest to absolutnie kluczowe. Dziwne? TAK!finally { try { in.close(); in = null; out.flush(); out.close(); out = null; System.gc(); } catch (IOException e) { logger.error(e.getMessage()); e.printStackTrace(); } }
źródło
new File(path)
), napotkałem ten sam problem i dodałem,System.gc()
zanimdelete()
zadziałało!System.gc
sztuczka działa za każdym razem.System.gc(); result = file.delete(); if (!result){ Thread.sleep(100); System.gc(); result = file.delete(); }
To była dość dziwna sztuczka, która zadziałała. Chodzi o to, że kiedy wcześniej przeczytałem zawartość pliku, użyłem
BufferedReader
. Po przeczytaniu zamknąłem bufor.W międzyczasie przełączyłem się i teraz czytam treść za pomocą
FileInputStream
. Również po skończeniu czytania zamykam strumień. A teraz to działa.Problem w tym, że nie mam na to wytłumaczenia.
Nie wiem
BufferedReader
iFileOutputStream
być niekompatybilnym.źródło
finalize()
żeby posprzątać? A może zestawto = null
? Zobacz Wymuszanie finalizacji i wyrzucanie elementów bezużytecznych .Wypróbowałem tę prostą rzecz i wydaje się, że działa.
file.setWritable(true); file.delete();
Mi to pasuje.
Jeśli to nie zadziała, spróbuj uruchomić aplikację Java z sudo w systemie Linux i jako administrator w systemie Windows. Aby upewnić się, że Java ma uprawnienia do zmiany właściwości pliku.
źródło
Przed próbą usunięcia / zmiany nazwy dowolnego pliku należy upewnić się, że wszystkie czytniki lub osoby piszące (na przykład:
BufferedReader
/InputStreamReader
/BufferedWriter
) są prawidłowo zamknięte.Kiedy próbujesz odczytać / zapisać dane z / do pliku, plik jest zatrzymywany przez proces i nie jest zwalniany do czasu zakończenia wykonywania programu. Jeśli chcesz wykonać operacje usuwania / zmiany nazwy przed zakończeniem programu, musisz użyć
close()
metody dołączonej dojava.io.*
klas.źródło
Jak skomentował Jon Skeet, powinieneś zamknąć swój plik w ostatnim bloku {...}, aby mieć pewność, że jest zawsze zamknięty. I zamiast połykać wyjątki za pomocą e.printStackTrace, po prostu nie przechwytuj i nie dodawaj wyjątku do sygnatury metody. Jeśli z jakiegoś powodu nie możesz, przynajmniej zrób to:
catch(IOException ex) { throw new RuntimeException("Error processing file XYZ", ex); }
Teraz pytanie numer 2:
Co jeśli zrobisz to:
... to.close(); System.out.println("Please delete the file and press <enter> afterwards!"); System.in.read(); ...
Czy byłbyś w stanie usunąć plik?
Ponadto pliki są opróżniane po zamknięciu. Używam IOUtils.closeQuietly (...), więc używam metody flush, aby upewnić się, że zawartość pliku jest tam, zanim spróbuję go zamknąć (IOUtils.closeQuietly nie zgłasza wyjątków). Coś takiego:
... try { ... to.flush(); } catch(IOException ex) { throw new CannotProcessFileException("whatever", ex); } finally { IOUtils.closeQuietly(to); }
Wiem więc, że jest tam zawartość pliku. Ponieważ zwykle ma dla mnie znaczenie, że zawartość pliku jest zapisana, a nie, czy plik można zamknąć, czy nie, tak naprawdę nie ma znaczenia, czy plik został zamknięty, czy nie. W Twoim przypadku, ponieważ ma to znaczenie, polecam samodzielne zamknięcie pliku i odpowiednie traktowanie wyjątków.
źródło
Nie ma powodu, dla którego nie powinieneś być w stanie usunąć tego pliku. Chciałbym sprawdzić, kto ma kontrolę nad tym plikiem. W systemach unix / linux możesz użyć narzędzia lsof, aby sprawdzić, który proces ma blokadę pliku. W systemie Windows możesz użyć eksploratora procesów.
w przypadku lsof wystarczy powiedzieć:
w eksploratorze procesów możesz użyć menu wyszukiwania i wprowadzić nazwę pliku, aby pokazać uchwyt, który wskaże proces blokujący plik.
tutaj jest kod, który robi to, co myślę, że musisz zrobić:
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(); }
Działa dobrze na OS X. Nie testowałem tego w systemie Windows, ale podejrzewam, że powinien działać również w systemie Windows. Przyznam się również, że zauważyłem nieoczekiwane zachowanie podczas obsługi plików wrt w systemie Windows.
źródło
Jeśli pracujesz w Eclipse IDE, może to oznaczać, że nie zamknąłeś pliku podczas poprzedniego uruchomienia aplikacji. Kiedy miałem ten sam komunikat o błędzie podczas próby usunięcia pliku, to był powód. Wygląda na to, że Eclipse IDE nie zamyka wszystkich plików po zakończeniu działania aplikacji.
źródło
Mam nadzieję, że to pomoże. Natknąłem się na podobny problem, w którym nie mogłem usunąć mojego pliku po tym, jak mój kod java skopiował zawartość do innego folderu. Po obszernym wyszukiwaniu w Google jawnie zadeklarowałem wszystkie zmienne związane z operacjami na plikach i wywołałem metodę close () każdego obiektu operacji na plikach i ustawiłem je na NULL. Następnie jest funkcja o nazwie System.gc (), która wyczyści mapowanie we / wy pliku (nie jestem pewien, po prostu podam, co jest podane na stronach internetowych).
Oto mój przykładowy kod:
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(); } }
źródło
odpowiedź brzmi: kiedy ładujesz plik, musisz zastosować metodę „close”, w każdym wierszu kodu, dla mnie działa
źródło
Raz w Ruby pojawił się problem polegający na tym, że pliki w systemie Windows wymagały „fsync”, aby faktycznie móc odwrócić się i ponownie odczytać plik po zapisaniu go i zamknięciu. Może to jest podobna manifestacja (a jeśli tak, myślę, że naprawdę jest to błąd systemu Windows).
źródło
Żadne z wymienionych tutaj rozwiązań nie zadziałało w mojej sytuacji. Moim rozwiązaniem było użycie pętli while, próbując usunąć plik, z 5-sekundowym (konfigurowalnym) limitem bezpieczeństwa.
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--; }
Korzystanie z powyższej pętli działało bez konieczności ręcznego zbierania śmieci lub ustawiania strumienia na zero itp.
źródło
Problem może polegać na tym, że plik jest nadal postrzegany jako otwarty i zablokowany przez program; a może jest to komponent twojego programu, w którym został otwarty, więc musisz upewnić się, że używasz
dispose()
metody do rozwiązania tego problemu. to znaczyJFrame frame; .... frame.dispose();
źródło
Musisz zamknąć wszystkie strumienie lub użyć bloku try-with-resource
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; }
źródło
jeśli file.delete () wysyła false, to w większości przypadków uchwyt Bufferedreader nie zostanie zamknięty. Po prostu blisko i wydaje mi się, że działa normalnie.
źródło
Miałem ten sam problem w systemie Windows. Kiedyś czytałem plik w scali wiersz po wierszu z
Teraz czytam to w całości za pomocą
import org.apache.commons.io.FileUtils._ // encoding is null for platform default val content=readFileToString(new File(path),null.asInstanceOf[String])
który zamyka plik poprawnie po przeczytaniu i teraz
new File(path).delete
Pracuje.
źródło
Zrestartuj IDE i uruchom kod jeszcze raz, to dla mnie tylko sztuczka po godzinnej walce.
Oto mój kod:
File file = new File("file-path"); if(file.exists()){ if(file.delete()){ System.out.println("Delete"); } else{ System.out.println("not delete"); } }
Wynik:
Usunąć
źródło
Kolejny przypadek, w którym może się to zdarzyć: jeśli odczytujesz / zapisujesz plik JAR za pomocą a,
URL
a później spróbujesz usunąć ten sam plik w tej samej sesji 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!
Powodem jest to, że wewnętrzna logika obsługi plików JAR w Javie ma tendencję do buforowania
JarFile
wpisów:// 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(); } } } }
I każda
JarFile
(a raczej podstawowaZipFile
struktura) trzymałaby uchwyt do pliku, od momentu konstrukcji aż doclose()
wywołania: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;
Istnieje dobre wyjaśnienie tego problemu z NetBeans .
Najwyraźniej istnieją dwa sposoby, aby to „naprawić”:
Możesz wyłączyć buforowanie plików JAR - dla bieżącej
URLConnection
lub dla wszystkich przyszłychURLConnection
s (globalnie) w bieżącej sesji 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);
[OSTRZEŻENIE HACK!] Możesz ręcznie wyczyścić
JarFile
pamięć podręczną, gdy skończysz z tym. Menedżer pamięci podręcznejsun.net.www.protocol.jar.JarFileFactory
jest prywatnym pakietem, ale pewna magia refleksji może wykonać zadanie za Ciebie: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.
Uwaga: wszystko to jest oparte na bazie kodu Java 8 (
1.8.0_144
); mogą nie działać z innymi / późniejszymi wersjami.źródło