Java File.renameTo()
bermasalah, terutama pada Windows, tampaknya. Seperti yang dikatakan dalam dokumentasi API ,
Banyak aspek perilaku metode ini secara inheren bergantung pada platform: Operasi penggantian nama mungkin tidak dapat memindahkan file dari satu sistem file ke sistem file lainnya, mungkin tidak bersifat atomik, dan mungkin tidak berhasil jika file dengan nama jalur abstrak tujuan sudah ada. Nilai yang dikembalikan harus selalu diperiksa untuk memastikan bahwa operasi penggantian nama berhasil.
Dalam kasus saya, sebagai bagian dari prosedur peningkatan, saya perlu memindahkan (mengganti nama) direktori yang mungkin berisi gigabyte data (banyak subdirektori dan file dengan berbagai ukuran). Pemindahan selalu dilakukan dalam partisi / drive yang sama, jadi tidak perlu memindahkan semua file secara fisik ke disk.
Ada seharusnya tidak menjadi file kunci untuk isi dir yang akan dipindahkan, tapi masih, cukup sering, renameTo () gagal untuk melakukan pekerjaan dan kembali nya palsu. (Saya hanya menebak bahwa mungkin beberapa kunci file kedaluwarsa agak sewenang-wenang di Windows.)
Saat ini saya memiliki metode fallback yang menggunakan penyalinan & penghapusan, tetapi ini menyebalkan karena mungkin membutuhkan banyak waktu, tergantung pada ukuran folder. Saya juga mempertimbangkan untuk mendokumentasikan fakta bahwa pengguna dapat memindahkan folder secara manual untuk menghindari menunggu berjam-jam, berpotensi. Tetapi Jalan yang Benar jelas akan menjadi sesuatu yang otomatis dan cepat.
Jadi pertanyaan saya adalah, apakah Anda tahu alternatif, pendekatan yang andal untuk melakukan perpindahan cepat / mengganti nama dengan Java di Windows , baik dengan JDK biasa atau beberapa perpustakaan eksternal. Atau jika Anda tahu cara mudah untuk mendeteksi dan melepaskan kunci file apa pun untuk folder tertentu dan semua isinya (mungkin ribuan file individual), itu juga bagus.
Sunting : Dalam kasus khusus ini, tampaknya kami lolos hanya renameTo()
dengan mempertimbangkan beberapa hal lagi; lihat jawaban ini .
Jawaban:
Lihat juga
Files.move()
metode di JDK 7.Sebuah contoh:
String fileName = "MyFile.txt"; try { Files.move(new File(fileName).toPath(), new File(fileName).toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); } catch (IOException ex) { Logger.getLogger(SomeClass.class.getName()).log(Level.SEVERE, null, ex); }
sumber
Untuk apa nilainya, beberapa pengertian lebih lanjut:
Pada Windows,
renameTo()
tampaknya gagal jika direktori target ada, meskipun kosong. Ini mengejutkan saya, seperti yang pernah saya coba di Linux, di manarenameTo()
berhasil jika target ada, selama masih kosong.(Jelas saya seharusnya tidak menganggap hal semacam ini berfungsi sama di seluruh platform; inilah yang diperingatkan Javadoc.)
Jika Anda menduga mungkin ada beberapa kunci file yang tertinggal, tunggu sebentar sebelum memindahkan / mengganti nama mungkin membantu. (Dalam satu titik di pemasang / pemutakhiran kami, kami menambahkan tindakan "tidur" dan bilah kemajuan tak tentu selama sekitar 10 detik, karena mungkin ada layanan yang tergantung pada beberapa file). Bahkan mungkin melakukan mekanisme coba lagi sederhana yang mencoba
renameTo()
, dan kemudian menunggu beberapa saat (yang mungkin meningkat secara bertahap), hingga operasi berhasil atau batas waktu tercapai.Dalam kasus saya, sebagian besar masalah tampaknya telah diselesaikan dengan mempertimbangkan kedua hal di atas, jadi kita tidak perlu melakukan panggilan kernel asli, atau semacamnya, setelah semua.
sumber
Posting asli meminta "pendekatan alternatif yang andal untuk melakukan pemindahan / penggantian nama cepat dengan Java di Windows, baik dengan JDK biasa atau beberapa library eksternal."
Opsi lain yang belum disebutkan di sini adalah v1.3.2 atau yang lebih baru dari pustaka apache.commons.io , yang menyertakan FileUtils.moveFile () .
Ini melempar IOException alih-alih menampilkan boolean false saat terjadi kesalahan.
Lihat juga respon lep besar di utas lainnya ini .
sumber
java.nio.file.Path.moveTo()
Dalam kasus saya, ini tampaknya menjadi objek mati dalam aplikasi saya sendiri, yang menyimpan pegangan ke file itu. Jadi solusi itu berhasil untuk saya:
for (int i = 0; i < 20; i++) { if (sourceFile.renameTo(backupFile)) break; System.gc(); Thread.yield(); }
Keuntungan: cukup cepat, karena tidak ada Thread.sleep () dengan waktu hardcode tertentu.
Kerugian: batas 20 itu adalah beberapa angka hardcode. Dalam semua pengujian saya, i = 1 sudah cukup. Tetapi untuk memastikan saya meninggalkannya pada 20.
sumber
Saya tahu ini tampaknya sedikit hacky, tetapi untuk apa saya membutuhkannya, tampaknya pembaca dan penulis buffer tidak memiliki masalah dalam membuat file.
void renameFiles(String oldName, String newName) { String sCurrentLine = ""; try { BufferedReader br = new BufferedReader(new FileReader(oldName)); BufferedWriter bw = new BufferedWriter(new FileWriter(newName)); while ((sCurrentLine = br.readLine()) != null) { bw.write(sCurrentLine); bw.newLine(); } br.close(); bw.close(); File org = new File(oldName); org.delete(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
Berfungsi dengan baik untuk file teks kecil sebagai bagian dari parser, cukup pastikan oldName dan newName adalah jalur lengkap ke lokasi file.
Cheers Kactus
sumber
Potongan kode berikut BUKAN 'alternatif' tetapi telah bekerja dengan andal untuk saya di lingkungan Windows dan Linux:
public static void renameFile(String oldName, String newName) throws IOException { File srcFile = new File(oldName); boolean bSucceeded = false; try { File destFile = new File(newName); if (destFile.exists()) { if (!destFile.delete()) { throw new IOException(oldName + " was not successfully renamed to " + newName); } } if (!srcFile.renameTo(destFile)) { throw new IOException(oldName + " was not successfully renamed to " + newName); } else { bSucceeded = true; } } finally { if (bSucceeded) { srcFile.delete(); } } }
sumber
Pada windows saya menggunakan
Runtime.getRuntime().exec("cmd \\c ")
dan kemudian menggunakan fungsi ganti nama baris perintah untuk benar-benar mengganti nama file. Ini jauh lebih fleksibel, misalnya jika Anda ingin mengganti nama ekstensi dari semua file txt di direktori menjadi bak tulis saja ini ke output stream:ganti nama * .txt * .bak
Saya tahu ini bukan solusi yang baik tetapi tampaknya itu selalu berhasil untuk saya, jauh lebih baik daripada dukungan inline Java.
sumber
Kenapa tidak....
import com.sun.jna.Native; import com.sun.jna.Library; public class RenamerByJna { /* Requires jna.jar to be in your path */ public interface Kernel32 extends Library { public boolean MoveFileA(String existingFileName, String newFileName); } public static void main(String[] args) { String path = "C:/yourchosenpath/"; String existingFileName = path + "test.txt"; String newFileName = path + "renamed.txt"; Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class); kernel32.MoveFileA(existingFileName, newFileName); } }
bekerja pada nwindows 7, tidak melakukan apa-apa jika existingFile tidak ada, tapi jelas bisa diinstrumentasi lebih baik untuk memperbaikinya.
sumber
Saya memiliki masalah serupa. File disalin agak bergerak di Windows tetapi berfungsi dengan baik di Linux. Saya memperbaiki masalah ini dengan menutup fileInputStream yang dibuka sebelum memanggil renameTo (). Diuji pada Windows XP.
fis = new FileInputStream(originalFile); .. .. .. fis.close();// <<<---- Fixed by adding this originalFile.renameTo(newDesitnationForOriginalFile);
sumber
Dalam kasus saya, kesalahan berada di jalur direktori induk. Mungkin bug, saya harus menggunakan substring untuk mendapatkan jalur yang benar.
try { String n = f.getAbsolutePath(); **n = n.substring(0, n.lastIndexOf("\\"));** File dest = new File(**n**, newName); f.renameTo(dest); } catch (Exception ex) { ...
sumber
Saya tahu itu menyebalkan, tetapi alternatifnya adalah membuat skrip kelelawar yang menghasilkan sesuatu yang sederhana seperti "SUKSES" atau "KESALAHAN", panggil, tunggu sampai dieksekusi dan kemudian periksa hasilnya.
Runtime.getRuntime (). Exec ("cmd / c mulai test.bat");
Utas ini mungkin menarik. Periksa juga kelas Proses tentang cara membaca keluaran konsol dari proses yang berbeda.
sumber
Anda dapat mencoba robocopy . Ini tidak persis "mengganti nama", tetapi sangat dapat diandalkan.
sumber
Untuk memindahkan / mengganti nama file Anda dapat menggunakan fungsi ini:
BOOL WINAPI MoveFile( __in LPCTSTR lpExistingFileName, __in LPCTSTR lpNewFileName );
Ini didefinisikan di kernel32.dll.
sumber
File srcFile = new File(origFilename); File destFile = new File(newFilename); srcFile.renameTo(destFile);
Di atas adalah kode sederhana. Saya telah menguji pada windows 7 dan bekerja dengan baik.
sumber