Saya mencoba menghapus file, setelah menulis sesuatu di dalamnya, dengan FileOutputStream
. Ini adalah kode yang saya gunakan untuk menulis:
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();
}
}
Seperti yang terlihat, saya menyiram dan menutup aliran, tetapi ketika saya mencoba untuk menghapus, file.delete()
mengembalikan salah.
Aku diperiksa sebelum penghapusan untuk melihat apakah file ada, dan: file.exists()
, file.canRead()
, file.canWrite()
, file.canExecute()
semua return true. Tepat setelah memanggil metode ini saya mencoba file.delete()
dan mengembalikan false.
Apakah ada kesalahan yang saya lakukan?
java
file
fileoutputstream
Jenny Smith
sumber
sumber
Jawaban:
Bug lain di Jawa. Saya jarang menemukannya, hanya yang kedua dalam 10 tahun karir saya. Ini adalah solusi saya, seperti yang telah disebutkan orang lain. Saya telah menggunakan nether
System.gc()
. Tapi di sini, dalam kasus saya, ini sangat penting. Aneh? IYA!finally { try { in.close(); in = null; out.flush(); out.close(); out = null; System.gc(); } catch (IOException e) { logger.error(e.getMessage()); e.printStackTrace(); } }
sumber
new File(path)
), saya mengalami masalah yang sama dan menambahkanSystem.gc()
sebelumdelete()
membuatnya berfungsi!System.gc
triknya berfungsi setiap saat.System.gc(); result = file.delete(); if (!result){ Thread.sleep(100); System.gc(); result = file.delete(); }
Cukup aneh trik yang berhasil. Masalahnya adalah ketika saya sebelumnya membaca konten file, saya menggunakan
BufferedReader
. Setelah membaca, saya menutup buffer.Sementara itu saya beralih dan sekarang saya membaca konten menggunakan
FileInputStream
. Juga setelah selesai membaca, saya menutup aliran. Dan sekarang berhasil.Masalahnya saya tidak punya penjelasan untuk ini.
Saya tidak tahu
BufferedReader
danFileOutputStream
tidak cocok.sumber
finalize()
untuk memastikan pembersihan? Atau mungkin diaturto = null
? Lihat Memaksa Penyelesaian dan Pengumpulan Sampah .Saya mencoba hal sederhana ini dan sepertinya berhasil.
file.setWritable(true); file.delete();
Ini bekerja untuk saya.
Jika ini tidak berhasil, coba jalankan aplikasi Java Anda dengan sudo if di linux dan sebagai administrator di windows. Hanya untuk memastikan Java memiliki hak untuk mengubah properti file.
sumber
Sebelum mencoba menghapus / mengganti nama file apa pun, Anda harus memastikan bahwa semua pembaca atau penulis (misalnya:
BufferedReader
/InputStreamReader
/BufferedWriter
) ditutup dengan benar.Ketika Anda mencoba membaca / menulis data Anda dari / ke sebuah file, file tersebut ditahan oleh proses dan tidak dilepaskan sampai eksekusi program selesai. Jika Anda ingin melakukan operasi hapus / ganti nama sebelum program berakhir, maka Anda harus menggunakan
close()
metode yang disertakan denganjava.io.*
kelas.sumber
Seperti komentar Jon Skeet, Anda harus menutup file Anda di blok {...}, untuk memastikan bahwa file itu selalu tertutup. Dan, alih-alih menelan pengecualian dengan e.printStackTrace, cukup jangan menangkap dan menambahkan pengecualian ke tanda tangan metode. Jika Anda tidak bisa karena alasan apa pun, setidaknya lakukan ini:
catch(IOException ex) { throw new RuntimeException("Error processing file XYZ", ex); }
Sekarang, pertanyaan nomor 2:
Bagaimana jika Anda melakukan ini:
... to.close(); System.out.println("Please delete the file and press <enter> afterwards!"); System.in.read(); ...
Apakah Anda dapat menghapus file tersebut?
Selain itu, file akan dibilas saat ditutup. Saya menggunakan IOUtils.closeQuietly (...), jadi saya menggunakan metode flush untuk memastikan bahwa konten file ada sebelum saya mencoba menutupnya (IOUtils.closeQuietly tidak memberikan pengecualian). Sesuatu seperti ini:
... try { ... to.flush(); } catch(IOException ex) { throw new CannotProcessFileException("whatever", ex); } finally { IOUtils.closeQuietly(to); }
Jadi saya tahu bahwa isi file tersebut ada di sana. Karena biasanya penting bagi saya bahwa konten file ditulis dan bukan apakah file dapat ditutup atau tidak, tidak masalah apakah file tersebut ditutup atau tidak. Dalam kasus Anda, karena itu penting, saya akan merekomendasikan untuk menutup file sendiri dan memperlakukan setiap pengecualian sesuai.
sumber
Tidak ada alasan Anda tidak dapat menghapus file ini. Saya akan mencari tahu siapa yang memegang file ini. Di unix / linux, Anda dapat menggunakan utilitas lsof untuk memeriksa proses mana yang memiliki kunci pada file. Di windows, Anda dapat menggunakan proses explorer.
untuk lsof, sesederhana mengatakan:
untuk penjelajah proses Anda dapat menggunakan menu temukan dan masukkan nama file untuk menunjukkan kepada Anda pegangan yang akan mengarahkan Anda ke proses penguncian file.
berikut beberapa kode yang menurut saya perlu Anda lakukan:
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(); }
Ini berfungsi dengan baik di OS X. Saya belum mengujinya di windows tetapi saya curiga itu harus berfungsi di Windows juga. Saya juga akan mengakui melihat beberapa perilaku tidak terduga pada penanganan file Windows wrt.
sumber
Jika Anda bekerja di Eclipse IDE, itu bisa berarti Anda belum menutup file di peluncuran aplikasi sebelumnya. Ketika saya mendapatkan pesan kesalahan yang sama saat mencoba menghapus file, itulah alasannya. Tampaknya, Eclipse IDE tidak menutup semua file setelah penghentian aplikasi.
sumber
Semoga ini bisa membantu. Saya menemukan masalah serupa di mana saya tidak dapat menghapus file saya setelah kode java saya membuat salinan konten ke folder lain. Setelah googling ekstensif, saya secara eksplisit mendeklarasikan setiap variabel terkait operasi file dan memanggil metode close () dari setiap objek operasi file, dan mengaturnya ke NULL. Kemudian, ada fungsi yang disebut System.gc (), yang akan membersihkan pemetaan i / o file (saya tidak yakin, saya hanya memberi tahu apa yang diberikan di situs web).
Ini contoh kode saya:
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(); } }
sumber
jawabannya adalah ketika Anda memuat file, Anda perlu menerapkan metode "tutup", di baris kode mana pun, berfungsi untuk saya
sumber
Pernah ada masalah di ruby di mana file di windows membutuhkan "fsync" untuk benar-benar dapat memutar dan membaca kembali file setelah menulis dan menutupnya. Mungkin ini adalah manifestasi serupa (dan jika demikian, saya pikir bug windows, sungguh).
sumber
Tidak ada solusi yang tercantum di sini yang berfungsi dalam situasi saya. Solusi saya adalah menggunakan loop sementara, mencoba menghapus file, dengan batas 5 detik (dapat dikonfigurasi) untuk keamanan.
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--; }
Menggunakan loop di atas bekerja tanpa harus melakukan pengumpulan sampah manual atau mengatur aliran ke null, dll.
sumber
Masalahnya mungkin file tersebut masih dilihat sebagai dibuka dan dikunci oleh program; atau mungkin itu adalah komponen dari program Anda yang telah dibuka, jadi Anda harus memastikan Anda menggunakan
dispose()
metode untuk menyelesaikan masalah itu. yaituJFrame frame; .... frame.dispose();
sumber
Anda harus menutup semua aliran atau menggunakan blok coba-dengan-sumber daya
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; }
sumber
jika file.delete () mengirimkan false maka dalam banyak kasus pegangan Bufferedreader Anda tidak akan ditutup. Cukup dekat dan tampaknya berfungsi untuk saya secara normal.
sumber
Saya memiliki masalah yang sama di Windows. Saya biasa membaca file dalam skala demi baris
Sekarang saya membacanya secara keseluruhan dengan
import org.apache.commons.io.FileUtils._ // encoding is null for platform default val content=readFileToString(new File(path),null.asInstanceOf[String])
yang menutup file dengan benar setelah membaca dan sekarang
new File(path).delete
bekerja.
sumber
Restart IDE Anda dan jalankan kode Anda lagi ini hanya trik bekerja untuk saya setelah perjuangan panjang satu jam.
Ini kode saya:
File file = new File("file-path"); if(file.exists()){ if(file.delete()){ System.out.println("Delete"); } else{ System.out.println("not delete"); } }
Keluaran:
Menghapus
sumber
Kasus sudut lain bahwa hal ini dapat terjadi: jika Anda membaca / menulis file JAR melalui a
URL
dan kemudian mencoba menghapus file yang sama dalam sesi JVM yang sama.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!
Alasannya adalah bahwa logika penanganan file JAR internal Java, cenderung menyimpan
JarFile
entri 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(); } } } }
Dan masing-masing
JarFile
(lebih tepatnya,ZipFile
struktur yang mendasarinya ) akan memegang pegangan ke file, langsung dari saat pembuatan hinggaclose()
dipanggil: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;
Ada penjelasan bagus tentang masalah NetBeans ini .
Ternyata ada dua cara untuk "memperbaiki" ini:
Anda dapat menonaktifkan cache file JAR - untuk saat ini
URLConnection
, atau untuk semua yang akan datangURLConnection
(secara global) di sesi JVM saat ini: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);
[PERINGATAN HACK!] Anda dapat membersihkan
JarFile
cache secara manual setelah selesai. Manajer cachesun.net.www.protocol.jar.JarFileFactory
bersifat pribadi-paket, tetapi beberapa keajaiban refleksi dapat menyelesaikan pekerjaan untuk Anda: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.
Harap diperhatikan: Semua ini didasarkan pada basis kode Java 8 (
1.8.0_144
); mereka mungkin tidak bekerja dengan versi lain / yang lebih baru.sumber