成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

近2萬(wàn)字詳解Java NIO2文件操作,過(guò)癮!

開(kāi)發(fā) 后端
從classpath中讀取過(guò)文件的人,都知道需要寫(xiě)一些讀取流的方法,很是繁瑣。最近使用IDEA在打出.這個(gè)符號(hào)的時(shí)候,一行代碼讓人激動(dòng)不已:竟然提供直接讀出bytes字節(jié)的方法。

[[318151]]

 從classpath中讀取過(guò)文件的人,都知道需要寫(xiě)一些讀取流的方法,很是繁瑣。最近使用IDEA在打出.這個(gè)符號(hào)的時(shí)候,一行代碼讓人激動(dòng)不已:竟然提供直接讀出bytes字節(jié)的方法。

 

  1. byte[] bytes = Test 
  2.                 .class 
  3.                 .getResourceAsStream("/test.txt"
  4.                 .readAllBytes(); 

這真是太讓人振奮了,再也不用寫(xiě)一些丑陋的,還容易忘記關(guān)閉流的代碼了。

可惜的是,代碼提示給了當(dāng)頭一棒。這需要Java的9版本以上才能支持。這就像一個(gè)還有1年壽命的患者看到救命的藥,還需要兩年才能問(wèn)世的感覺(jué),是一樣的。

 

 

 

 

廢話(huà)少說(shuō),我們用不了這些函數(shù),難道Java7+的也用不了么(有些可憐的寶貝們還真用不了)?話(huà)說(shuō)回來(lái),JAVA7+對(duì)NIO進(jìn)行了增強(qiáng),主要在對(duì)文件操作部分做了大量的改進(jìn)。它體現(xiàn)在,將File操作進(jìn)行分離、封裝、改進(jìn),最終形成Path(Paths)、Files、FileSystem(FileSystems)三個(gè)主要類(lèi)。

我們親切的叫它NIO2。

其中,Paths、Files中提供了大量便捷的靜態(tài)操作方法;NIO2還提供了有關(guān)文件權(quán)限(屬性)操作、軟連接、文件查找等高級(jí)API,使得NIO2具有更全面的文件系統(tǒng)操作接口。

新入行的小鮮肉可能一開(kāi)始就接觸這個(gè)了,但對(duì)我們一些老程序員來(lái)說(shuō),突然看到這些東西,就像打開(kāi)了一個(gè)新大陸。所以本文面向的是還不知道這些個(gè)操作的菜鳥(niǎo),以及懶癌晚期的老Java程序員。

1、Path

文件系統(tǒng)都是Tree或者層級(jí)結(jié)構(gòu)來(lái)組織文件的,任何一個(gè)節(jié)點(diǎn)可以是一個(gè)目錄或者一個(gè)文件,在NIO2中稱(chēng)為Path,這和原來(lái)的File有很多相似之處,只是Path具有更多的表述語(yǔ)義。

1.1、基本屬性

以下代碼展示了它的基本屬性。

  1. Path path = Paths.get("/data/logs/web.log"); 
  2. //屬性 
  3. //獲取路徑中的文件名或者最后一個(gè)節(jié)點(diǎn)元素 
  4. System.out.printf("FileName:%s%n", path.getFileName()); 
  5. //路徑節(jié)點(diǎn)元素的格式 
  6. System.out.printf("NameCount:%s%n", path.getNameCount()); 
  7. //遍歷路徑節(jié)點(diǎn)方法1 
  8. Iterator<Path> names = path.iterator(); 
  9. int i = 0; 
  10. while (names.hasNext()) { 
  11.     Path name = names.next(); 
  12.     System.out.printf("Name %s:%s%n",i,name.toString()); 
  13.     i++; 
  14. //方法2 
  15. for(int j = 0; j < path.getNameCount(); j++) { 
  16.     System.out.printf("Name %s:%s%n",j,path.getName(j)); 
  17. //父路徑 
  18. System.out.printf("Parent:%s%n",path.getParent()); 
  19. //跟路徑,比如"/""C:";如果是相對(duì)路徑,則返回null。System.out.printf("Root:%s%n",path.getRoot()); 
  20. //子路徑,結(jié)果中不包含root,前開(kāi)后閉 
  21. System.out.printf("Subpath[0,2]:%s%n",path.subpath(0,2)); 

結(jié)果:

 

  1. FileName:web.log 
  2. NameCount:3 
  3. Name 0:data 
  4. Name 1:logs 
  5. Name 2:web.log 
  6. Name 0:data 
  7. Name 1:logs 
  8. Name 2:web.log 
  9. Parent:/data/logs 
  10. Root:/ 
  11. Subpath[0,2]:data/logs 

1.2、路徑轉(zhuǎn)換

1)比如“/data/logs/./web.log”、“/data/logs/../db”這種包含“冗余”路徑的,有時(shí)候我們需要轉(zhuǎn)換為正常路徑語(yǔ)句,則使用“Path.normalize()”方法,無(wú)比的清爽清潔。

 

  1. Path path = Paths.get("/data/logs/../web.log"); 
  2. //輸出結(jié)果:/data/web.log 
  3. System.out.printf("%s%n",path.normalize()); 

2)如果文件需要被外部資源訪(fǎng)問(wèn)(resource),你可以通過(guò)Path.toUri()來(lái)轉(zhuǎn)換,path對(duì)應(yīng)的文件或者目錄可以不存在,此方法不會(huì)check異常:

 

  1. Path path = Paths.get("/data/logs/web.log"); 
  2. //表示本地文件的uri,輸出結(jié)果:file:///data/logs/web.log 
  3. System.out.printf("%s%n",path.toUri()); 

3)toAbsolutePath():如果路徑為相對(duì)路徑,則轉(zhuǎn)換為絕對(duì)路徑,對(duì)于JAVA程序而言,起始路徑為classpath。此方法不會(huì)檢測(cè)文件是否真的存在或者有權(quán)限。

4)其中toRealPath()是比較重要的方法,不過(guò)它會(huì)對(duì)文件是否存在、訪(fǎng)問(wèn)權(quán)限進(jìn)行檢測(cè),需要捕獲異常。首先檢測(cè)文件是否存在、是否有權(quán)限;如果path為相對(duì)路徑,則將會(huì)轉(zhuǎn)換為絕對(duì)路徑,同“3)”;如果是“符號(hào)連接”文件(軟連接),則獲取其實(shí)際target路徑(除非指定了NO_FOLLOW_LINKS);如果路徑中包含“冗余”,則移除,同1)。這個(gè)方法,通常用于對(duì)“用戶(hù)輸入的path”進(jìn)行校驗(yàn)和轉(zhuǎn)換,使用比較多。

5)resolve():路徑合并,當(dāng)前path與參數(shù)進(jìn)行路徑合并,append。

6)relativize():獲取相對(duì)路徑,“/data”與“/data/logs/p1”的相對(duì)路徑為“logs/p1”,反之為“../../”。

2、Files

Files類(lèi)中提供了大量靜態(tài)方法,用于實(shí)現(xiàn)文件(目錄)的創(chuàng)建、復(fù)制、遷移、刪除以及訪(fǎng)問(wèn)文件數(shù)據(jù)等操作。

2.1、檢測(cè)文件或目錄

Files.exists(Path)和notExists(Path)兩個(gè)方法,這兩個(gè)方法都會(huì)實(shí)際檢測(cè)文件或者目錄是否存在、以及是否有訪(fǎng)問(wèn)權(quán)限。注意:!exist() 與notExists()并不完全相等,exist可能有三種狀態(tài):如果不存在或者安全校驗(yàn)不通過(guò)則返回false,如果返回true則表示文件確實(shí)存在且有權(quán)限。notExists()檢測(cè)類(lèi)似,對(duì)于沒(méi)有通過(guò)安全校驗(yàn)的也會(huì)返回false;當(dāng)exists與notExists同時(shí)返回false時(shí),說(shuō)明文件不可以驗(yàn)證(即無(wú)權(quán)限),所以通常這兩個(gè)方法需要同時(shí)使用。

判斷文件(目錄)具有讀、寫(xiě)、執(zhí)行的權(quán)限,可以通過(guò)如下方法:

 

  1. Path path = Paths.get("data/logs/web.log"); 
  2. boolean isRegularExecutableFile = Files.isRegularFile(path) & 
  3.         Files.isReadable(path) & Files.isExecutable(path); 

有時(shí)候,兩個(gè)不同的path,會(huì)指向同一個(gè)文件,比如當(dāng)一個(gè)path是軟連接時(shí),此時(shí)可以使用Files.isSameFile(p1,p2)來(lái)檢測(cè),當(dāng)然你可以通過(guò)Path + LinkOption相關(guān)組合獲取target實(shí)際path來(lái)比較。

2.2、刪除

delete和deleteIfExists兩個(gè)方法均可刪除文件,前者嘗試刪除的文件如果不存在則會(huì)拋出異常。如果文件是軟連接,則只刪除連接文件而不會(huì)刪除target文件,如果path為目錄,則目錄需要為空,否則刪除失敗(IOException)。在刪除操作之前,最后做一些常規(guī)的檢測(cè),比如文件是否存在(有權(quán)限)、目錄是否為空等。稍后我們?cè)俳榻B“遞歸刪除目錄樹(shù)和文件”。

2.3、文件(目錄)復(fù)制

copy(Path,Path,CopyOption…)方法可以復(fù)制文件,不過(guò),需要注意CopyOption的相關(guān)選項(xiàng)。

當(dāng)copy一個(gè)軟連接文件時(shí),默認(rèn)將會(huì)復(fù)制target文件,如果只想復(fù)制軟連接文件而不是target內(nèi)容,可以指定NOFOLLOW_LINKS選項(xiàng)。CopyOption的實(shí)現(xiàn)類(lèi)為StandardCopyOption,此外CopyOption也擴(kuò)展了LinkOption,即包含NOFOLLOW_LINKS選項(xiàng)。如下為CopyOption選項(xiàng)列表:

1)REPLACE_EXISTING:如果目標(biāo)文件已經(jīng)存在,則直接覆蓋;如果目標(biāo)文件是個(gè)軟連接,則軟連接文件本身被覆蓋(而非連接文件的target文件);如果復(fù)制的是目錄,且目標(biāo)目錄不為空時(shí),則會(huì)拋出異常(DirectoryNotEmptyException),稍后介紹“遞歸復(fù)制目錄樹(shù)和文件”。此參數(shù)通常必選。復(fù)制目錄時(shí),目標(biāo)目錄會(huì)自動(dòng)創(chuàng)建,源目錄中如果有文件,則不會(huì)復(fù)制文件,只會(huì)創(chuàng)建空的目標(biāo)目錄。source和target,要么同時(shí)是目錄、要么同時(shí)是文件。

2)COPY_ATTRIBUTES:復(fù)制文件時(shí),也同時(shí)復(fù)制目標(biāo)文件的屬性(metadata),對(duì)于文件屬性(FileAttribute)的支持依賴(lài)于文件系統(tǒng)(和平臺(tái)),不過(guò)lastModifiedTime通常會(huì)被復(fù)制。

3)NOFOLLOW_LINKS:繼承自L(fǎng)inkOption,表示如果文件是軟連接,則不followed,即只復(fù)制連接文件,不復(fù)制其target實(shí)際文件內(nèi)容。

4)ATOMIC_MOVE:只支持move操作,copy不支持。

 

  1. Path source = Paths.get("/data/logs/web.log"); 
  2. Path target = Paths.get("/data/logs/web.log.copy"); 
  3. Files.copy(source,target,REPLACE_EXISTING,COPY_ATTRIBUTES,NOFOLLOW_LINKS); 

2.4、移動(dòng)

move(Path,Path,CopyIOption),基本原則同copy。需要注意,如果是目錄,目錄中包含文件時(shí)也可以移動(dòng)的(這可能依賴(lài)于平臺(tái)),子目錄也一起移動(dòng),但是目標(biāo)目錄必須為空(DirectoryNotEmptyException)。基本語(yǔ)義同“mv -rf”,目標(biāo)目錄不需要提前創(chuàng)建,move結(jié)束后,源目錄將不存在。支持兩種選項(xiàng):

1)REPLACE_EXISTING:如果目標(biāo)文件已存在,則覆蓋;如果目標(biāo)文件是軟連接,則連接文件被覆蓋但是其指向不會(huì)受影響。

2)ATOMIC_MOVE:原子復(fù)制,需要平臺(tái)的文件系統(tǒng)支持(不支持則拋出異常),指定此參數(shù)時(shí)其他選項(xiàng)將被忽略;如果文件不能被原子復(fù)制(或者替換),則會(huì)拋出AtomicMoveNotSupportedException。

2.5、打開(kāi)文件

Files類(lèi)中提供了多個(gè)靜態(tài)的方法,用于直接讀寫(xiě)文件。如下為文件打開(kāi)的幾個(gè)選項(xiàng)參數(shù)(StandardOpenOptions):

1)WRITE: 打開(kāi)文件用于write訪(fǎng)問(wèn)。

2)APPEND:在文件尾部追加數(shù)據(jù),伴隨用于WRITE或CREATE選項(xiàng)。

3)TRUNCATE_EXISTING:將文件truncate為空,伴隨用于WRITE選項(xiàng)。比如,文件存在時(shí),將文件數(shù)據(jù)清空并重新寫(xiě)入。

4)CREATE_NEW:創(chuàng)建新文件,如果文件已存在則拋出異常。

5)CREATE:如果文件已存在則直接打開(kāi),否則創(chuàng)建文件。

6)DELETE_ON_CLOSE:當(dāng)文件操作關(guān)閉時(shí)則刪除文件(close方法或者JVM關(guān)閉時(shí)),此選項(xiàng)適用于臨時(shí)文件(臨時(shí)文件不應(yīng)該被其他進(jìn)程并發(fā)訪(fǎng)問(wèn))。

7)SPARSE:創(chuàng)建一個(gè)“稀疏”文件,伴隨使用CREATE_NEW,適用于某些特殊的文件系統(tǒng)比如NTFS,這些大文件允許出現(xiàn)“gaps”(空洞)在某些情況下可以提高性能且這些gaps不消耗磁盤(pán)空間。

8)SYNC:對(duì)文件內(nèi)容(data)或者metadata的修改,都會(huì)同步到底層存儲(chǔ)。

9)DSYNC:對(duì)文件內(nèi)容的修改,會(huì)同步到底層存儲(chǔ)。

對(duì)于一些小文件(M級(jí)別),通常我們希望一次全部讀取所有內(nèi)容,而不再使用傳統(tǒng)的方式迭代讀取。

  1. //全部讀取小文件中的數(shù)據(jù) 
  2. //Files.readAllBytes(Paths.get("/data/web.log")); 
  3. List<String> lines = Files.readAllLines(Paths.get("/data/web.log"),Charset.forName("utf-8")); 
  4.  
  5. //將準(zhǔn)備好的數(shù)據(jù),直接全部寫(xiě)入文件。(打開(kāi)、寫(xiě)入) 
  6. Files.write(Paths.get("/data/web-1.log"),lines,Charset.forName("utf-8"), 
  7.         StandardOpenOption.APPEND, 
  8.         StandardOpenOption.CREATE)); 
  9.  
  10. //傳統(tǒng)操作 
  11. try (BufferedReader reader = Files.newBufferedReader(Paths.get("/data/web.log"))) { 
  12.     while (true) { 
  13.         String line = reader.readLine(); 
  14.         if (line == null) { 
  15.             break; 
  16.         } 
  17.         System.out.println(line); 
  18.     } 
  19. } catch (IOException e) { 
  20.     // 
  21.  
  22. //傳統(tǒng)操作 
  23. try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("/data/web.log"),Charset.forName("utf-8"),StandardOpenOption.APPEND, 
  24.         StandardOpenOption.CREATE)) { 
  25.     for(String line : lines) { 
  26.         writer.write(line); 
  27.     } 
  28. } catch (IOException e) { 
  29.     // 

此外Files中還提供了基于buffer的channel操作,返回類(lèi)型為SeekableByteChannel,這種操作通常適用于讀或者寫(xiě),以及數(shù)據(jù)可以基于buffer進(jìn)行拆封包,其他特性類(lèi)似“隨機(jī)訪(fǎng)問(wèn)文件”。(Files.newByteChannel(),功能同F(xiàn)ile.open())

 

  1. Path path = Paths.get("/data/web.log"); 
  2. //創(chuàng)建一個(gè)普通文件,如果已存在則拋出異常,文件屬性為默認(rèn)。Files.createFile(path); 
  3.  
  4. //創(chuàng)建臨時(shí)文件,臨時(shí)文件的目錄和前綴可以為null,后綴如果為null時(shí)默認(rèn)使用".tmp"
  5. Files.createTempFile(null,null,".tmp"); 
  6. //創(chuàng)建一個(gè)軟連接文件 
  7. Files.createSymbolicLink(Paths.get("/data/link.log"),Paths.get("/data/web.log")); 

2.6、Metadata管理

2.6.1、BasicFileAttributes

BasicFileAttributes基本接口,提供了一些基本的文件metadata,比如lastAccessTime、lastModifiedTime等,它的實(shí)現(xiàn)類(lèi)因平臺(tái)而已有:DosFileAttributes、PosixFileAttribute、UnixFileAttribute等;不同平臺(tái)所能支持的屬性有所不同。(在跨平臺(tái)場(chǎng)景下,你可能需要使用FileStore來(lái)判斷當(dāng)前文件系統(tǒng)是否支持相應(yīng)的FileAttributeView)

 

  1. Path path = Paths.get("/data/logs/web.log"); 
  2. BasicFileAttributes attributes = Files.readAttributes(path,BasicFileAttributes.class); 
  3. System.out.println("regular file:" + attributes.isRegularFile()); 
  4. System.out.println("directory:" + attributes.isDirectory()); 
  5. System.out.println("symbolic link:" + attributes.isSymbolicLink()); 
  6. System.out.println("modified time:" + attributes.lastModifiedTime().toMillis()); 
  7.  
  8. //修改系統(tǒng)更新屬性 
  9. Files.setLastModifiedTime(path,FileTime.fromMillis(System.currentTimeMillis())); 
  10.  
  11. //修改其他屬性 
  12. Files.setAttribute(path,"dos:hidden",true); 

屬性名格式為“view-name:attribute-name”,比如“dos:hidden”;其中合法的view-name目前有“basic”、“posix”、“unix”、“owner”(所有者信息,權(quán)限),屬性的列表需要根據(jù)自己的平臺(tái)對(duì)應(yīng)相應(yīng)的Attributes類(lèi),否則會(huì)導(dǎo)致設(shè)置異常。

2.6.2、PosixFileAttributes

  1. Path path = Paths.get("/data/logs/web.log"); 
  2. PosixFileAttributes attributes = Files.readAttributes(path,PosixFileAttributes.class); 
  3.  
  4. //用戶(hù)組和權(quán)限 
  5. UserPrincipal userPrincipal = attributes.owner(); 
  6. System.out.println(userPrincipal.toString()); 
  7.  
  8. GroupPrincipal groupPrincipal =  attributes.group(); 
  9. System.out.println(groupPrincipal.toString()); 
  10.  
  11. Set<PosixFilePermission> permissions = attributes.permissions(); 
  12. //將權(quán)限轉(zhuǎn)換為文件屬性,用于創(chuàng)建新的文件,目前文件權(quán)限也是一種屬性 
  13. FileAttribute<Set<PosixFilePermission>> fileAttribute = PosixFilePermissions.asFileAttribute(permissions); 
  14.  
  15. Files.createFile(Paths.get("/data/test.log"),fileAttribute); 
  16.  
  17. //修改文件權(quán)限,可以在permissions中增減權(quán)限列表,枚舉 
  18. Files.setPosixFilePermissions(path,permissions); 

從權(quán)限字符串中,構(gòu)建權(quán)限列表

  1. Set<PosixFilePermission> permissions = PosixFilePermissions.fromString("-rw-r--r--"); 
  2. Files.setPosixFilePermissions(path, permissions); 

修改文件(目錄)的所有者或者所在組:

 

  1. Path path = Paths.get("/data/logs/web.log"); 
  2. //首先找到系統(tǒng)中的其他用戶(hù),根據(jù)用戶(hù)名 
  3. UserPrincipal userPrincipal = path.getFileSystem().getUserPrincipalLookupService().lookupPrincipalByName("userName"); 
  4. Files.setOwner(path,userPrincipal); 
  5. //或者 
  6. Files.getFileAttributeView(path,FileOwnerAttributeView.class).setOwner(userPrincipal); 
  7.  
  8. //修改group 
  9. GroupPrincipal groupPrincipal = path.getFileSystem().getUserPrincipalLookupService().lookupPrincipalByGroupName("groupName"); 
  10. Files.getFileAttributeView(path,PosixFileAttributeView.class).setGroup(groupPrincipal); 

2.6.3、UserDefinedFileAttributeView

用戶(hù)自定義文件屬性(即擴(kuò)展文件屬性),以及屬性值的長(zhǎng)度,這取決于底層文件系統(tǒng)或者平臺(tái)是否支持。目前,主流的平臺(tái)和文件系統(tǒng)都支持?jǐn)U展文件屬性,比如FreeBSD(ZFS)、Linux(ext3、ext4、ZFS)、MacOS等。默認(rèn)情況下,此操作是開(kāi)啟的,如果已關(guān)閉,可以通過(guò)“sudo mount -o remount,user_xattr {你的文件系統(tǒng)掛載路徑}”,否則也會(huì)拋出UnsupportedOperationException。

 

  1. Path path = Paths.get("/data/logs/web.log"); 
  2. UserDefinedFileAttributeView view = Files.getFileAttributeView(path,UserDefinedFileAttributeView.class); 
  3. String name = "user.mimetype"
  4. int size = view.size(name);//我個(gè)人認(rèn)為JDK應(yīng)該直接支持獲取屬性值,而不是再周折一番 
  5. ByteBuffer buffer = ByteBuffer.allocate(size); 
  6. view.read(name,buffer); 
  7. buffer.flip(); 
  8. String value = Charset.defaultCharset().decode(buffer).toString(); 
  9. System.out.println(value); 
  10. //其他操作,比如list獲取所有屬性的列表等。//寫(xiě)入或者跟新自定義屬性 
  11. view.write(name,Charset.defaultCharset().encode("text/html")); 

3、FileSystem

FileStore是新增的API,用于描述底層存儲(chǔ)系統(tǒng),一個(gè)平臺(tái)有多個(gè)FileStore,我們可以通過(guò)FileSystem獲取FileStore的列表,以及每個(gè)store的存儲(chǔ)狀態(tài)、文件列表等。

  1. Path path = Paths.get("/data/logs/web.log"); 
  2. path.getFileSystem().getFileStores();//獲取文件所屬的文件系統(tǒng)的所有的存儲(chǔ)器。//當(dāng)前文件系統(tǒng)所能支持的FileAttributeView,此后可以對(duì)文件使用相應(yīng)的view獲取或者修改屬性 
  3. Set<String> viewNames = FileSystems.getDefault().supportedFileAttributeViews(); 
  4. System.out.println(viewNames);//basic,unix,posix,owner,dos等 
  5.  
  6. //或者,全局 
  7. //遍歷所有的磁盤(pán)存儲(chǔ) 
  8. Iterable<FileStore> fileStores = FileSystems.getDefault().getFileStores();//獲取默認(rèn)文件系統(tǒng)的所有存儲(chǔ)器 
  9. for(FileStore store : fileStores) { 
  10.     System.out.println("\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-"); 
  11.     System.out.println("className:" + store.getClass().getName()); 
  12.     System.out.println("name:" + store.name());//磁盤(pán)名稱(chēng) 
  13.     System.out.println("type:" + store.type());//類(lèi)型 
  14.     System.out.println("readOnly:" + store.isReadOnly());//是否為只讀 
  15.     System.out.println("usableSpace:" + store.getUsableSpace() + "/" + store.getTotalSpace()); 
  16.     boolean supported = store.supportsFileAttributeView(BasicFileAttributeView.class); 
  17.     //或者 
  18.     //boolean supported =  store.supportsFileAttributeView("basic"); 
  19.     //fileStore的屬性,不同于FileAttributes,這些屬性應(yīng)該與FileStore的各個(gè)實(shí)現(xiàn)類(lèi)對(duì)應(yīng)。Long totalSpace = (Long)store.getAttribute("totalSpace"); 
  20.     System.out.println(totalSpace); 

可以獲取每個(gè)FileStore支持的FileAttributeView,此后即可通過(guò)Files.getFileAttributeView()來(lái)獲取相應(yīng)的視圖類(lèi)。每個(gè)view都有簡(jiǎn)寫(xiě)名稱(chēng),比如BasicFileAttributeView.name()返回其簡(jiǎn)寫(xiě)名稱(chēng)為“basic”。目前JDK支持很多FileAttributeView,比如BasicFileAttributeView、UnixFileAttributeView等等,以及允許自定義的UserDefinedFileAttributeView等。JDK將獲取文件屬性、修改文件屬性的操作全部基于對(duì)應(yīng)的FileAttributeView類(lèi)來(lái)實(shí)現(xiàn)。

 

  1. PosixFileAttributeView view = Files.getFileAttributeView(path,PosixFileAttributeView.class); 
  2. PosixFileAttributes fileAttributes = view.readAttributes(); 

此外,根據(jù)FileStore的底層存儲(chǔ)不同,有多種實(shí)現(xiàn),可以參看FileStore的實(shí)現(xiàn)類(lèi),比如UnixFileStore、BsfFileStore(Mac)等,每個(gè)FileStore所能支持的attribute也不太相同,需要根據(jù)其對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)獲取,也可以使用FileStore.getAttribute()來(lái)獲取,但是屬性名需要與類(lèi)中支持的屬性名對(duì)應(yīng)。

4、目錄操作

JAVA中目錄也用Path表示,其基本屬性與File一樣。

4.1、列舉根目錄

  1. //遍歷文件系統(tǒng)的所有根目錄 
  2. Iterable<Path> roots = FileSystems.getDefault().getRootDirectories(); 
  3. for(Path root : roots) { 
  4.     System.out.print(root); 

4.2、創(chuàng)建、刪除

 

  1. Path dir = Paths.get("/data/xyz"); 
  2. Files.createDirectories(dir); 
  3. Files.createDirectory(dir); 

其中createDirectory()方法是一個(gè)“嚴(yán)格校驗(yàn)”的方法,如果父路徑不存在則會(huì)拋出異常,如果路徑已經(jīng)存在或者同名文件存在則會(huì)拋出異常,簡(jiǎn)單來(lái)說(shuō)此方法只能創(chuàng)建最后一級(jí)目錄(且此前不存在)。對(duì)于createDirectories()方法,比較兼容,會(huì)逐層校驗(yàn)并創(chuàng)建父路徑,如果不存在則創(chuàng)建。

創(chuàng)建目錄時(shí),也可以像文件那樣,指定文件屬性(包括權(quán)限)

  1. Path dir = Paths.get("/data/xyz/12x/123x"); 
  2. Set<PosixFilePermission> permissions = PosixFilePermissions.fromString("\-rw\-rw\-\-\-\-"); 
  3. FileAttribute<Set<PosixFilePermission>> fileAttribute = PosixFilePermissions.asFileAttribute(permissions); 
  4. Files.createDirectories(dir,fileAttribute); 

4.3、遍歷目錄

  1. Path dir = Paths.get("/data"); 
  2. DirectoryStream<Path> stream = Files.newDirectoryStream(dir); 
  3. for (Path path : stream) { 
  4.     System.out.println(path); 
  5. stream.close(); 

stream方式會(huì)遍歷指定目錄下的所有文件,包括文件。目錄。連接、隱藏文件或者目錄等。

此外,JDK還支持基于filter模式,在遍歷時(shí)過(guò)濾“非必要”的文件或者目錄。

  1. Path dir = Paths.get("/data"); 
  2. DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() { 
  3.     @Override 
  4.     public boolean accept(Path entry) throws IOException { 
  5.         return Files.isRegularFile(entry); 
  6.     } 
  7. }; 
  8. DirectoryStream<Path> stream = Files.newDirectoryStream(dir,filter); 
  9. for (Path path : stream) { 
  10.     System.out.println(path); 
  11. stream.close(); 

4.4、Glob文件過(guò)濾器

NIO2中新增支持了基于Glob的文件過(guò)濾器,一種類(lèi)似于正則表達(dá)式的匹配語(yǔ)法;glob是來(lái)自u(píng)nlix(shell指令)用于文件匹配的表達(dá)式,很多主流語(yǔ)言和平臺(tái)(dos、window)都支持,不過(guò)不同語(yǔ)言對(duì)glob的支持程度不同(需要注意)。

1、*:匹配任意多個(gè)任意字符,包括空字符(none)。比如“/data/*.log”匹配“data”目錄下所有以“.log”結(jié)尾的文件。

2、**:類(lèi)似于*,匹配任意多個(gè)字符,不過(guò)它可以越過(guò)目錄分割符,此語(yǔ)法通常用于匹配全路徑。比如:“/data/**”

3、?:只匹配一個(gè)字符。

4、\:轉(zhuǎn)義符,用于轉(zhuǎn)義特殊字符,比如“\”、“-”、“{”、“}”、“[”等等。比如需要匹配“{”那么其字面表達(dá)式為“\{”,“\\”用于匹配單斜杠。

5、!:非,不包含,通常配合[]使用。(貌似不支持^)

6、{}:指定一組子規(guī)則,比如:

1){sum,moon,stars}:匹配“sun”或者“moon”或者“starts”(其一即可),子規(guī)則使用“,”分割。

2){temp*,tmp*}:匹配以temp或者tmp開(kāi)頭的所有字符串。

7、[]:匹配一組字符串中的單個(gè)字符,如果字符串集中包含“-”則匹配區(qū)間中單個(gè)字符。比如[abc]匹配“a”或者“b”或者“c”,[a-z]匹配a到z小寫(xiě)字符中的一個(gè),[0-9]匹配0~9任意一個(gè)數(shù)字。可以混合使用,比如[abce-g]匹配“a”、“b”、“c”、“e”、“f”、“g”,[!a-c]匹配除a、b、c之外的任意一個(gè)字符。復(fù)合子規(guī)則使用“,”分割,比如[a-z,0-9]匹配a~z或者0~9任意一個(gè)字符。

在[]中,“*”、“?”、“\”只匹配其自己(字面),如果“-”在[]內(nèi)且是第一個(gè)字符或者在!之后,也匹配自己。

8、文件中的前導(dǎo)字符、“.”將作為普通字符對(duì)待。比如“*”可以匹配“.tmp”這個(gè)文件,F(xiàn)Iles.isHidden()可以用來(lái)檢測(cè)此文件為隱藏文件。

9、其他所有字符匹配其自己(取決于因平臺(tái)而已的實(shí)現(xiàn)方式,包括路徑分隔符等)。

示例:

1、*.html匹配任意“.html”結(jié)尾的文件。

2、???:匹配任意三個(gè)字符(包括數(shù)字字符)

3、*[0-9]*:匹配包含一個(gè)數(shù)字的任意多個(gè)字符。

4、*.{htm,html},匹配任意以“html”或者“htm”結(jié)尾的字符串。

GLobbing表達(dá)式,一種比較便捷的過(guò)濾策略,對(duì)于一些簡(jiǎn)單的操作(主要是只根據(jù)文件或者路徑名特性匹配時(shí)),可以不使用Filter的情況下完成,當(dāng)然glob的內(nèi)部實(shí)現(xiàn)仍然是基于封裝的Filter來(lái)實(shí)現(xiàn)(PathMatcher);但是glob語(yǔ)法相對(duì)簡(jiǎn)單,JDK NIO2有關(guān)文件過(guò)濾表達(dá)式,可以同時(shí)支持glob和正則表達(dá)式。稍后介紹如何使用PathMatcher來(lái)遍歷文件或者目錄樹(shù)。

  1. Path dir = Paths.get("/data"); 
  2. //內(nèi)部,默認(rèn)會(huì)對(duì)glob表達(dá)式增加前綴,glob,為了兼容PathMatcher 
  3. DirectoryStream<Path> stream = Files.newDirectoryStream(dir,"\*.txt"); 
  4. for (Path path : stream) { 
  5.     System.out.println(path); 
  6. stream.close(); 

4.5、操作鏈接文件

硬連接(或者連接):

1)文件有相同的 inode 及 data block;

2)只能對(duì)已存在的文件進(jìn)行創(chuàng)建;

3)不能交叉文件系統(tǒng)進(jìn)行硬鏈接的創(chuàng)建;

4)不能對(duì)目錄進(jìn)行創(chuàng)建,只可對(duì)文件創(chuàng)建;

5)刪除一個(gè)硬鏈接文件并不影響其他有相同 inode 號(hào)的文件。

軟連接(符號(hào)連接):軟鏈接與硬鏈接不同,若文件用戶(hù)數(shù)據(jù)塊中存放的內(nèi)容是另一文件的路徑名的指向,則該文件就是軟連接。軟鏈接就是一個(gè)普通文件,只是數(shù)據(jù)塊內(nèi)容有點(diǎn)特殊。軟鏈接有著自己的 inode 號(hào)以及用戶(hù)數(shù)據(jù)塊。因此軟鏈接的創(chuàng)建與使用沒(méi)有類(lèi)似硬鏈接的諸多限制:

1)軟鏈接有自己的文件屬性及權(quán)限等;

2)可對(duì)不存在的文件或目錄創(chuàng)建軟鏈接;

3)軟鏈接可交叉文件系統(tǒng);

4)軟鏈接可對(duì)文件或目錄創(chuàng)建;

5)創(chuàng)建軟鏈接時(shí),鏈接計(jì)數(shù) i_nlink 不會(huì)增加;

6)刪除軟鏈接并不影響被指向的文件,但若被指向的原文件被刪除,則相關(guān)軟連接被稱(chēng)為死鏈接(即 dangling link,若被指向路徑文件被重新創(chuàng)建,死鏈接可恢復(fù)為正常的軟鏈接)。

 

  1. ##創(chuàng)建連接 
  2. ln 目標(biāo) 連接名 
  3. ## 創(chuàng)建軟連接 
  4. ln \-s 目標(biāo) 連接名 
  5.  
  6. ##查看軟連接目標(biāo)指向,對(duì)于硬連接是不顯示。ls \-l 軟連接文件 
  7.  
  8. ##通過(guò)stat指令可以查看軟硬連接的inode和block信息 
  9. ##發(fā)現(xiàn)硬連接與目標(biāo)文件的信息完全一致。##軟連接文件有單獨(dú)的inode和block。 

創(chuàng)建連接

 

  1. Path target = Paths.get("/data/test.log"); 
  2. //target必須存在 
  3. Files.createLink(Paths.get("/data/hard\-link.log"),target); 
  4. Files.createSymbolicLink(Paths.get("/data/soft\-link.log"),target); 
  5.  
  6. //檢測(cè)文件是否為軟連接問(wèn)題 
  7. boolean isSymbolicLink = Files.isSymbolicLink(Paths.get("/data/soft\-link.log")); 
  8.  
  9. Path target2 = Files.readSymbolicLink(Paths.get("/data/soft\-link.log")); 
  10. //檢測(cè)是否為同一個(gè)文件 
  11. System.out.println(Files.isSameFile(target,target2));//true 
  12. System.out.println(Files.isSameFile(target,Paths.get("/data/hard\-link.log")));//true 
  13. System.out.println(Files.isSameFile(target,Paths.get("/data/soft\-link.log")));//true 
  14.  
  15. 通過(guò)Files.isSameFile()比較,我們會(huì)發(fā)現(xiàn),無(wú)論是軟連接、硬鏈接,都與目標(biāo)文件是同一個(gè)文件。 

4.6、查找文件

前文中介紹了有關(guān)PathMatcher,在JAVA NIO2中用于匹配文件的表達(dá)式,可以支持glob和正則表達(dá)式(regex)兩種方式。其中g(shù)lob的語(yǔ)法更接近linux shell,regex是更廣泛、更豐富的一種方式。比如文件:/data/test.log

 

  1. Path path = Paths.get("/data/test.log"); 
  2. PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:\*\*.log"); 
  3.  
  4. System.out.println(pathMatcher.matches(path)); 
  5.  
  6. //基于正則 
  7. pathMatcher = FileSystems.getDefault().getPathMatcher("regex:.\*\\\\.log"); 
  8. System.out.println(pathMatcher.matches(path)); 

表達(dá)式規(guī)則:syntax:pattern,其中合法的syntax為“glob”和“regex”;需要注意這兩種表達(dá)式的區(qū)別。內(nèi)部實(shí)現(xiàn)也比較簡(jiǎn)單,對(duì)于glob字符串將會(huì)轉(zhuǎn)化為正則表達(dá)式字符串,然后統(tǒng)一使用正則匹配。

4.7、遞歸遍歷目錄樹(shù)

曾經(jīng),使用JAVA遍歷文件數(shù)是一件比較繁瑣的事情,在NIO2中增加了原生提供了此操作。主要API為FileVisitor,其簡(jiǎn)單實(shí)現(xiàn)類(lèi)為SimpleFileVisitor:

1、preVisitDirectory:在瀏覽目錄之前。前置操作。比如遍歷并復(fù)制文件時(shí),可以在進(jìn)入目錄之前,創(chuàng)建遷移的目標(biāo)新目錄。

2、postVisitDirectory:在瀏覽目錄中所有文件之后(瀏覽其他目錄之前)。后置操作。

3、visitFile:瀏覽文件,Path和BaseFileAttributes會(huì)傳遞入方法。

4、visitFileFailed:瀏覽文件失敗時(shí)調(diào)用,比如文件屬性無(wú)法獲取、目錄無(wú)法打開(kāi)等異常時(shí),調(diào)用此方法,同時(shí)傳入Path和Exception。

簡(jiǎn)單的遍歷(查找、篩選匹配)

  1. Path dir = Paths.get("/data/redis"); 
  2. Stream<Path> stream = Files.walk(dir); 
  3. stream.forEach(path \-> { 
  4.     System.out.println(path); 
  5. }); 
  6. stream.close(); 

復(fù)雜遍歷(遍歷查找、文件遷移校驗(yàn))

  1. public static void main(String\[\] args) throws Exception{ 
  2.     Path dir = Paths.get("/data/redis"); 
  3.     Files.walkFileTree(dir,new Finder()); 
  4.  
  5. public static class Finder implements FileVisitor<Path> { 
  6.  
  7.     @Override 
  8.     public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { 
  9.         System.out.println("preVisitDirectory:" + dir); 
  10.         return FileVisitResult.CONTINUE
  11.     } 
  12.  
  13.     @Override 
  14.     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 
  15.         System.out.println("visitFile:" + file); 
  16.         return FileVisitResult.CONTINUE
  17.     } 
  18.  
  19.     @Override 
  20.     public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { 
  21.         System.out.println("visitFileFailed:" + file + ",exception:" + (exc != null ? exc.getMessage() : "\-")); 
  22.         return FileVisitResult.CONTINUE
  23.     } 
  24.  
  25.     @Override 
  26.     public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { 
  27.         System.out.println("postVisitDirectory:" + dir); 
  28.         return FileVisitResult.CONTINUE
  29.     } 

FileVisitResult用于表示執(zhí)行狀態(tài):

1)CONTINUE:表示繼續(xù)執(zhí)行(繼續(xù)下一步操作)

2)TERMINATE:終止遞歸遍歷,其他的后續(xù)方法不會(huì)被執(zhí)行,尚未瀏覽的文件也將不會(huì)被訪(fǎng)問(wèn)。

3)SKIP_SUBTREE:跳過(guò)子樹(shù),即當(dāng)前目錄以及其子目錄都將被跳過(guò)。適用在preVisitDirectory(),其他方法返回此值則等效于CONTINUE。

4)SKIP_SIBLINGS:跳過(guò)此文件(或者目錄)的同級(jí)文件或者文件,適用在postVisitDirectory(),如果preVisitDirectory返回此值,則當(dāng)前目錄也會(huì)跳過(guò),且postVisitDirectory()不會(huì)被執(zhí)行。

 

責(zé)任編輯:武曉燕 來(lái)源: 小姐姐味道
相關(guān)推薦

2011-12-15 11:39:25

JavaNIO

2023-10-31 12:58:00

TypeScriptJavaScript

2021-03-16 08:21:29

Spark系統(tǒng)并行

2009-11-30 09:40:23

Java 7 NIO2HTTP Server

2011-03-17 11:08:49

Java SE

2024-08-13 15:07:20

2022-09-06 08:02:40

死鎖順序鎖輪詢(xún)鎖

2020-08-11 07:34:29

Java溢出事故

2009-12-14 10:44:51

Java 7NIO2

2024-08-30 10:29:21

2024-12-31 00:00:01

驅(qū)動(dòng)設(shè)計(jì)應(yīng)用場(chǎng)景業(yè)務(wù)邏輯

2024-09-26 13:33:12

2015-07-22 16:01:31

2020-07-01 08:10:34

JVM 內(nèi)存

2021-03-18 10:04:46

數(shù)據(jù)倉(cāng)庫(kù)體系

2024-05-10 12:59:58

PyTorch人工智能

2011-05-19 14:29:49

DB2導(dǎo)入導(dǎo)出

2023-10-26 00:37:40

滴滴彈性云公有云

2022-07-11 10:08:34

大數(shù)據(jù)平臺(tái)機(jī)房

2023-02-16 18:22:44

ChatGPTWolfram語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 精品成人| 91视频免费视频 | 日本又色又爽又黄又高潮 | 免费国产成人av | 日日综合 | 久草综合在线 | 啪啪毛片 | 99成人| 成人欧美在线 | 久久99精品久久久久久 | 国产99久久久国产精品 | 国产一区二区在线播放 | 久久久久久久一区 | 国产视频福利一区 | 国产成人免费一区二区60岁 | 日韩久久成人 | japan21xxxxhd美女| 在线成人 | 一区二区三区 在线 | 久久视频免费看 | 日韩欧美精品一区 | 中文字幕免费在线 | 日韩精品在线一区 | 国产精品久久久久久久久久免费 | 日韩无 | 国产亚洲成av人片在线观看桃 | 天天操天天射天天舔 | 国产一区二区日韩 | 欧美片网站免费 | 国产精品视频一二三区 | 国产丝袜一区二区三区免费视频 | www.一级毛片 | 少妇黄色 | 99在线免费观看视频 | 亚洲欧美一区二区三区在线 | 操人网| 久久久久国产一区二区三区四区 | 在线婷婷 | 国产精品久久av | 欧美区日韩区 | 久久精品国产久精国产 |