Java 7 includes automatic resource closing, Switch String implementation, try-catch, and binary writing. For details, see the original article (a list of Java 7 syntax features). The only thing missing in that article is the update to IO operations in Java 7, which happens to be a very important part of it.

After reading this article, you will learn:

  1. Abstract file path operation mode, intuitive and convenient BUG less.
  2. Efficient file operation, write read copy file only one line.
  3. Quick access to file properties under different systems.
  4. A variety of ways to traverse files and directories under a directory, and very efficient.
  5. Reactive event notification, monitoring file changes.

In Java 7, enhancements to file manipulation are included in the new java.nio.file package, which provides features such as file path abstraction, file directory flow, directory tree, file properties, and change monitoring services that can dramatically improve how we manipulate files.

The file path

Before Java 7, all operations on file paths were string operations, and you needed to throw a string directly into them. Using strings directly was inefficient. For example, if you wanted to concatenate parent paths and subdirectories, you could only concatenate strings. And concatenating itself loses its meaning as a file path. In addition, the use of strings for various path operations can cause various problems due to spelling errors.

Java 7 made all that different when it provided the Path interface to represent the abstraction of a Path, and then provided a set of operations on the Path that made everything so much easier.

To make it easy to create Path objects, the Paths utility class is provided as a sneak peek at how to use it.

Get (“/Users/darcy/ Java /”); Get a Path object to start.

Path path = Paths.get("/Users/darcy/java/");
System.out.println("Full path:" + path.toString());

Path pathParent = path.getParent();
System.out.println("Parent path:" + pathParent.toString());

Path pathRoot = path.getRoot();
System.out.println("Root directory:" + pathRoot.toString());

int pathNameCount = path.getNameCount();
System.out.println("Directory depth:" + pathNameCount);

Path pathIndex3 = path.getName(2);
System.out.println("Level 3 Catalogue:" + pathIndex3);

Path subPath = path.subpath(1.3);
System.out.println("Level 1 directory to level 3 directory (package left not package right) :" + subPath.toString());

ResolveSibling splashes directories from the parent directory of the current directory
Path pathResolveSibling = path.resolveSibling("PathDemo.java");
System.out.println("Parent directory start concatenation parameter:" + pathResolveSibling.toString());

// resolve uses the current path as the parent path and the parameter as a subdirectory or file
Path pathResolve = Paths.get("/Users/darcy/java/").resolve("PathDem.java");
System.out.println("Current directory spliced directory:" + pathResolve.toString());

// The relative path of the parameter path to the main path
Path path1 = Paths.get("/Users/darcy/");
Path path2 = Paths.get("/Users/darcy/java/PathDemo.java");
Path path3 = path1.relativize(path2);
System.out.println("Relative path:" + path3.toString());

/* Complete path: /Users/darcy/ Java parent path: /Users/darcy Root directory: / directory depth: 3 Level 3 directory: Java level 1 directory to level 3 directory (package left not package right) : darcy/ Java parent directory Start spliceover parameters: / Users/darcy/PathDemo. Java after mosaics of the current directory directory: / Users/darcy/Java/PathDem. Java relative path: Java/PathDemo. Java * /
Copy the code

As you can see in the above code, except for creating the Path object and entering the Path once, all the subsequent operations are performed using the Path method. Before that, you may need to cut and concatenate various strings, which is quite tedious.

File operations

Remember when you first learned Java IO, there are many ways to write file copy, but no matter which way, it requires a lot of code to write, and also need to consider the performance of the copy. Reading files, not to mention defining various read and receive variables, various validations. Not only is it easy to manipulate files, but common operations like copying and reading files can be done in one line.

Using overly simple, direct code.

// If the file does not exist, create a file
Path path = Paths.get("test.txt");
Path pathBackup = Paths.get("test_bak.txt");
Path pathLink = Paths.get("test.txt.link");
Path pathDir = Paths.get("dir");

// If it already exists, delete it
Files.deleteIfExists(path);
Files.deleteIfExists(pathBackup);
Files.deleteIfExists(pathLink);
Files.deleteIfExists(pathDir);

// Create a file to write to
Path file = Files.createFile(path);
Files.write(path, "Follow public account: Unread code".getBytes());
Files.write(path, System.lineSeparator().getBytes(), StandardOpenOption.APPEND);
Files.write(path, Welcome to add me on wechat: WN8398.getBytes(), StandardOpenOption.APPEND);
System.out.println("Create file:" + file.toString());

// Create a file link
pathLink = Files.createLink(pathLink, path);
System.out.println("Create file:" + pathLink.toString());

// Create directory
Path directory = Files.createDirectory(pathDir);
System.out.println("Create directory:" + directory.toString());

// Copy files
Files.copy(path, pathBackup);
System.out.println("Copy file:" + path + "-- >" + pathBackup);

// Read the file
List<String> lines = Files.readAllLines(pathBackup);
for (String line : lines) {
    System.out.println("File read:" + line);
}
Copy the code

Above shows how Files create, delete, write, copy, and read Files with only one line of code.

File attributes

Like path manipulation, Java 7 provides abstraction of file properties, adding a set of utility classes for manipulating file properties. This code is in the java.nio.file.attribute package. It abstracts an AttributeView as the parent interface for all attributeviews, then subclasses Fi leAttributeView to represent the file view, and subclasses FileOwnerAttributeView to represent the FileOwnerAttributeView. The former attributes include information about the creation time, modification time, and directory of the file, while the latter contains information about the file. Java 7 also provides different implementations for compatibility with different operating systems, such as the DosFileAttributeView view, which is clearly intended for Windows operating systems.

Too simple to use, direct code to serve.

Path path = Paths.get("/Users/darcy/git/jdk-feature/README.md");
BasicFileAttributeView fileAttributeView = Files.getFileAttributeView(path, BasicFileAttributeView.class);
BasicFileAttributes basicFileAttributes = fileAttributeView.readAttributes();
FileTime creationTime = basicFileAttributes.creationTime();
FileTime lastModifiedTime = basicFileAttributes.lastModifiedTime();
FileTime lastAccessTime = basicFileAttributes.lastAccessTime();
System.out.println("Created at:" + creationTime);
System.out.println("Last modified:" + lastModifiedTime);
System.out.println("Last visited:" + lastAccessTime);

boolean directory = basicFileAttributes.isDirectory();
boolean regularFile = basicFileAttributes.isRegularFile();
boolean symbolicLink = basicFileAttributes.isSymbolicLink();
System.out.println("Whether directory:" + directory);
System.out.println("Ordinary file or not:" + regularFile);
System.out.println("Whether symbolic link:" + symbolicLink);

long size = basicFileAttributes.size();
System.out.println("File size:" + size);

PosixFileAttributeView linuxFileAttributeView = Files.getFileAttributeView(path, PosixFileAttributeView.class);
UserPrincipal owner = linuxFileAttributeView.getOwner();
System.out.println("File owner :" + owner.getName());
Copy the code

The sample code runs with the following output.

2020-09-06T13:35:14.649261371z 2020-09-06T13:35:14.680968254z Directory: false Common file: True Whether symbolic link: false File size: 3636 Owning user: DarcyCopy the code

File list stream

To traverse File directories and files before Java 7, you should select the listFiles method of the File class.

// Files are traversed directly without traversing subdirectories
String pathString = "/Users/darcy/project/mylab/src/main/java/com/wdbyte/java";
File file = new File(pathString);
File[] listFiles = file.listFiles();
for (File tempFile : listFiles) {
    System.out.println("file list: " + tempFile.getAbsolutePath());
}
Copy the code

This traversal may seem elegant, but it can be inefficient when faced with a large number of files. So Java 7 has improved on this with the introduction of the DirectoryStream file list stream. It can perform progressive file traversals, reading a certain number of files at a time, reducing the performance overhead of traversals, but DirectoryStream traversals only its direct directories and files, not its subdirectories recursively. Here’s how it’s written.

String pathString = "/Users/darcy/project/mylab/src/main/java/com/wdbyte/java";
// Path Traversal mode without traversing subdirectories
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(pathString))) {
    for (Path pathTemp : directoryStream) {
        System.out.println("DirectoryStream: "+ pathTemp); }}// Path direct traversal - filter.class files
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(pathString), "*.java")) {
    for (Path pathTemp : directoryStream) {
        System.out.println("DirectoryStream file type is class : "+ pathTemp); }}Copy the code

As an extension, Java 8 has enhanced the Files class, introducing Java 8 Lambda expressions, adding the walk method, and traversing Files in similar ways (Lambda expressions are used in the following examples).

// Iterate through all directories and subdirectories
Stream<Path> pathStream = Files.walk(Paths.get("/Users/darcy/project/mylab/src/main/java/com/wdbyte"));
pathStream.forEach(pathTemp -> {
    System.out.println("Stream: " + pathTemp.toString());
});

// Iterate through all directories and subdirectories - filter Java files
pathStream = Files.walk(Paths.get("/Users/darcy/project/mylab/src/main/java/com/wdbyte"));
pathStream
    .filter(pathTemp -> pathTemp.toString().endsWith(".java"))
    .forEach(pathTemp -> {
        System.out.println("Stream filter java: " + pathTemp.toString());
    });
Copy the code

File monitoring

File monitoring is the ability to dynamically monitor changes in files or content in a specified directory. It can be used in a variety of scenarios, such as checking class files for updates during hot deployment, or performing operations whenever a file comes in. Before, you could only find the file changes by calling listFiles in a loop and comparing the results with the last call. Now you can do the reaction logic by notifying them. Everything is much simpler.

The monitored object implements the Watchable interface and registers with the implementation of the WatchService interface through the Register method, specifying the type of event to monitor.

/ / create
StandardWatchEventKinds.ENTRY_CREATE,
/ / delete
StandardWatchEventKinds.ENTRY_DELETE,
/ / update
StandardWatchEventKinds.ENTRY_MODIFY
Copy the code

How do you use it? To see how this code works, take a look at the following example, which monitors the folder /Users/ Darcy /test and registers the create, delete, update actions of interest.

WatchService watchService = FileSystems.getDefault().newWatchService();
Path path = Paths.get("/Users/darcy/test");
path.register(watchService,
    StandardWatchEventKinds.ENTRY_CREATE,
    StandardWatchEventKinds.ENTRY_DELETE,
    StandardWatchEventKinds.ENTRY_MODIFY);

while (true) {
    WatchKey watchKey = watchService.take();
    // Get the event type
    for(WatchEvent<? > pollEvent : watchKey.pollEvents()) {// Specific event context informationPath tempPath = (Path)pollEvent.context(); Kind<? > kind = pollEvent.kind();if (kind.name().equals(StandardWatchEventKinds.ENTRY_CREATE.name())) {
            System.out.println("Create a file:" + tempPath.toString());
        }
        if (kind.name().equals(StandardWatchEventKinds.ENTRY_DELETE.name())) {
            System.out.println("Deleted a file:" + tempPath.toString());
        }
        if (kind.name().equals(StandardWatchEventKinds.ENTRY_MODIFY.name())) {
            System.out.println("Modified a file:"+ tempPath.toString()); }}// After the event is processed, you need to reset to continue listening for events
    watchKey.reset();
    // Cancel the monitor
    // watchKey.cancel();
}
Copy the code

After registering the event listener, call the take() method to obtain the event result through a loop. After obtaining the event, determine the event type and log output. I started a simple test, and here is the log output.

#Here's what I did➜ test PWD /Users/darcy/test ➜ test touch test. TXT # create file ➜ test vim test. TXT # modify file ➜ test rm test. TXT # delete file#The resulting log outputTXT created a file:.test.txt. SWP modified a file: test.txt deleted a file:.test.txt. SWP deleted a file: test.txtCopy the code

Temporary SWP file generation and automatic deletion due to vim editing were also detected.

Previous articles in the New Java feature series:

  • New Features in Java 11

  • New Java 10 features

  • New Java 09 features

  • New in Java 8 – Powerful Stream manipulation posture

  • New features in Java 8 – Lambda expressions, function interfaces

  • New in Java 8 – Time processing posture

  • Java 8 new Features – Handling null Pointers with Optional grace?

  • New Java 7 features

The last word

The article is available at Github.com/niumoo/Java… Welcome Star and advice. There are also some articles such as pilot of big factory surface and core knowledge Java programmers need to master. I have also sorted out a lot of my words. Welcome Star and Perfection, and I hope we can become excellent together.

Article helpful can point a “like” or “share”, are support, I like! Posts are updated every week. To keep track of what I update and share, you can follow the “Unread Code” account or my blog.