java.io.File的renameTo方法移動(dòng)文件失敗的解決方案
今天線(xiàn)上發(fā)現(xiàn)一個(gè)問(wèn)題,發(fā)現(xiàn)一個(gè)定時(shí)移動(dòng)文件的業(yè)務(wù)沒(méi)有正常執(zhí)行,結(jié)合日志和代碼發(fā)現(xiàn),移動(dòng)文件是使用File類(lèi)的renameTo方法,但是方法返回的都是false,表示文件移動(dòng)失敗。
出現(xiàn)這個(gè)問(wèn)題我第一反應(yīng)是不是文件權(quán)限的問(wèn)題,但是和運(yùn)維研究后發(fā)現(xiàn)的確不是權(quán)限導(dǎo)致的。既然不是權(quán)限的問(wèn)題,那就看看renameTo的實(shí)現(xiàn)吧,查看源碼發(fā)現(xiàn)該方法最終是通過(guò)一個(gè)本地方法實(shí)現(xiàn)的,看不到咋寫(xiě)的。
網(wǎng)上查了一下renameTo這個(gè)方法,發(fā)現(xiàn)這個(gè)方法確實(shí)存在一些問(wèn)題,就是在不同的文件系統(tǒng)中移動(dòng)是不會(huì)成功的。因?yàn)闇y(cè)試環(huán)境并未出現(xiàn)這個(gè)問(wèn)題,我就把生產(chǎn)環(huán)境和測(cè)試環(huán)境對(duì)比了下,發(fā)現(xiàn)測(cè)試環(huán)境下,文件本身的目錄和要移動(dòng)到的目錄是在/home下,而生產(chǎn)環(huán)境中,文件本身目錄是在/home下,要移動(dòng)到的目錄都是在/data下。于是用df命令查看了一下,發(fā)現(xiàn) /home的文件系統(tǒng)是/dev/sda3,類(lèi)型是xfs的,/data的文件系統(tǒng)是/dev/sdb1,類(lèi)型是ext4。
既然是這樣那就寫(xiě)個(gè)demo在自己的虛擬機(jī)上驗(yàn)證一下是不是這個(gè)原因?qū)е碌摹?/p>
1.首先找兩個(gè)文件系統(tǒng)不一樣的目錄,命令df -T
我們用/tmp 和 /run 作為測(cè)試目錄。
2.測(cè)試代碼
import java.io.File; /** * 文件移動(dòng)方法測(cè)試 */ 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.編譯運(yùn)行
javac FileTest.java java FileTest
運(yùn)行結(jié)果輸出false,文件也確實(shí)未移動(dòng)成功
解決方法:
使用apache的commons-io包中的工具類(lèi)的進(jìn)行文件移動(dòng)。
1.測(cè)試代碼:
import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; /** * 文件移動(dòng)方法測(cè)試 */ 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.編譯運(yùn)行
javac -cp /root/jar/commons-io-2.4.jar FileTest.java java -cp /root/jar/commons-io-2.4.jar: FileTest
運(yùn)行結(jié)果成功移動(dòng)文件
3.apache的FileUtils移動(dòng)文件方法的主要實(shí)現(xiàn)如下:
//先使用renameTo方法進(jìn)行移動(dòng) boolean rename = srcFile.renameTo(destFile); if (!rename) { //renameTo移動(dòng)失敗,就復(fù)制文件,然后刪除原文件 copyFile( srcFile, destFile ); if (!srcFile.delete()) { FileUtils.deleteQuietly(destFile); throw new IOException("Failed to delete original file '" + srcFile + "' after copy to '" + destFile + "'"); } }
總結(jié):
1、文件移動(dòng)最好不要使用Java的renameTo方法,而是應(yīng)該使用apache的commons-io包,當(dāng)然也可以自己封裝類(lèi)似的方法。
2、renameTo方法移動(dòng)失敗是文件系統(tǒng)不同造成的,補(bǔ)充測(cè)試發(fā)現(xiàn)不同的文件系統(tǒng),就算類(lèi)型相同,移動(dòng)也會(huì)失敗。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot實(shí)現(xiàn)API接口的完整代碼
這篇文章主要給大家介紹了關(guān)于SpringBoot實(shí)現(xiàn)API接口的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10詳解Java MyBatis 插入數(shù)據(jù)庫(kù)返回主鍵
這篇文章主要介紹了詳解Java MyBatis 插入數(shù)據(jù)庫(kù)返回主鍵,有興趣的可以了解一下。2017-01-01Java結(jié)束線(xiàn)程的三種方法及該如何選擇
這篇文章主要介紹了Java結(jié)束線(xiàn)程的三種方法及該如何選擇,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下2021-03-03springboot2 生產(chǎn)部署注意事項(xiàng)及示例代碼
這篇文章主要介紹了springboot2 生產(chǎn)部署注意事項(xiàng)及示例代碼,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04關(guān)于SpringGateway調(diào)用服務(wù) 接受不到參數(shù)問(wèn)題
這篇文章主要介紹了關(guān)于SpringGateway調(diào)用服務(wù)接受不到參數(shù)問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12java.lang.IllegalStateException:方法有太多主體參數(shù)問(wèn)題
這篇文章主要介紹了java.lang.IllegalStateException:方法有太多主體參數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07java?CompletableFuture異步任務(wù)編排示例詳解
這篇文章主要為大家介紹了java?CompletableFuture異步任務(wù)編排示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11