亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時間:2022年04月02日 11:28:18   作者:時間靜止不是簡史  
本文主要介紹了項目打包成jar后包無法讀取src/main/resources下文件的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、項目場景

在項目中讀取文件時, 使用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") , 在本地運(yùn)行沒問題,
但是打包之后在服務(wù)器中運(yùn)行出現(xiàn)了問題. 下面是錯誤截圖

在這里插入圖片描述

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

分析問題

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

在這里插入圖片描述

在定位問題的過程中發(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運(yùn)行環(huán)境的jar, Maven 項目中的jar, 以及當(dāng)前項目打包后的jar等(如下圖)

在這里插入圖片描述

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

在這里插入圖片描述

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

在這里插入圖片描述

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

在這里插入圖片描述

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

在這里插入圖片描述

三、解決方案

原來讀取文件的代碼如下

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

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

在這里插入圖片描述

方案一

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

在這里插入圖片描述

手寫的代碼如下
主要注意 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 運(yùn)行后還是訪問不到
有問題的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 沒有被打包進(jìn)來

在這里插入圖片描述

程序運(yùn)行之后的錯誤截圖

在這里插入圖片描述

我們修改下指定打包的配置 <include>**/*.txt</include>
這樣配置后, 我們就可以將類路徑下的所有txt 文件打包進(jìn)行項目中了, 打包之后文件位置如下圖
或者我們可以去除項目中下面的代碼配置, 這樣做會默認(rèn)打包 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 被打包進(jìn)來 )

在這里插入圖片描述

總結(jié)

在項目內(nèi)的文件的讀取/下載時, 由于本地路徑和項目打包后的路徑不同. 出現(xiàn)找不到文件的情況,我們只需要例化ClassPathResource(文件名) 對象. 然后調(diào)用getInputStream 來獲取資源文件.就能獲取任意環(huán)境下項目內(nèi)的文件

如果想打算使用其他方式來獲取resources 目錄下的文件, 可以參見 這篇博客 .核心和上面問題分析差不多, 基本上都是通過類加載器來獲取資源文件的輸入流進(jìn)而找到這個文件

到此這篇關(guān)于項目打包成jar后包無法讀取src/main/resources下文件的解決的文章就介紹到這了,更多相關(guān)jar無法讀取src/main/resources文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論