您好,登錄后才能下訂單哦!
這篇文章主要介紹“項目打包成jar后包無法讀取src/main/resources下文件怎么解決”,在日常操作中,相信很多人在項目打包成jar后包無法讀取src/main/resources下文件怎么解決問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”項目打包成jar后包無法讀取src/main/resources下文件怎么解決”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
在項目中讀取文件時, 使用new File() 出現的一個坑以及解決流程
這種問題不僅在本地文件讀取時會遇到, 而且在下載項目下 (例如: src/main/resources目錄下
) 的文本時, 也會遇到,
原來代碼
該代碼功能是利用 common.io 包下的FileUtils來讀取文件, 放到一個字符串中
String s = FileUtils.readFileToString(new File("src/main/resources/holiday.txt"), "utf-8");
這種路徑書寫方式 new File("src/main/resources/holiday.txt")
, 在本地運行沒問題,
但是打包之后在服務器中運行出現了問題. 下面是錯誤截圖
可以看到在服務器中日志提示: java.io.FileNotFoundException: File 'holiday.txt' does not exist
即: 在打包后, 一開始配置的路徑src/main/resources
下無法找到該文件
項目在打包之后, 位于 resource目錄下的文件, 最常見的就是各種Spring配置文件就會打包在 BOOT-INF/classes
目錄下
而FIle 在按照原來的文件路徑src/main/resources/holiday.txt'
去尋找, 必然找不到文件, 因此會報文件找不到的異常
在定位問題的過程中發現, 這里 提供了一個思路
就是SpringBoot中所有文件都在jar包中,沒有一個實際的路徑,因此可以使用以下方式
/** * 通過ClassPathResource類獲取,建議SpringBoot中使用 * springboot項目中需要使用此種方法,因為jar包中沒有一個實際的路徑存放文件 * * @param fileName * @throws IOException */ public void function6(String fileName) throws IOException { ClassPathResource classPathResource = new ClassPathResource(fileName); InputStream inputStream = classPathResource.getInputStream(); getFileContent(inputStream); }
上面代碼的核心就是: 實例化
ClassPathResource
對象. 然后調用getInputStream
來獲取資源文件
下面我們來分析這些代碼
在 ClassPathResource
在實例化時, 會初始化類加載器 classLoader
并將項目所用到的所有路徑加載到類加載器 classLoader
中, 這些路徑包括: java運行環境的jar, Maven 項目中的jar, 以及當前項目打包后的jar等(如下圖)
而 classPathResource.getInputStream
在獲取資源文件時, 因為上面我們初始化了一個classLoader
.
所以classLoader
不為空, 因此會執行 getResourceAsStream
方法, 我們來追一下這個方法
getResourceAsStream
方法中的getResource
是實際的業務處理方法, 我們繼續深入
getResource
方法如下圖, 實際的功能就是遞歸調用自己, 去不斷遍歷 parent
下的路徑, 獲取對應的資源文件
那么 parent
又是誰呢? 我們繼續往下看
看到這里我們豁然開朗, 這個神秘的 parent
就是類加載器classLoader
!!!
因此getResource
方法就是去不斷遍歷我們在ClassPathResource
實例化時, 創建的類加載器下面的路徑!!!(對應第1點)
原來讀取文件的代碼如下
String s = FileUtils.readFileToString(new File("src/main/resources/holiday.txt"), "utf-8");
去查看 File 的構造函數, 看能否通過 InputStream
來構造
從下圖看是不行的
并且我們發現 org.apache.commons.io
下沒有提供將 ClassPathResource
作為入參的讀取文件的方法.
因此我們必須手寫讀取文件的方法
手寫的代碼如下
主要注意 Resource resource = new ClassPathResource(fileName); is = resource.getInputStream();
/** * Java讀取txt文件的內容 * * @param fileName resources目錄下文件名稱(無需帶目錄) * @return 將每行作為一個單位放到list中 */ public static List<String> readTxtFile(String fileName) { List<String> listContent = new ArrayList<>(); InputStream is = null; InputStreamReader isr = null; BufferedReader br = null; String encoding = "utf-8"; try { Resource resource = new ClassPathResource(fileName); is = resource.getInputStream(); isr = new InputStreamReader(is, encoding); br = new BufferedReader(isr); String lineTxt = null; while ((lineTxt = br.readLine()) != null) { listContent.add(lineTxt); } } catch (IOException e) { e.printStackTrace(); } finally { try { br.close(); isr.close(); is.close(); } catch (IOException e) { e.printStackTrace(); } } return listContent; }
這種方式對代碼入侵較小, 核心還是利用 common.io 下的 FileUtils, 具體方法是
利用FileUtils將ClassPathResource.getInputStream
得到的輸入流復制到臨時文件中, 然后讀取這個臨時文件
這種方式缺點是: 需要創建臨時文件, 如果待讀取文件過大, 則重新創建文件和復制操作會消耗一定的空間和時間, 影響性能
//方式二 利用FileUtils將ClassPathResource.getInputStream 得到的輸入流復制到臨時文件中 Resource resource = new ClassPathResource("holiday.txt"); InputStream inputStream = resource.getInputStream(); File tempFile = File.createTempFile("temp", ".txt"); FileUtils.copyInputStreamToFile(inputStream, tempFile); String s = FileUtils.readFileToString(tempFile, StandardCharsets.UTF_8);
到這里又出現了一個問題, 就是我用的測試項目因為在 maven 里面指定了某些格式的文件. 如下配置
因為指定了banner.txt 以及 xml 與 properties結尾的文件作為資源被打包. 所以文件 holiday.txt 運行后還是訪問不到
有問題的pom.xml文件如下
<!-- 資源拷貝插件,實現在打包時自動拷貝java目錄下以及resources目錄下的xml的配置文件 --> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> <include>**/banner.txt</include> </includes> </resource> </resources>
打包后資源文件截圖如下, 從該圖中可以看到 holiday.txt 沒有被打包進來
程序運行之后的錯誤截圖
我們修改下指定打包的配置 <include>**/*.txt</include>
這樣配置后, 我們就可以將類路徑下的所有txt 文件打包進行項目中了, 打包之后文件位置如下圖
或者我們可以去除項目中下面的代碼配置, 這樣做會默認打包 resources 下面的所有文件
<!-- 資源拷貝插件,實現在打包時自動拷貝java目錄下以及resources目錄下的xml的配置文件 --> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> <include>**/*.txt</include> </includes> </resource> </resources>
修改pom文件后, 重新打包后資源文件(從這里可以看到 holiday.txt 被打包進來 )
到此,關于“項目打包成jar后包無法讀取src/main/resources下文件怎么解決”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。