糊言亂語(yǔ)

          志未半斤, 才無(wú)八兩. 有苦有樂(lè), 糊涂過(guò)活。
          posts - 25, comments - 7, trackbacks - 0, articles - 42
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          文件資源的操作是應(yīng)用程序中常見(jiàn)的功能,如當(dāng)上傳一個(gè)文件后將其保存在特定目錄下,從指定地址加載一個(gè)配置文件等等。我們一般使用 JDK 的 I/O 處理類完成這些操作,但對(duì)于一般的應(yīng)用程序來(lái)說(shuō),JDK 的這些操作類所提供的方法過(guò)于底層,直接使用它們進(jìn)行文件操作不但程序編寫(xiě)復(fù)雜而且容易產(chǎn)生錯(cuò)誤。相比于 JDK 的 File,Spring 的 Resource 接口(資源概念的描述接口)抽象層面更高且涵蓋面更廣,Spring 提供了許多方便易用的資源操作工具類,它們大大降低資源操作的復(fù)雜度,同時(shí)具有更強(qiáng)的普適性。這些工具類不依賴于 Spring 容器,這意味著您可以在程序中象一般普通類一樣使用它們。

          加載文件資源

          Spring 定義了一個(gè) org.springframework.core.io.Resource 接口,Resource 接口是為了統(tǒng)一各種類型不同的資源而定義的,Spring 提供了若干 Resource 接口的實(shí)現(xiàn)類,這些實(shí)現(xiàn)類可以輕松地加載不同類型的底層資源,并提供了獲取文件名、URL 地址以及資源內(nèi)容的操作方法。

          訪問(wèn)文件資源

          假設(shè)有一個(gè)文件地位于 Web 應(yīng)用的類路徑下,您可以通過(guò)以下方式對(duì)這個(gè)文件資源進(jìn)行訪問(wèn):

          • 通過(guò) FileSystemResource 以文件系統(tǒng)絕對(duì)路徑的方式進(jìn)行訪問(wèn);
          • 通過(guò) ClassPathResource 以類路徑的方式進(jìn)行訪問(wèn);
          • 通過(guò) ServletContextResource 以相對(duì)于Web應(yīng)用根目錄的方式進(jìn)行訪問(wèn)。

          相比于通過(guò) JDK 的 File 類訪問(wèn)文件資源的方式,Spring 的 Resource 實(shí)現(xiàn)類無(wú)疑提供了更加靈活的操作方式,您可以根據(jù)情況選擇適合的 Resource 實(shí)現(xiàn)類訪問(wèn)資源。下面,我們分別通過(guò) FileSystemResource 和 ClassPathResource 訪問(wèn)同一個(gè)文件資源:


          清單 1. FileSourceExample

          package com.baobaotao.io;
          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 FileSourceExample {
              public static void main(String[] args) {
                  try {
                      String filePath = 
                      "D:/masterSpring/chapter23/webapp/WEB-INF/classes/conf/file1.txt";
                      // ① 使用系統(tǒng)文件路徑方式加載文件
                      Resource res1 = new FileSystemResource(filePath); 
                      // ② 使用類路徑方式加載文件
                      Resource res2 = new ClassPathResource("conf/file1.txt");
                      InputStream ins1 = res1.getInputStream();
                      InputStream ins2 = res2.getInputStream();
                      System.out.println("res1:"+res1.getFilename());
                      System.out.println("res2:"+res2.getFilename());
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
          

          在獲取資源后,您就可以通過(guò) Resource 接口定義的多個(gè)方法訪問(wèn)文件的數(shù)據(jù)和其它的信息:如您可以通過(guò) getFileName() 獲取文件名,通過(guò) getFile() 獲取資源對(duì)應(yīng)的 File 對(duì)象,通過(guò) getInputStream() 直接獲取文件的輸入流。此外,您還可以通過(guò) createRelative(String relativePath) 在資源相對(duì)地址上創(chuàng)建新的資源。

          在 Web 應(yīng)用中,您還可以通過(guò) ServletContextResource 以相對(duì)于 Web 應(yīng)用根目錄的方式訪問(wèn)文件資源,如下所示:

          <%@ 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"/>
          <%
              // ① 注意文件資源地址以相對(duì)于 Web 應(yīng)用根路徑的方式表示
              Resource res3 = new ServletContextResource(application, 
                  "/WEB-INF/classes/conf/file1.txt");
              out.print(res3.getFilename());
          %>
          

          對(duì)于位于遠(yuǎn)程服務(wù)器(Web 服務(wù)器或 FTP 服務(wù)器)的文件資源,您則可以方便地通過(guò) UrlResource 進(jìn)行訪問(wèn)。

          為了方便訪問(wèn)不同類型的資源,您必須使用相應(yīng)的 Resource 實(shí)現(xiàn)類,是否可以在不顯式使用 Resource 實(shí)現(xiàn)類的情況下,僅根據(jù)帶特殊前綴的資源地址直接加載文件資源呢?Spring 提供了一個(gè) ResourceUtils 工具類,它支持"classpath:"和"file:"的地址前綴,它能夠從指定的地址加載文件資源,請(qǐng)看下面的例子:


          清單 2. ResourceUtilsExample

          package com.baobaotao.io;
          import java.io.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());        
              }
          }
          

          ResourceUtils 的 getFile(String resourceLocation) 方法支持帶特殊前綴的資源地址,這樣,我們就可以在不和 Resource 實(shí)現(xiàn)類打交道的情況下使用 Spring 文件資源加載的功能了。

          本地化文件資源

          本地化文件資源是一組通過(guò)本地化標(biāo)識(shí)名進(jìn)行特殊命名的文件,Spring 提供的 LocalizedResourceHelper 允許通過(guò)文件資源基名和本地化實(shí)體獲取匹配的本地化文件資源并以 Resource 對(duì)象返回。假設(shè)在類路徑的 i18n 目錄下,擁有一組基名為 message 的本地化文件資源,我們通過(guò)以下實(shí)例演示獲取對(duì)應(yīng)中國(guó)大陸和美國(guó)的本地化文件資源:


          清單 3. LocaleResourceTest

          package com.baobaotao.io;
          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();
                  // ① 獲取對(duì)應(yīng)美國(guó)的本地化文件資源
                  Resource msg_us = lrHalper.findLocalizedResource("i18n/message", ".properties", 
                  Locale.US);
                  // ② 獲取對(duì)應(yīng)中國(guó)大陸的本地化文件資源
                  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());
              }
          }
          

          雖然 JDK 的 java.util.ResourceBundle 類也可以通過(guò)相似的方式獲取本地化文件資源,但是其返回的是 ResourceBundle 類型的對(duì)象。如果您決定統(tǒng)一使用 Spring 的 Resource 接表征文件資源,那么 LocalizedResourceHelper 就是獲取文件資源的非常適合的幫助類了。

          文件操作

          在使用各種 Resource 接口的實(shí)現(xiàn)類加載文件資源后,經(jīng)常需要對(duì)文件資源進(jìn)行讀取、拷貝、轉(zhuǎn)存等不同類型的操作。您可以通過(guò) Resource 接口所提供了方法完成這些功能,不過(guò)在大多數(shù)情況下,通過(guò) Spring 為 Resource 所配備的工具類完成文件資源的操作將更加方便。

          文件內(nèi)容拷貝

          第一個(gè)我們要認(rèn)識(shí)的是 FileCopyUtils,它提供了許多一步式的靜態(tài)操作方法,能夠?qū)⑽募?nèi)容拷貝到一個(gè)目標(biāo) byte[]、String 甚至一個(gè)輸出流或輸出文件中。下面的實(shí)例展示了 FileCopyUtils 具體使用方法:


          清單 4. FileCopyUtilsExample

          package com.baobaotao.io;
          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");
                  // ① 將文件內(nèi)容拷貝到一個(gè) byte[] 中
                  byte[] fileData = FileCopyUtils.copyToByteArray(res.getFile());
                  // ② 將文件內(nèi)容拷貝到一個(gè) String 中
                  String fileStr = FileCopyUtils.copyToString(new FileReader(res.getFile()));
                  // ③ 將文件內(nèi)容拷貝到另一個(gè)目標(biāo)文件
                  FileCopyUtils.copy(res.getFile(), 
                  new File(res.getFile().getParent()+ "/file2.txt"));
          
                  // ④ 將文件內(nèi)容拷貝到一個(gè)輸出流中
                  OutputStream os = new ByteArrayOutputStream();
                  FileCopyUtils.copy(res.getInputStream(), os);
              }
          }
          

          往往我們都通過(guò)直接操作 InputStream 讀取文件的內(nèi)容,但是流操作的代碼是比較底層的,代碼的面向?qū)ο笮圆⒉粡?qiáng)。通過(guò) FileCopyUtils 讀取和拷貝文件內(nèi)容易于操作且相當(dāng)直觀。如在 ① 處,我們通過(guò) FileCopyUtils 的 copyToByteArray(File in) 方法就可以直接將文件內(nèi)容讀到一個(gè) byte[] 中;另一個(gè)可用的方法是 copyToByteArray(InputStream in),它將輸入流讀取到一個(gè) byte[] 中。

          如果是文本文件,您可能希望將文件內(nèi)容讀取到 String 中,此時(shí)您可以使用 copyToString(Reader in) 方法,如 ② 所示。使用 FileReader 對(duì) File 進(jìn)行封裝,或使用 InputStreamReader 對(duì) InputStream 進(jìn)行封裝就可以了。

          FileCopyUtils 還提供了多個(gè)將文件內(nèi)容拷貝到各種目標(biāo)對(duì)象中的方法,這些方法包括:

          方法 說(shuō)明
          static void copy(byte[] in, File out) 將 byte[] 拷貝到一個(gè)文件中
          static void copy(byte[] in, OutputStream out) 將 byte[] 拷貝到一個(gè)輸出流中
          static int copy(File in, File out) 將文件拷貝到另一個(gè)文件中
          static int copy(InputStream in, OutputStream out) 將輸入流拷貝到輸出流中
          static int copy(Reader in, Writer out) 將 Reader 讀取的內(nèi)容拷貝到 Writer 指向目標(biāo)輸出中
          static void copy(String in, Writer out) 將字符串拷貝到一個(gè) Writer 指向的目標(biāo)中

          在實(shí)例中,我們雖然使用 Resource 加載文件資源,但 FileCopyUtils 本身和 Resource 沒(méi)有任何關(guān)系,您完全可以在基于 JDK I/O API 的程序中使用這個(gè)工具類。

          屬性文件操作

          我們知道可以通過(guò) java.util.Properties的load(InputStream inStream) 方法從一個(gè)輸入流中加載屬性資源。Spring 提供的 PropertiesLoaderUtils 允許您直接通過(guò)基于類路徑的文件地址加載屬性資源,請(qǐng)看下面的例子:

          package com.baobaotao.io;
          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"));
              }
          }
          

          一般情況下,應(yīng)用程序的屬性文件都放置在類路徑下,所以 PropertiesLoaderUtils 比之于 Properties#load(InputStream inStream) 方法顯然具有更強(qiáng)的實(shí)用性。此外,PropertiesLoaderUtils 還可以直接從 Resource 對(duì)象中加載屬性資源:

          方法 說(shuō)明
          static Properties loadProperties(Resource resource) 從 Resource 中加載屬性
          static void fillProperties(Properties props, Resource resource) 將 Resource 中的屬性數(shù)據(jù)添加到一個(gè)已經(jīng)存在的 Properties 對(duì)象中

          特殊編碼的資源

          當(dāng)您使用 Resource 實(shí)現(xiàn)類加載文件資源時(shí),它默認(rèn)采用操作系統(tǒng)的編碼格式。如果文件資源采用了特殊的編碼格式(如 UTF-8),則在讀取資源內(nèi)容時(shí)必須事先通過(guò) EncodedResource 指定編碼格式,否則將會(huì)產(chǎn)生中文亂碼的問(wèn)題。


          清單 5. EncodedResourceExample

          package com.baobaotao.io;
          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");
                      // ① 指定文件資源對(duì)應(yīng)的編碼格式(UTF-8)
                      EncodedResource encRes = new EncodedResource(res,"UTF-8");
                      // ② 這樣才能正確讀取文件的內(nèi)容,而不會(huì)出現(xiàn)亂碼
                      String content  = FileCopyUtils.copyToString(encRes.getReader());
                      System.out.println(content);  
              }
          }
          

          EncodedResource 擁有一個(gè) getResource() 方法獲取 Resource,但該方法返回的是通過(guò)構(gòu)造函數(shù)傳入的原 Resource 對(duì)象,所以必須通過(guò) EncodedResource#getReader() 獲取應(yīng)用編碼后的 Reader 對(duì)象,然后再通過(guò)該 Reader 讀取文件的內(nèi)容。


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 甘孜县| 巴楚县| 上思县| 光山县| 长顺县| 科技| 蕉岭县| 绩溪县| 株洲市| 宁波市| 榆林市| 克山县| 南雄市| 西昌市| 宿州市| 渭源县| 桂东县| 斗六市| 河北省| 双鸭山市| 三台县| 民乐县| 清苑县| 资源县| 洛扎县| 罗源县| 东宁县| 商丘市| 洪泽县| 东乌珠穆沁旗| 交城县| 延边| 光山县| 西青区| 嵩明县| 河津市| 绥中县| 古蔺县| 剑川县| 曲阜市| 育儿|