您好,登錄后才能下訂單哦!
JDK提供的訪問資源的類(如java.net.URL、File等)并不能很好的滿足各種底層資源的訪問,比如缺少從類路徑以及web容器上下文獲取資源的操作類,因此,Spring設計了一個Resource接口,他提供了更強訪問底層資源的能力,先來看看Resource接口的主要方法:
exists():用于判斷對應的資源是否真的存在。
isReadable():用于判斷對應資源的內容是否可讀。需要注意的是當其結果為true的時候,其內容未必真的可讀,但如果返回false,則其內容必定不可讀。
isOpen():用于判斷當前資源是否代表一個已打開的輸入流,如果結果為true,則表示當前資源的輸入流不可多次讀取,而且在讀取以后需要對它進行關閉,以防止內存泄露。該方法主要針對于InputStreamResource,實現類中只有它的返回結果為true,其他都為false。
getURL():返回當前資源對應的URL。如果當前資源不能解析為一個URL則會拋出異常。如ByteArrayResource就不能解析為一個URL。
getFile():返回當前資源對應的File。如果當前資源不能以絕對路徑解析為一個File則會拋出異常。如ByteArrayResource就不能解析為一個File。
getInputStream():獲取當前資源代表的輸入流。除了InputStreamResource以外,其它Resource實現類每次調用getInputStream()方法都將返回一個全新的InputStream。
Resource在Spring中占有重要作用,Spring用它來讀取配置文件、國際化屬性文件資源等下面來看一下Resource實現方法:
ByteArrayResource:二進制數組表示的資源,二進制數組源可以在內存中通過程序構造。
ClassPathResource:類路徑下的資源,資源以相對于類路徑的方式表示,如:new ClassPathResource("com/baobaotao/beanfactory/bean.xml")。
FileSystemResource:文件系統資源,資源以文件系統路徑的方式表示,如:new FileSystemResource("c:\\beans.xml")。
InputSteamResource:以輸入流返回表示的資源。
ServletContextResource:為訪問Web容器上下文中的資源而設計的類,負責從Web應用根目錄中加載資源,它支持以流和Url的方式訪問,在WAR解包的情況下,也可以通過File的方式訪問,該類還可以直接從JAR包中訪問資源。
UrlResource:Url封裝了java.net.URL,它使用戶能夠訪問任何可以通過URL表示的資源,如文件系統的資源、HTTP資源、FTP資源等。
有了這個抽象的資源類后,我們就可以將Spring的配置信息放置在任何地方(如數據庫、LDAP中),只要最終可以通過Resource接口返回配置信息就可以了。
注意:Spring的Resource可以脫離Spring框架下單獨使用。
下面我們來看看Resource能給我們帶來什么?
訪問文件資源
現在我們假設Web項目類路徑下有一個文件,那么我們應該怎么去讀取呢?
①FileSystemResource通過系統的絕對路徑去讀取。
②ClassPathResource以類路徑方式進行訪問。
③ServletContextResource以相對Web應用根目錄的方式讀取。
相比較JDK提供的訪問資源的方法,Resource可以讓我們根據需要進行更多的選擇,下面我們來看一下2種方法實現的代碼(項目名稱為Spring在其src下有個conf,里面有個test.txt的文件):
package test.com.gloryscience.service; import java.io.IOException; import java.io.InputStream; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; public class ResourceTest { public static void main(String[] args) { try { String filepath="F:/guoxiangworkspace/Spring/WebContent/WEB-INF/classes/conf/test.txt"; //以系統文件路徑的方式加載文件 Resource fileresource=new FileSystemResource(filepath); //以class類路徑加載文件 Resource classsource=new ClassPathResource("/conf/test.txt"); InputStream is2=classsource.getInputStream(); InputStream is1=fileresource.getInputStream(); System.out.println("通過FileSystemResource:"+fileresource.getFilename()); System.out.println("通過ClassPathResource:"+classsource.getFilename()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
在獲取資源后,您就可以通過 Resource 接口定義的多個方法訪問文件的數據和其它的信息:如您可以通過 getFileName() 獲取文件名,通過 getFile() 獲取資源對應的 File 對象,通過 getInputStream() 直接獲取文件的輸入流。此外,您還可以通過 createRelative(String relativePath) 在資源相對地址上創建新的資源。
在 Web 應用中,您還可以通過 ServletContextResource 以相對于 Web 應用根目錄的方式訪問文件資源,如下所示:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <jsp:directive.page import=" org.springframework.web.context.support.ServletContextResource"/> <jsp:directive.page import="org.springframework.core.io.Resource"/> <% // ① 注意文件資源地址以相對于 Web 應用根路徑的方式表示 Resource res3 = new ServletContextResource(application, "/WEB-INF/classes/conf/file1.txt"); out.print(res3.getFilename()); %>
對于位于遠程服務器(Web 服務器或 FTP 服務器)的文件資源,您則可以方便地通過 UrlResource 進行訪問。
為了方便訪問不同類型的資源,您必須使用相應的 Resource 實現類,是否可以在不顯式使用 Resource 實現類的情況下,僅根據帶特殊前綴的資源地址直接加載文件資源呢? Spring 提供了一個 ResourceUtils 工具類,它支持“classpath:”和“file:”的地址前綴,它能夠從指定的地址加載文件資源,請看下面的例子:
import org.springframework.util.ResourceUtils; public class ResourceUtilsExample { public static void main(String[] args) throws Throwable{ File clsFile = ResourceUtils.getFile("classpath:conf/file1.txt"); System.out.println(clsFile.isFile()); String httpFilePath = "file:D:/masterSpring/chapter23/src/conf/file1.txt"; File httpFile = ResourceUtils.getFile(httpFilePath); System.out.println(httpFile.isFile()); } }
本地化文件資源
本地化文件資源是一組通過本地化標識名進行特殊命名的文件,Spring 提供的 LocalizedResourceHelper 允許通過文件資源基名和本地化實體獲取匹配的本地化文件資源并以 Resource 對象返回。假設在類路徑的 i18n 目錄下,擁有一組基名為 message 的本地化文件資源,我們通過以下實例演示獲取對應中國大陸和美國的本地化文件資源:import java.util.Locale; import org.springframework.core.io.Resource; import org.springframework.core.io.support.LocalizedResourceHelper; public class LocaleResourceTest { public static void main(String[] args) { LocalizedResourceHelper lrHalper = new LocalizedResourceHelper(); // ① 獲取對應美國的本地化文件資源 Resource msg_us = lrHalper.findLocalizedResource("i18n/message", ".properties", Locale.US); // ② 獲取對應中國大陸的本地化文件資源 Resource msg_cn = lrHalper.findLocalizedResource("i18n/message", ".properties", Locale.CHINA); System.out.println("fileName(us):"+msg_us.getFilename()); System.out.println("fileName(cn):"+msg_cn.getFilename()); } }
文件操作
在使用各種 Resource 接口的實現類加載文件資源后,經常需要對文件資源進行讀取、拷貝、轉存等不同類型的操作。您可以通過 Resource 接口所提供了方法完成這些功能,不過在大多數情況下,通過 Spring 為 Resource 所配備的工具類完成文件資源的操作將更加方便。
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileReader; import java.io.OutputStream; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.util.FileCopyUtils; public class FileCopyUtilsExample { public static void main(String[] args) throws Throwable { Resource res = new ClassPathResource("conf/file1.txt"); // ① 將文件內容拷貝到一個 byte[] 中 byte[] fileData = FileCopyUtils.copyToByteArray(res.getFile()); // ② 將文件內容拷貝到一個 String 中 String fileStr = FileCopyUtils.copyToString(new FileReader(res.getFile())); // ③ 將文件內容拷貝到另一個目標文件 FileCopyUtils.copy(res.getFile(), new File(res.getFile().getParent()+ "/file2.txt")); // ④ 將文件內容拷貝到一個輸出流中 OutputStream os = new ByteArrayOutputStream(); FileCopyUtils.copy(res.getInputStream(), os); } }
往往我們都通過直接操作 InputStream 讀取文件的內容,但是流操作的代碼是比較底層的,代碼的面向對象性并不強。通過 FileCopyUtils 讀取和拷貝文件內容易于操作且相當直觀。如在 ① 處,我們通過 FileCopyUtils 的 copyToByteArray(File in) 方法就可以直接將文件內容讀到一個 byte[] 中;另一個可用的方法是 copyToByteArray(InputStream in),它將輸入流讀取到一個 byte[] 中。
如果是文本文件,您可能希望將文件內容讀取到 String 中,此時您可以使用 copyToString(Reader in) 方法,如 ② 所示。使用 FileReader 對 File 進行封裝,或使用 InputStreamReader 對 InputStream 進行封裝就可以了。
FileCopyUtils 還提供了多個將文件內容拷貝到各種目標對象中的方法,這些方法包括:
方法 說明
static void copy(byte[] in, File out) 將 byte[] 拷貝到一個文件中
static void copy(byte[] in, OutputStream out) 將 byte[] 拷貝到一個輸出流中
static int copy(File in, File out) 將文件拷貝到另一個文件中
static int copy(InputStream in, OutputStream out) 將輸入流拷貝到輸出流中
static int copy(Reader in, Writer out) 將 Reader 讀取的內容拷貝到 Writer 指向目標輸出中
static void copy(String in, Writer out) 將字符串拷貝到一個 Writer 指向的目標中
在實例中,我們雖然使用 Resource 加載文件資源,但 FileCopyUtils 本身和 Resource 沒有任何關系,您完全可以在基于 JDK I/O API 的程序中使用這個工具類。
屬性資源加載
我們知道可以通過 java.util.Properties 的 load(InputStream inStream) 方法從一個輸入流中加載屬性資源。Spring 提供的 PropertiesLoaderUtils 允許您直接通過基于類路徑的文件地址加載屬性資源,請看下面的例子:
import java.util.Properties; import org.springframework.core.io.support.PropertiesLoaderUtils; public class PropertiesLoaderUtilsExample { public static void main(String[] args) throws Throwable { // ① jdbc.properties 是位于類路徑下的文件 Properties props = PropertiesLoaderUtils.loadAllProperties("jdbc.properties"); System.out.println(props.getProperty("jdbc.driverClassName")); } }
一般情況下,應用程序的屬性文件都放置在類路徑下,所以 PropertiesLoaderUtils 比之于 Properties#load(InputStream inStream) 方法顯然具有更強的實用性。此外,PropertiesLoaderUtils 還可以直接從 Resource 對象中加載屬性資源:
方法 | 說明 |
---|---|
static Properties loadProperties(Resource resource) | 從 Resource 中加載屬性 |
static void fillProperties(Properties props, Resource resource) | 將 Resource 中的屬性數據添加到一個已經存在的 Properties 對象中 |
特殊編碼資源
當您使用 Resource 實現類加載文件資源時,它默認采用操作系統的編碼格式。如果文件資源采用了特殊的編碼格式(如 UTF-8),則在讀取資源內容時必須事先通過 EncodedResource 指定編碼格式,否則將會產生中文亂碼的問題。
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.EncodedResource; import org.springframework.util.FileCopyUtils; public class EncodedResourceExample { public static void main(String[] args) throws Throwable { Resource res = new ClassPathResource("conf/file1.txt"); // ① 指定文件資源對應的編碼格式(UTF-8) EncodedResource encRes = new EncodedResource(res,"UTF-8"); // ② 這樣才能正確讀取文件的內容,而不會出現亂碼 String content = FileCopyUtils.copyToString(encRes.getReader()); System.out.println(content); } }
EncodedResource 擁有一個 getResource() 方法獲取 Resource,但該方法返回的是通過構造函數傳入的原 Resource 對象,所以必須通過 EncodedResource#getReader() 獲取應用編碼后的 Reader 對象,然后再通過該 Reader 讀取文件的內容。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。