java.io.File的renameTo方法移動文件失敗的解決方案
今天線上發現一個問題,發現一個定時移動文件的業務沒有正常執行,結合日志和代碼發現,移動文件是使用File類的renameTo方法,但是方法返回的都是false,表示文件移動失敗。
出現這個問題我第一反應是不是文件權限的問題,但是和運維研究後發現的確不是權限導致的。既然不是權限的問題,那就看看renameTo的實現吧,查看源碼發現該方法最終是通過一個本地方法實現的,看不到咋寫的。
網上查瞭一下renameTo這個方法,發現這個方法確實存在一些問題,就是在不同的文件系統中移動是不會成功的。因為測試環境並未出現這個問題,我就把生產環境和測試環境對比瞭下,發現測試環境下,文件本身的目錄和要移動到的目錄是在/home下,而生產環境中,文件本身目錄是在/home下,要移動到的目錄都是在/data下。於是用df命令查看瞭一下,發現 /home的文件系統是/dev/sda3,類型是xfs的,/data的文件系統是/dev/sdb1,類型是ext4。
既然是這樣那就寫個demo在自己的虛擬機上驗證一下是不是這個原因導致的。
1.首先找兩個文件系統不一樣的目錄,命令df -T
我們用/tmp 和 /run 作為測試目錄。
2.測試代碼
import java.io.File; /** * 文件移動方法測試 */ public class FileTest { public static void main(String[] args) { String filePath="/tmp/test.txt"; File file = new File(filePath); boolean b = file.renameTo(new File("/run/test.txt")); System.out.println(b); } }
3.編譯運行
javac FileTest.java java FileTest
運行結果輸出false,文件也確實未移動成功
解決方法:
使用apache的commons-io包中的工具類的進行文件移動。
1.測試代碼:
import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; /** * 文件移動方法測試 */ public class FileTest { public static void main(String[] args) { String filePath="/tmp/test.txt"; File file = new File(filePath); boolean b = file.renameTo(new File("/run/test.txt")); System.out.println(b); //使用apache的FileUtils工具 try { FileUtils.moveFile(file,new File("/run/test.txt")); System.out.println("success"); } catch (IOException e) { e.printStackTrace(); } } }
2.編譯運行
javac -cp /root/jar/commons-io-2.4.jar FileTest.java java -cp /root/jar/commons-io-2.4.jar: FileTest
運行結果成功移動文件
3.apache的FileUtils移動文件方法的主要實現如下:
//先使用renameTo方法進行移動 boolean rename = srcFile.renameTo(destFile); if (!rename) { //renameTo移動失敗,就復制文件,然後刪除原文件 copyFile( srcFile, destFile ); if (!srcFile.delete()) { FileUtils.deleteQuietly(destFile); throw new IOException("Failed to delete original file '" + srcFile + "' after copy to '" + destFile + "'"); } }
總結:
1、文件移動最好不要使用Java的renameTo方法,而是應該使用apache的commons-io包,當然也可以自己封裝類似的方法。
2、renameTo方法移動失敗是文件系統不同造成的,補充測試發現不同的文件系統,就算類型相同,移動也會失敗。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Java文件操作之IO流 File類的使用詳解
- Java的IO流實現文件和文件夾的復制
- java 移動文件,並修改名稱方式
- Java深入淺出說流的使用
- java面試try-with-resources問題解答