Java NIO Files類提供了一系列方法來操作檔案系統中的檔案。這個Java NIO Files教程將會包含大部分常用的方法。Files類包含許多的方法,所以如果你需要的方法沒有在這裡描述,也需要檢視JavaDoc。
java.nio.file.Files類跟java.nio.Paths例項一起工作。所以在與Files一起工作時你需要了解Path類。
Files.exists()方法
Files.exists()方法會檢查一個給定的Path是否在檔案系統中存在。
也可以建立在檔案系統中不存在的Path例項。例如,如果你想要建立一個新的目錄,你先會建立相應的Path例項,然後建立目錄。
由於Path例項可能在檔案系統中並不存在,你可以使用Files.exists()方法來檢查。
下面是Files.exists()方法的例子:
Path path = Paths.get("data/logging.properties");
boolean pathExists =
Files.exists(path,
new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});
複製程式碼
這個例子首先建立了一個我們需要檢查檔案是否存在的Path例項。然後,這個例子呼叫了Files.exists()方法並將Path例項作為第一個引數。
注意到Files.exists()方法的第二個引數,這個引數是選項陣列來供方法Files.exist()來判斷檔案是否存。在以上的例子中,這個陣列包含了LinkOption.NOFOLLOW_LINKS,這說明這Files.exists()方法不應該檢查符號連線來判斷檔案是否存在。
Files.createDirectory()
Files.createSirectory方法通過Path例項來建立一個新的目錄。下面是Java的Files.createDirecotry()的例子。
Path path = Paths.get("data/subdir");
try {
Path newDir = Files.createDirectory(path);
} catch(FileAlreadyExistsException e){
// the directory already exists.
} catch (IOException e) {
//something else went wrong
e.printStackTrace();
}
複製程式碼
第一行建立了一個Path例項來代表需要建立的目錄。在try-catch塊的內部呼叫了Files.createDirectory()方法,並將path作為第一個引數。如果目錄建立成功,會返回一個指向新建立目錄的Path例項。
如果目錄已經存在,會丟擲java.nio.FileAlreadyExistsException異常。如果出現其他情況,會出現IO異常。
Files.copy()
Files.copy()方法用於將檔案複製到另一個檔案。下面是Java NIO的Files.copy()的例子:
Path sourcePath = Paths.get("data/logging.properties");
Path destinationPath = Paths.get("data/logging-copy.properties");
try {
Files.copy(sourcePath, destinationPath);
} catch(FileAlreadyExistsException e) {
//destination file already exists
} catch (IOException e) {
//something else went wrong
e.printStackTrace();
}
複製程式碼
首先這個例子建立了一個源Path和目標Path。然後,這個例子呼叫了Files.copy()方法,並將兩個path例項作為引數。這會將源Path中指定的檔案複製到目標path中。
如果目標檔案已經存在,將會丟擲java.nio.file.FileAlreadyExistsException異常。如果出現其它異常,會丟擲IOException。例如,如果目錄檔案的目錄不存在,就會丟擲IOException。
覆蓋存在檔案
也可以實現在檔案複製時覆蓋已經存在的檔案。下面是一個如何使用Files.copy()方法的一個例子。
Path sourcePath = Paths.get("data/logging.properties");
Path destinationPath = Paths.get("data/logging-copy.properties");
try {
Files.copy(sourcePath, destinationPath,
StandardCopyOption.REPLACE_EXISTING);
} catch(FileAlreadyExistsException e) {
//destination file already exists
} catch (IOException e) {
//something else went wrong
e.printStackTrace();
}
複製程式碼
注意到Files.copy()方法的第三個引數。這個參數列明複製時覆蓋已經存在的檔案。
File.move()方法
Java NIO Files類包含了從一個路徑移動到另一個路徑的方法。移動檔案與重新命名檔案是一致的。移動檔案除了能夠移動檔案之外還能重新命名檔案。是的,在java.io.File中可以通過renameTo()方法來實現,但是現在在java.nio.file.Files也可以實現這個功能。
下面是Files.move()的例子:
Path sourcePath = Paths.get("data/logging-copy.properties");
Path destinationPath = Paths.get("data/subdir/logging-moved.properties");
try {
Files.move(sourcePath, destinationPath,
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
//moving file failed.
e.printStackTrace();
}
複製程式碼
首先源路徑和目標路徑會被建立。源路徑指定的是需要移動的檔案,目標路徑指定的是原始檔需要被移動到的位置。然後呼叫了Files.move()方法。結果是檔案被移動了。
注意到Files.move()方法的第三個引數,這個引數告訴Files.move()方法如果目標檔案存在,則覆蓋。這個引數事實上是可選的。
Files.move()方法可能會丟擲一個IO異常如果移動檔案時出現異常。例如,如果一個檔案已經在目標路徑上存在,但沒有指定StandardCopyOPtion.REPLACE_EXISTING或者原始檔不存在等其它情況。
Files.delete()
Files.delete()方法可以刪除一個檔案或目錄。下面是一個Files.delete()的例子:
Path path = Paths.get("data/subdir/logging-moved.properties");
try {
Files.delete(path);
} catch (IOException e) {
//deleting file failed
e.printStackTrace();
}
複製程式碼
首先建立了需要刪除檔案的Path例項。然後,呼叫Files.delete()方法。如果刪除檔案失敗或其它原因,會丟擲IOEXception。
Files.walkFileTree()
Files.walkFileTree()用來遞迴遍歷目錄。walkFileTree方法需要一個Path引數和一個FileVisitor引數。Path引數指向需要遍歷的目錄,FileVisitor是在遍歷時需要呼叫的。
在我解析遍歷器工作原理之前,我們先來看一下FileVisitor介面:
public interface FileVisitor {
public FileVisitResult preVisitDirectory(
Path dir, BasicFileAttributes attrs) throws IOException;
public FileVisitResult visitFile(
Path file, BasicFileAttributes attrs) throws IOException;
public FileVisitResult visitFileFailed(
Path file, IOException exc) throws IOException;
public FileVisitResult postVisitDirectory(
Path dir, IOException exc) throws IOException {
}
複製程式碼
FileVisitor介面必須自己實現,並傳遞一個具體的例項給walkFileTree方法。在訪問目錄期間,每個FileVisitor的實現會在不同的時候被呼叫。需要你不想要實現FileVsitor的全部方法,可以繼承SimpleFileVisitor類,它包含了FileVisitor的預設實現。
下面是walkFileTree()的例子:
Files.walkFileTree(path, new FileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
System.out.println("pre visit dir:" + dir);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("visit file: " + file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
System.out.println("visit file failed: " + file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
System.out.println("post visit directory: " + dir);
return FileVisitResult.CONTINUE;
}
});
複製程式碼
FileVisitor的不同方法會在遍歷的不同的時候被呼叫:
preVisitDirectory方法會在訪問任何目錄前被呼叫。postVisitDirectory方法會在訪問目錄之後被呼叫。
visitFile方法會在每次訪問檔案時被呼叫。它不是在訪問目錄時被呼叫,而是在訪問檔案時被呼叫。visitFileFailed方法會在訪問檔案失敗時被呼叫。例如,沒有許可權訪問檔案或其他情況。
這四個方法的每個方法都返回了一個FileVisitResult列舉例項。FileVisitResult列舉包含以下幾個選項:
- CONTINUE
- TERMINATE
- SKIP_SIBLINGS
- SKIP_SUBTREE
通過返回這些值呼叫者可以確定後續需要怎麼做。
CONTINUE 意味著檔案遍歷按正常繼續。
TERMINATE 表示檔案遍歷應該結束。
SKIP_SIBLINGS 表示遍歷應該繼續,但不繼續訪問相鄰的檔案或目錄。
SKIP_SUBTREE 表示檔案遍歷應該繼續,但不訪問子目錄。這個值只會在preVisitDirectory中返回,如果在其它函式中返回,會被解析成CONTINUE。
查詢檔案
下面是一個繼承SimpleFileVisitor來查詢README.txt檔案的walkFileTree()方法的使用例子:
Path rootPath = Paths.get("data");
String fileToFind = File.separator + "README.txt";
try {
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String fileString = file.toAbsolutePath().toString();
//System.out.println("pathString = " + fileString);
if(fileString.endsWith(fileToFind)){
System.out.println("file found at path: " + file.toAbsolutePath());
return FileVisitResult.TERMINATE;
}
return FileVisitResult.CONTINUE;
}
});
} catch(IOException e){
e.printStackTrace();
}
複製程式碼
遞迴刪除目錄
Files.walkFileTree()方法也可以用來刪除指定目錄下的檔案和子目錄。Files.delete()方法僅會刪除一個空目錄。通過遍歷所有的目錄並刪除每個目錄下的檔案,然後刪除目錄自己。下面是一個遞迴刪除目錄的例子:
Path rootPath = Paths.get("data/to-delete");
try {
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("delete file: " + file.toString());
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
System.out.println("delete dir: " + dir.toString());
return FileVisitResult.CONTINUE;
}
});
} catch(IOException e){
e.printStackTrace();
}
複製程式碼
Files類中的其他方法
java.nio.file.Files類下包含其他的許多方法,如建立符號連結,檢測檔案的大小,設定檔案許可權等等。請從java.nio.file.Files的JavaDoc檢視這些方法的明細。