欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

項(xiàng)目打包成jar后包無(wú)法讀取src/main/resources下文件的解決

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

一、項(xiàng)目場(chǎng)景

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

二、問(wèn)題描述

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

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

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

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

在這里插入圖片描述

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

分析問(wèn)題

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

在這里插入圖片描述

在定位問(wèn)題的過(guò)程中發(fā)現(xiàn), 這里 提供了一個(gè)思路
就是SpringBoot中所有文件都在jar包中,沒(méi)有一個(gè)實(shí)際的路徑,因此可以使用以下方式

    /**
     * 通過(guò)ClassPathResource類獲取,建議SpringBoot中使用
     * springboot項(xiàng)目中需要使用此種方法,因?yàn)閖ar包中沒(méi)有一個(gè)實(shí)際的路徑存放文件
     *
     * @param fileName
     * @throws IOException
     */
    public void function6(String fileName) throws IOException {
        ClassPathResource classPathResource = new ClassPathResource(fileName);
        InputStream inputStream = classPathResource.getInputStream();
        getFileContent(inputStream);
    }

為什么使用 ClassPathResource 后, 可以找到打包后的文件路徑?

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

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

在這里插入圖片描述

classPathResource.getInputStream 在獲取資源文件時(shí), 因?yàn)樯厦嫖覀兂跏蓟艘粋€(gè)classLoader.
所以classLoader不為空, 因此會(huì)執(zhí)行 getResourceAsStream 方法, 我們來(lái)追一下這個(gè)方法

在這里插入圖片描述

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

在這里插入圖片描述

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

在這里插入圖片描述

看到這里我們豁然開(kāi)朗, 這個(gè)神秘的 parent 就是類加載器classLoader!!!
因此getResource 方法就是去不斷遍歷我們?cè)?/strong>ClassPathResource實(shí)例化時(shí), 創(chuàng)建的類加載器下面的路徑!!!(對(duì)應(yīng)第1點(diǎn))

在這里插入圖片描述

三、解決方案

原來(lái)讀取文件的代碼如下

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

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

在這里插入圖片描述

方案一

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

在這里插入圖片描述

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

    /**
     * Java讀取txt文件的內(nèi)容
     *
     * @param fileName resources目錄下文件名稱(無(wú)需帶目錄)
     * @return 將每行作為一個(gè)單位放到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;
    }

方案二

這種方式對(duì)代碼入侵較小, 核心還是利用 common.io 下的 FileUtils, 具體方法是
利用FileUtils將ClassPathResource.getInputStream 得到的輸入流復(fù)制到臨時(shí)文件中, 然后讀取這個(gè)臨時(shí)文件
這種方式缺點(diǎn)是: 需要?jiǎng)?chuàng)建臨時(shí)文件, 如果待讀取文件過(guò)大, 則重新創(chuàng)建文件和復(fù)制操作會(huì)消耗一定的空間和時(shí)間, 影響性能

  //方式二 利用FileUtils將ClassPathResource.getInputStream 得到的輸入流復(fù)制到臨時(shí)文件中
  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)了一個(gè)問(wèn)題, 就是我用的測(cè)試項(xiàng)目因?yàn)樵?maven 里面指定了某些格式的文件. 如下配置
因?yàn)橹付薭anner.txt 以及 xml 與 properties結(jié)尾的文件作為資源被打包. 所以文件 holiday.txt 運(yùn)行后還是訪問(wèn)不到
有問(wèn)題的pom.xml文件如下

	<!-- 資源拷貝插件,實(shí)現(xiàn)在打包時(shí)自動(dòng)拷貝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 沒(méi)有被打包進(jìn)來(lái)

在這里插入圖片描述

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

在這里插入圖片描述

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

	<!-- 資源拷貝插件,實(shí)現(xiàn)在打包時(shí)自動(dòng)拷貝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)來(lái) )

在這里插入圖片描述

總結(jié)

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

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

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

相關(guān)文章

最新評(píng)論