Java 7 中 NIO.2 的使用——第一節 Path 類的使用


  路徑隸屬於文件系統,實際上它是存儲和組織媒體文件的格式,通常在一塊或多塊硬盤設備上,以便於非常容易地檢索。文件系統可以通過  java.nio.file.FileSystems 這個final 類來訪問,通常我們用來獲取它的實例然后做我們想做的事情。FileSystems 包含下面兩個非常重要的方法,還有 newFileSystem() 方法,用來構建一個新的文件系統實例。

  • getDefault(): 這個靜態方法會返回一個默認的FileSystem 給 JVM——通常是操作系統默認的文件系統。
  • getFileSystem(URI uri): 這個靜態方法根據提供的可以匹配 URI 模式的一系列可用的文件系統提供者中返回一個文件系統。Path類可以操作任何類型的文件系統並可以使用任何存儲的地方(java.nio.file.FileStore這個類會呈現潛在的存儲)。通常情況下,Path類指向默認的操作系統的文件,但是在 NIO.2 中 徹底模塊化了—— 可以是內存中數據,在互聯網上,在虛擬文件系統的FileSystem 類的實現,這些都可以都可以完美的被NIO.2接受,NIO.2 提供了所有文件系統的功能,我們需要執行在文件,目錄或是一個link 鏈接文件上。

  Path類實際上是java.io.File類的升級版本,但是File類有一些特定的操作,所以File類不要被認為是過時的類,也不要把他當作一個障礙。此外,在Java 7 中,這兩個類都是可以繼續使用,這就意味着可以混合使用這兩個類來獲取最佳的 API 操作。 Java 7 中提供了非常簡單的API 方便這兩者的互相轉換。

  在以前IO操作都是這樣寫的。

import java.io.File;
…
File file = new File("index.html");

  但在Java7 中,我們可以這樣寫:

import java.nio.file.Path;
import java.nio.file.Paths;
…
Path path = Paths.get("index.html");

  最后總結,一個 Path 類 是一個路徑在文件系統中的程序表示。Path基本上就是一個文件路徑的字符串,實際的引用的資源可以不存在。

  一旦你確定了文件系統和文件或是目錄的存儲的地方,你就可以創建一個Path實例。絕對路徑,相對路徑,使用“.”定義的當前路徑以及“..” 定義的父級路徑,路徑中包含一個文件或是目錄名字,這些都可以用Path類來搞定。最簡單辦法是使用Paths幫助類來調用get() 方法。下面的例子演示了使用同一路徑定義path的幾種不同的方法。默認使用C:\rafaelnadal\tournaments\2009\BNP.txt這個路徑。

  定義一個絕對目錄

  一個絕對目錄就是包含了根目錄然后接下來幾層子目錄最后是文件名或是最后一層的目錄。你可以使用下面代碼來定義一個絕對目錄Path類。

Path path = Paths.get("C:/rafaelnadal/tournaments/2009/BNP.txt");

  get()方法也支持把路徑分割成一塊一塊的。NIO會重新組織路徑。看下面代碼:

Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
Path path = Paths.get("C:", "rafaelnadal/tournaments/2009", "BNP.txt");
Path path = Paths.get("C:", "rafaelnadal", "tournaments", "2009", "BNP.txt");

  定義一個相對於根路徑的相對路徑

  相對路徑是全路徑的一部分,相對路徑通常用在創建web 頁面中。相對路徑要比絕對路徑用的更加廣泛。在當前路徑下保存一個相對路徑通常要加上文件分隔符。例如,如果當前路徑是C盤,則絕對路徑應該是:C:\rafaelnadal\tournaments\2009\BNP.txt:

Path path = Paths.get("/rafaelnadal/tournaments/2009/BNP.txt");
Path path = Paths.get("/rafaelnadal","tournaments/2009/BNP.txt");

   定義一個相對於工作目錄的相對路徑

  當你定義一個相對於當前工作目錄的路徑,這個路徑就不用使用文件分隔符作為開始。例如向前目錄是相對於根目錄C盤下的/ATP目錄,則根據下面的代碼返回絕對路徑是:C:\ATP\rafaelnadal\tournaments\2009\BNP.txt:

Path path = Paths.get("rafaelnadal/tournaments/2009/BNP.txt");
Path path = Paths.get("rafaelnadal","tournaments/2009/BNP.txt"); 

  定義一個從URI獲取的路徑

  在一些情況下,你需要從URI中創建一個路徑,你可以使用URI.create() 方法根據指定的字符串從URI中創建路徑。

import java.net.URI;
 …
 Path path = Paths.get(URI.create("file:///rafaelnadal/tournaments/2009/BNP.txt"));
 Path path = Paths.get(URI.create("file:///C:/rafaelnadal/tournaments/2009/BNP.txt")); 

  你也可以使用FileSystems.getDefault().getPath() 方法來定義一個Path類。

  

import java.nio.file.FileSystems;
 …
 Path path = FileSystems.getDefault().getPath("/rafaelnadal/tournaments/2009", "BNP.txt");
 Path path = FileSystems.getDefault().getPath("/rafaelnadal/tournaments/2009/BNP.txt");
 Path path = FileSystems.getDefault().getPath("rafaelnadal/tournaments/2009", "BNP.txt");
 Path path = FileSystems.getDefault().
                         getPath("/rafaelnadal/tournaments/./2009","BNP.txt").normalize();

  獲取系統的主目錄的路徑

  當你想獲取主目錄的路徑時,可以使用下面的代碼:

Path path = Paths.get(System.getProperty("user.home"), "downloads", "game.exe");

  在Windows 7 中,返回的路徑是C:\Users\{your user name}\downloads\game.exe,在Linux系統中,則返回/home/{your user name}/downloads/game.exe。

  ----------------------------------------------------------------------------------------------------------------------------

  獲取路徑的信息

  當你定義完Path對象后,接下來會有一系列的方法用來訪問文件的信息。首先定義一個Path實例:

Path path = Paths.get("C:", "rafaelnadal/tournaments/2009", "BNP.txt");

  獲取文件或目錄的名字:

//output: BNP.txt
 System.out.println("The file/directory indicated by path: " + path.getFileName()); 

  獲取根目錄

//output: C:\
 System.out.println("Root of this path: " + path.getRoot()); 

  獲取路徑的父目錄

//output: C:\rafaelnadal\tournaments\2009
 System.out.println("Parent: " + path.getParent());

  獲取路徑名的元素

  你可以使用 getNameCount()方法獲取路徑層級的個數,然后再使用getName()循環遍歷每個元素的名字。

//output: 4
 System.out.println("Number of name elements in path: " + path.getNameCount());
 
//output: rafaelnadal  tournaments  2009  BNP.txt
 for (int i = 0; i < path.getNameCount(); i++) {
   System.out.println("Name element " + i + " is: " + path.getName(i));
 }

  獲取子路徑

//output: rafaelnadal\tournaments\2009
 System.out.println("Subpath (0,3): " + path.subpath(0, 3)); 

  --------------------------------------------------------------------------------------------------------------------------

  Path的轉換

  在這節中,將會介紹怎樣由一個Path對象轉換成字符串,URI,絕對路徑,相對路徑以及File對象。

  先定義一個Path實例:

Path path = Paths.get("/rafaelnadal/tournaments/2009", "BNP.txt");

  轉化成一個字符串

//output: \rafaelnadal\tournaments\2009\BNP.txt
 String path_to_string = path.toString();
 System.out.println("Path to String: " + path_to_string);

  轉換成一個URI

//output: file:///C:/rafaelnadal/tournaments/2009/BNP.txt
 URI path_to_uri = path.toUri();
 System.out.println("Path to URI: " + path_to_uri); 

  由相對路徑轉換成絕對路徑

//output: C:\rafaelnadal\tournaments\2009\BNP.txt
 Path path_to_absolute_path = path.toAbsolutePath();
 System.out.println("Path to absolute path: " + path_to_absolute_path.toString()); 

  轉換成真實路徑

import java.io.IOException;
 …
 //output: C:\rafaelnadal\tournaments\2009\BNP.txt
 try {
     Path real_path = path.toRealPath(LinkOption.NOFOLLOW_LINKS);
     System.out.println("Path to real path: " + real_path);
 } catch (NoSuchFileException e) {
     System.err.println(e);
 } catch (IOException e) {
     System.err.println(e);
 }

  轉換成File對象

//output: BNP.txt
 File path_to_file = path.toFile();
 
//output: \rafaelnadal\tournaments\2009\BNP.txt
 Path file_to_path = path_to_file.toPath();
 System.out.println("Path to file name: " + path_to_file.getName());
 System.out.println("File to path: " + file_to_path.toString()); 

  --------------------------------------------------------------------------------------------------------------------------

  合並兩個路徑

  合並兩個路徑的技術允許你先定義一個固定的根目錄然后再附上局部的路徑,在NIO.2 中,使用resolve() 方法來實現這一功能。

//define the fixed path
 Path base = Paths.get("C:/rafaelnadal/tournaments/2009");
 
//resolve BNP.txt file
 Path path_1 = base.resolve("BNP.txt");
 //output: C:\rafaelnadal\tournaments\2009\BNP.txt
 System.out.println(path_1.toString());
 
//resolve AEGON.txt file
 Path path_2 = base.resolve("AEGON.txt");
 //output: C:\rafaelnadal\tournaments\2009\AEGON.txt
 System.out.println(path_2.toString());

  還有一個方法用於兄弟路徑,叫resolveSibling(),它會根據給定的路徑去替換當前的路徑。

//define the fixed path
 Path base = Paths.get("C:/rafaelnadal/tournaments/2009/BNP.txt");
 
//resolve sibling AEGON.txt file
 Path path = base.resolveSibling("AEGON.txt");
 //output: C:\rafaelnadal\tournaments\2009\AEGON.txt
 System.out.println(path.toString());

  --------------------------------------------------------------------------------------------------------------------------------

  在兩個位置中構造一個路徑

  當你需要構造從一個位置到另一個位置的路徑的時候,你可以使用relativize()方法。直接上代碼。

Path path01 = Paths.get("BNP.txt");
Path path02 = Paths.get("AEGON.txt"); 

  在這種情況下,可以假設這兩個txt文件在同一層目錄下,這就意味着你你可以從一個文件導航到另一個文件根據目錄的層級。

//output:  ..\AEGON.txt
 Path path01_to_path02 = path01.relativize(path02);
 System.out.println(path01_to_path02);
 
//output:  ..\BNP.txt
 Path path02_to_path01 = path02.relativize(path01);
 System.out.println(path02_to_path01);

  另一種情況是兩個文件不在同一層的目錄中,考慮下面的這個情況:

Path path01 = Paths.get("/tournaments/2009/BNP.txt");
Path path02 = Paths.get("/tournaments/2011");

  這兩個路徑都有一個共同的根元素:/tournaments, 從path01 導航到 path02,你需要向上兩個目錄層級然后再向下一個層級(..\..\2011)。從path02導航到path01,你需要向上一個層級然后向下兩個層級,relativize()方法就是這樣做的。

//output:  ..\..\2011
 Path path01_to_path02 = path01.relativize(path02);
 System.out.println(path01_to_path02);
 
//output:  ..\2009\BNP.txt
 Path path02_to_path01 = path02.relativize(path01);
 System.out.println(path02_to_path01);

  注意,如果只有一個path包含根元素,那么相對路徑是不能構造的,必保證兩個path包含根元素。即使這樣,相對路徑的構造是依賴於系統的。

  -----------------------------------------------------------------------------------------------------------------------------------

  比較兩個路徑

  兩個路徑是否相等可以通過不同的方式和目的去測試。你可以使用 Path.equals()方法,這個方法並不直接訪問文件系統,所以沒有強制要求文件必須存在,

也不會檢查兩個文件是否是同一個文件。在有的系統中,路徑的比較會忽略大小寫,有的則是大小寫敏感的。下面的代碼中表示的是同一個文件,但是並不相等。

Path path01 = Paths.get("/rafaelnadal/tournaments/2009/BNP.txt");
Path path02 = Paths.get("C:/rafaelnadal/tournaments/2009/BNP.txt");
 
if(path01.equals(path02)){
     System.out.println("The paths are equal!");
 } else {
     System.out.println("The paths are not equal!"); //true
 }

  有時候你想檢查兩個路徑是否是同一個目錄和文件,你可以很容易地使用java.nio.File.Files.isSameFile()方法,要注意,要保證路徑是真實存在。

try {
     boolean check = Files.isSameFile(path01, path02);
     if(check){
         System.out.println("The paths locate the same file!"); //true
     } else {
         System.out.println("The paths does not locate the same file!");
     }
 } catch (IOException e) {
     System.out.println(e.getMessage());
 }

   因為Path實現了Comparable接口,所以你可以使用 compareTo()方法對路徑進行比較,根據字典順序進行比較。

//output: 24
 int compare = path01.compareTo(path02);
 System.out.println(compare); 

  還可以進行局部路徑的比較。

boolean sw = path01.startsWith("/rafaelnadal/tournaments");
boolean ew = path01.endsWith("BNP.txt");
System.out.println(sw);  //output:  true
System.out.println(ew);  //output:  true 

  ------------------------------------------------------------------------------------------------------------------------------

  遍歷路徑元素的名稱

  因為Path實現了Iterable接口,所以你可以得到一個對象然后新型循環遍歷一個路徑的信息。請看下面的代碼。

Path path = Paths.get("C:", "rafaelnadal/tournaments/2009", "BNP.txt");
 
for (Path name : path) {
     System.out.println(name);
 }

  輸出結構如下所示:

  rafaelnadal

  tournaments

  2009

  BNP.txt

 

  -----------------------------------------------------------------------------------------------------------------------------

  完。

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM