The Java NIO Path interface and the Files class work with instances of files

  • 2020-11-26 18:46:33
  • OfStack

Path interface

1. Path refers to a sequence of directory names, which can be followed by a file name. When the first part of the path is the root part, it is the absolute path, such as/or C:\, and the accessible root part depends on the file system;

2. The path starting with the root part is an absolute path; otherwise, it is a relative path;

. 3, static Paths get method takes one or more string, the string between automatically use the default file system path separator connected (Unix is /, Windows \), which solved the problem of the cross-platform, then parse connected as a result, if not legal path is thrown InvalidPathException exception, otherwise it returns a Path object;


// Hypothesis is Unix File system 
 Path absolute = Paths.get("/home", "cat"); // An absolute path 
 
 Path relative = Pahts.get("ixenos", "config", "user.properties"); // Relative paths 

4. Get Path object from String path

get can also get 1 whole path (that is, a single string of parts), such as reading a path from a configuration file:


String baseDir = properties.getProperty("base.dir");
 // May gain  /opt/ixenos  or  C:\Program Files\ixenos
 Path basePath = Paths.get(baseDir);

5. Combine or parse paths

1) Calling ES29en. resolve(q) returns 1 Path as follows: If q is absolute, return q; otherwise, append path returns p/q or p\q


Path workRelative = Paths.get("work");
Path workPath = basePath.resolve(workRelative);
 
//resolve String parameters can also be accepted 
Path workPath = basePath.resolve("work");

2) Calling ES42en.resolveSibling ("q") resolves the parent path o of the specified path p and produces the sibling path o/q


 Path tempPath = workPath.resolveSibling("temp");
 /*
  if workPath is  /opt/ixenos/work
  So that will create  /opt/ixenos/temp 
 */

3) Call p. relativize(r) will generate a redundant path q, parse q will generate a relative path r, and finally r does not contain the intersection path with p


/*
 pathA for  /home/misty
 pathB for  /home/ixenos/config 

  now pathA right pathB When you do relativization, you create redundant paths 
*/
Path pathC = pathA.relativize(pathB); // At this time pathC for  ../ixenos/config

/*
 normalize Method removes redundant parts 
*/
Path pathD = pathC.normalize(); //pathD for  /ixenos/config

4) toAbsolutePath will generate the absolute path of the given path, starting from the root part

5) The Path class also has a number of useful ways to break and combine paths, such as getParent, getFileName, getRoot// to get the root directory

6) Path has an toFile method for dealing with legacy File class, and File class has an toPath method

Files tools

1. Read and write files

Method signature:

static path write(Path path, byte[] bytes, OpenOption... options)

static path write(Path path, Iterable < ? extends CharSequence > lines, OpenOption... options)

Here is a list of the methods used below, see the API documentation for more...

OpenOption is an nio interface, and StandardOpenOption is its enum implementation class. Please check the API documentation for each enum instance function


/*
 Files The simple method provided is suitable for processing medium-length text files 

  If the file you are processing is of a larger length, or 2 Base files, you should still use the classic IO flow 
 
*/

// Read in all contents of the file byte In the array 
byte[] bytes = Files.readAllBytes(path); // The incoming Path object 

// You can then build strings based on the character set 
String content = new String(bytes, charset);

// It can also be read directly as a sequence of rows 
List<String> lines = Files.readAllLines(path, charset);

// Instead, you could write it 1 String to a file. Default is overwrite 
Files.write(path, content.getBytes(charset)); // The incoming byte[]

// Append content, append according to parameters and other functions 
Files.write(path, content.getBytes(charset), StandardOpenOption.APPEND); // Pass in the enumeration object and turn on the append switch 

// will 1 A line String A collection of List Write to a file 
Files.write(path, lines);

2. Copy, cut and delete

Method signature:

static path copy(Path source, Path target, CopyOption... options)

static path move(Path source, Path target, CopyOption... options)

static void delete(Path path) // If path does not have a file, an exception will be thrown. It is better to call the following

static boolean deleteIfExists(Path path)

Here is a list of the methods used below, see the API documentation for more...

CopyOption is an nio interface, and StandardCopyOption is its enum implementation class. Please check the API documentation for each enum instance function

One of these, ATOMIC_MOVE, can be filled in to ensure atomicity, either by successfully moving the file or by keeping the source file in place


// copy 
Files.copy(fromPath, toPath);

// shear 
Files.move(fromPath, toPath);

/*
  If the above toPath Exists, then the operation fails, 
  To override, pass in parameters REPLACE_EXISTING
  Also copy the file properties, pass in COPY_ATTRIBUTES
*/
Files.copy(fromPath, toPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);

Create files and directories


// Create a new directory, except at the end 1 Components, others must already exist 
Files.createDirectory(path); 

// Creates an intermediate directory in the path to create an intermediate widget that does not exist 
Files.createDirectories(path);

/*
  create 1 An empty file, checks that the file exists, and throws an exception if it does 
  Checking for file existence is atomic, so file creation cannot be performed during this process 
*/
Files.createFile(path);

// Before adding / The suffix creates temporary files or temporary directories 
Path newPath = Files.createTempFile(dir, prefix, suffix);
Path newPath = Files.createTempDirectory(dir, prefix);

4. Obtain file information

Skip the API document, or corejava page51

5. Iterate over the files in the directory

The old File class had two methods to get an array of strings made up of all the files in the directory, String[] list() and String[] list(FileFilter filter), but these methods performed very poorly when the directory contained a large number of files.

Reason analysis:


1 , //File class list All the files 
 public String[] list() {
  SecurityManager security = System.getSecurityManager(); // File system permission access 
  if (security != null) {
   security.checkRead(path);
  }
  if (isInvalid()) {
   return null;
  }
  return fs.list(this); // The underlying call FileSystem the list
 }

 //FileSystem The abstract class list
 //File Classes are defined in the fs Is made up of DefaultFileSystem Statically generated 
private static final FileSystem fs = DefaultFileSystem.getFileSystem();

// So let's see 1 Under the DefaultFileSystem Class, discovery is generated 1 a WinNtFileSystem object 
class DefaultFileSystem {

 /**
  * Return the FileSystem object for Windows platform.
  */
 public static FileSystem getFileSystem() {
  return new WinNTFileSystem();
 }
}


// while WinNtFileSystem Class inherited from FileSystem Abstract class, here we mainly look at its list(File file) methods 
 @Override
public native String[] list(File f);
/* We can see that this is a native Method, description list The operation is controlled by the operating system's file system, and the performance of this method can be very poor when the directory contains a large number of files. 
 So instead of saying, NIO the Files The class design newDirectoryStream(Path dir) And its overloaded methods, will generate Iterable Object (available foreach Iteration) *///~


 2 , // The callback filter 
 public String[] list(FilenameFilter filter) { // Interface callbacks are used 
  String names[] = list(); // call list all 
  if ((names == null) || (filter == null)) {
   return names;
  }
  List<String> v = new ArrayList<>();
  for (int i = 0 ; i < names.length ; i++) {
   if (filter.accept(this, names[i])) { // The callback FilenameFileter The object's accept methods 
    v.add(names[i]);
   }
  }
  return v.toArray(new String[v.size()]);
 }

This is where the high tech comes in -- Files gets an iterable directory stream,

Pass in 1 directory Path, walk through descendant directory return 1 directory Path Stream, note that all Path involved here are directories and not files!

Therefore, the Files class designed newDirectoryStream(Path dir) and its overloaded methods to generate Iterable objects (foreach iterations are available)

Traverse the directory to obtain an iteratable descendant file set

CODE_TAG_REPLACE_MARK_0 CODE_TAG_REPLACE_MARK_1
Opens a directory, returning a CODE_TAG_REPLACE_MARK_2 to iterate over all entries in the directory.
CODE_TAG_REPLACE_MARK_0 CODE_TAG_REPLACE_MARK_4
Opens a directory, returning a CODE_TAG_REPLACE_MARK_2 to iterate over the entries in the directory.
CODE_TAG_REPLACE_MARK_0 CODE_TAG_REPLACE_MARK_7

Returns a directory stream, which can be viewed as a collection of Iterable implementations that holds all of Path,

Therefore, we can use iterator or foreach iteration, but we should be careful not to use invoke and another Iterator:

While DirectoryStream extends Iterable, it is not a general-purpose Iterable as it supports only a single Iterator; invoking the iterator method to obtain a second or subsequent iterator throws IllegalStateException.

Example:


try(DirectoryStream<Path> entries = Files.newDirectoryStream(dir))
{
 for(Path entry : entries)
 {
   ...
 }
}

You can pass in the glob parameter, that is, using glob mode to filter files (instead of list(FileFilter filter)) :

newDirectoryStream(Path dir, String glob) note the String type


String baseDir = properties.getProperty("base.dir");
 // May gain  /opt/ixenos  or  C:\Program Files\ixenos
 Path basePath = Paths.get(baseDir);
0

glob mode

The so-called glob pattern refers to the simplified regular expression used by shell.

1. Asterisk * matches 0 or more characters in the path component; For example, *.java matches all Java files in the current directory

2. Two asterisks ** match 0 or more characters across directory boundaries; For example, **.java matches Java files in all subdirectories

3. Question mark (?) Matches only 1 character; For example the & # 63; The & # 63; The & # 63; The & # 63; .java matches Java files of all 4 characters, excluding extensions; Using the & # 63; Because * is a wildcard and does not specify a number

4. [...]. To match a set of characters, you can use the line [0-9] and the inverse character [!0-9]; For example, Test[0-9ES238en-ES239en].java matches ES241en.ES242en. Suppose x is one decimal number, [0-9ES244en-ES245en] matches a single character number in decimal, such as B (decimal 106 is case-insensitive).

If a short underscore is used in square brackets to separate two characters, it means that anything within those two characters can match (for example, [0-9] means matching all Numbers from 0 to 9).

5. {... } matches one of multiple options separated by commas; For example *.{java,class} matches all Java files and class class files

6.\ Escape characters in any of the above modes; For example, *\* matches all files in subdirectories whose filenames contain *, here escaped with **, followed by 0 or more characters matched

The following is the Glob pattern summarized by netizens:

Glob模式 描述
*.txt 匹配所有扩展名为.txt的文件
*.{html,htm} 匹配所有扩展名为.html或.htm的文件。{ }用于组模式,它使用逗号分隔
?.txt 匹配任何单个字符做文件名且扩展名为.txt的文件
. 匹配所有含扩展名的文件
C:\Users\* 匹配所有在C盘Users目录下的文件。反斜线“\”用于对紧跟的字符进行转义
/home/** UNIX平台上匹配所有/home目录及子目录下的文件。**用于匹配当前目录及其所有子目录
[xyz].txt 匹配所有单个字符作为文件名,且单个字符只含“x”或“y”或“z”3种之1,且扩展名为.txt的文件。方括号[]用于指定1个集合
[a-c].txt 匹配所有单个字符作为文件名,且单个字符只含“a”或“b”或“c”3种之1,且扩展名为.txt的文件。减号“-”用于指定1个范围,且只能用在方括号[]内
[!a].txt 匹配所有单个字符作为文件名,且单个字符不能包含字母“a”,且扩展名为.txt的文件。叹号“!”用于否定

Isn't iterating through the set of all the descendants of a directory nice enough? Let's go through all the descendants of a directory (including directories and files) directly.

We can call the walkFileTree method of the Files class and pass in an object of the FileVisitor interface type (there are more methods in API for you to find...).


String baseDir = properties.getProperty("base.dir");
 // May gain  /opt/ixenos  or  C:\Program Files\ixenos
 Path basePath = Paths.get(baseDir);
1

So let's summarize 1,

Files.newDirectoryStream(Path dir) returns 1 iterable descendant file set after traversal;

Files.walkFileTree(Path dir, FileVisitor fv) is a process of traversing the descendant directories and files;

ZIP file system

As you know above, the Paths class looks for a path in the default file system, which is a file on the user's local disk.

In fact, we can have other file systems, such as the ZIP file system.


String baseDir = properties.getProperty("base.dir");
 // May gain  /opt/ixenos  or  C:\Program Files\ixenos
 Path basePath = Paths.get(baseDir);
2

The above code creates an ES300en-based file system that contains all the files in the ZIP document.

1) If you know the file name (String type), it is easy to copy the file from the ZIP document:


Files.copy(fs.getPath(fileName), targetPath);


Q: ES310en.getPath USES the ZIP file system for getPath. Can the default file system be called?

A: can. The FileSystem class has a static getDefault() method that returns a default file system object, which can also be named getPath.

Specific getPath(String name) is traversal or random access, free to see the source code implementation.

2) To list all the files in the ZIP document, you can also traverse the file tree with walkFileTree


String baseDir = properties.getProperty("base.dir");
 // May gain  /opt/ixenos  or  C:\Program Files\ixenos
 Path basePath = Paths.get(baseDir);
4

Related articles: