溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

項目打包成jar后包無法讀取src/main/resources下文件怎么解決

發(fā)布時間:2022-04-02 13:42:55 來源:億速云 閱讀:1156 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“項目打包成jar后包無法讀取src/main/resources下文件怎么解決”,在日常操作中,相信很多人在項目打包成jar后包無法讀取src/main/resources下文件怎么解決問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”項目打包成jar后包無法讀取src/main/resources下文件怎么解決”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習吧!

    一、項目場景

    在項目中讀取文件時, 使用new File() 出現(xiàn)的一個坑以及解決流程
    這種問題不僅在本地文件讀取時會遇到, 而且在下載項目下 (例如: src/main/resources目錄下) 的文本時, 也會遇到,

    二、問題描述

    發(fā)現(xiàn)問題

    原來代碼
    該代碼功能是利用 common.io 包下的FileUtils來讀取文件, 放到一個字符串中

    String s = FileUtils.readFileToString(new File("src/main/resources/holiday.txt"), "utf-8");

    這種路徑書寫方式 new File("src/main/resources/holiday.txt") , 在本地運行沒問題,
    但是打包之后在服務(wù)器中運行出現(xiàn)了問題. 下面是錯誤截圖

    項目打包成jar后包無法讀取src/main/resources下文件怎么解決

    可以看到在服務(wù)器中日志提示: java.io.FileNotFoundException: File 'holiday.txt' does not exist
    即: 在打包后, 一開始配置的路徑src/main/resources下無法找到該文件

    分析問題

    項目在打包之后, 位于 resource目錄下的文件, 最常見的就是各種Spring配置文件就會打包在 BOOT-INF/classes 目錄下
    而FIle 在按照原來的文件路徑src/main/resources/holiday.txt'去尋找, 必然找不到文件, 因此會報文件找不到的異常

    項目打包成jar后包無法讀取src/main/resources下文件怎么解決

    在定位問題的過程中發(fā)現(xiàn), 這里 提供了一個思路
    就是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 后, 可以找到打包后的文件路徑?

    上面代碼的核心就是: 實例化ClassPathResource 對象. 然后調(diào)用getInputStream 來獲取資源文件

    下面我們來分析這些代碼
    ClassPathResource 在實例化時, 會初始化類加載器 classLoader 并將項目所用到的所有路徑加載到類加載器 classLoader 中, 這些路徑包括: java運行環(huán)境的jar, Maven 項目中的jar, 以及當前項目打包后的jar等(如下圖)

    項目打包成jar后包無法讀取src/main/resources下文件怎么解決

    classPathResource.getInputStream 在獲取資源文件時, 因為上面我們初始化了一個classLoader.
    所以classLoader不為空, 因此會執(zhí)行 getResourceAsStream 方法, 我們來追一下這個方法

    項目打包成jar后包無法讀取src/main/resources下文件怎么解決

    getResourceAsStream 方法中的getResource是實際的業(yè)務(wù)處理方法, 我們繼續(xù)深入

    項目打包成jar后包無法讀取src/main/resources下文件怎么解決

    getResource 方法如下圖, 實際的功能就是遞歸調(diào)用自己, 去不斷遍歷 parent 下的路徑, 獲取對應(yīng)的資源文件
    那么 parent 又是誰呢? 我們繼續(xù)往下看

    項目打包成jar后包無法讀取src/main/resources下文件怎么解決

    看到這里我們豁然開朗, 這個神秘的 parent 就是類加載器classLoader!!!
    因此getResource 方法就是去不斷遍歷我們在ClassPathResource實例化時, 創(chuàng)建的類加載器下面的路徑!!!(對應(yīng)第1點)

    項目打包成jar后包無法讀取src/main/resources下文件怎么解決

    三、解決方案

    原來讀取文件的代碼如下

    String s = FileUtils.readFileToString(new File("src/main/resources/holiday.txt"), "utf-8");

    去查看 File 的構(gòu)造函數(shù), 看能否通過 InputStream 來構(gòu)造
    從下圖看是不行的

    項目打包成jar后包無法讀取src/main/resources下文件怎么解決

    方案一

    并且我們發(fā)現(xiàn) org.apache.commons.io沒有提供ClassPathResource 作為入?yún)⒌淖x取文件的方法.
    因此我們必須手寫讀取文件的方法

    項目打包成jar后包無法讀取src/main/resources下文件怎么解決

    手寫的代碼如下
    主要注意 Resource resource = new ClassPathResource(fileName); is = resource.getInputStream();

        /**
         * Java讀取txt文件的內(nèi)容
         *
         * @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 得到的輸入流復(fù)制到臨時文件中, 然后讀取這個臨時文件
    這種方式缺點是: 需要創(chuàng)建臨時文件, 如果待讀取文件過大, 則重新創(chuàng)建文件和復(fù)制操作會消耗一定的空間和時間, 影響性能

      //方式二 利用FileUtils將ClassPathResource.getInputStream 得到的輸入流復(fù)制到臨時文件中
      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);

    意外出現(xiàn)

    到這里又出現(xiàn)了一個問題, 就是我用的測試項目因為在 maven 里面指定了某些格式的文件. 如下配置
    因為指定了banner.txt 以及 xml 與 properties結(jié)尾的文件作為資源被打包. 所以文件 holiday.txt 運行后還是訪問不到
    有問題的pom.xml文件如下

    	<!-- 資源拷貝插件,實現(xiàn)在打包時自動拷貝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 沒有被打包進來

    項目打包成jar后包無法讀取src/main/resources下文件怎么解決

    程序運行之后的錯誤截圖

    項目打包成jar后包無法讀取src/main/resources下文件怎么解決

    我們修改下指定打包的配置 <include>**/*.txt</include>
    這樣配置后, 我們就可以將類路徑下的所有txt 文件打包進行項目中了, 打包之后文件位置如下圖
    或者我們可以去除項目中下面的代碼配置, 這樣做會默認打包 resources 下面的所有文件

    	<!-- 資源拷貝插件,實現(xiàn)在打包時自動拷貝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下文件怎么解決

    到此,關(guān)于“項目打包成jar后包無法讀取src/main/resources下文件怎么解決”的學(xué)習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習,快去試試吧!若想繼續(xù)學(xué)習更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    jar
    AI