java学习-io-new io
对于 从jdk 1.7 开始引入新的 文件系统 称为 nio;
和之前io的不同点在于
- 存在新的api java.nio.file.Path 以及新的文件系统 java.nio.file.FileSystem
- 新的工具类: java.nio.file.Files 以及 java.nio.filePaths
- 对于 新的 Path 接口集成了 java.nio.file.Watchable提供了便利的文件变更监控API 而不需要再使用java.io.File#lastModified 来判断文件变化
- 新的文件读写API,对于io中之前直接使用 byte数组读取方式,提供了 HeapByteBuffer和DirectByteBuffer两种方式, 对于 Heap底层实际还是使用byte数组存储;对于Direct实际是使用的堆外内存
ByteBuffer 使用样例
/* * Copyright (c) 2020, guoxing, Co,. Ltd. All Rights Reserved */ package com.xingguo.nio; import java.io.IOException; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.ByteChannel; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.OpenOption; import java.nio.file.Path; import java.nio.file.Paths; /** * ByteChannelDemo * {@link java.nio.channels.ByteChannel} * 作为 new io 中新提供的操作,实际使用了{@link java.nio.ByteBuffer} 对于 其 concrete class 包含{@link java.nio.HeapByteBuffer} 以及 {@link java.nio.DirectByteBuffer}, 其和 {@link java.io.BufferedInputStream} 的区别在于 对于{@link java.io.BufferedInputStream}由于其使用了{@code byte[]} 因此其只支持 堆内数据 等价于 {@link java.nio.HeapByteBuffer} * 对于 {@link java.nio.DirectByteBuffer} 实际就是也是存储到内存中的,只是并不直接存储到堆空间中 * * @author guoxing * @date 2020/12/8 9:18 PM * @since */ public class ByteChannelDemo { private static final String USER_DIR = System.getProperty("user.dir"); public static void main(String[] args) { byteBufferReadData(); } private static void byteBufferReadData() { /** * 测试 使用 {@link Files#newByteChannel(Path, OpenOption...)} 来进行文件读取和写入操作 * 对于{@link OpenOption}的 concrete class {@link java.nio.file.StandardOpenOption} 中的操作包含了其他语言都通用的文件io操作 */ // 读取 USER_DIR/README.md 文件 try (ByteChannel byteChannel = Files.newByteChannel(Paths.get(USER_DIR, "README.md"))) { // 创建一个{@link HeapByteBuffer} /** * TODO : 对于当前数据读取中文存在乱码的情况; 由于中文字符UTF-8编码集字节长度不固定,因此会导致按照字节读取时出现一个完整的字符字节被中断的情况 * 对于 当前初始化的 {@link ByteBuffer}中的相关初始化字段 * {@link ByteBuffer#mark} = -1 * {@link ByteBuffer#position} = 0 * {@link ByteBuffer#capacity} = {@link ByteBuffer#allocate(int)} 中的参数 * {@link ByteBuffer#limit} = {@link ByteBuffer#allocate(int)} 中的参数 */ ByteBuffer byteBuffer = ByteBuffer.allocate(16); Charset charset = StandardCharsets.UTF_8; // 对于 read 的终止条件为 0或-1 代表文件读取结束 /** * 对于 {@link ByteBuffer#put(byte)}操作实际会变更{@link ByteBuffer#position} 记录写入 bytebuffer的字节长度 */ while (byteChannel.read(byteBuffer) > 0) { /** * rewind 倒带的含义表示 对于bytebuffer每次数据读取都是从头{@link ByteBuffer#position} = 0 开始进行数据读取;由于当写入完成后,{@link ByteBuffer#position}位置发生变化,因此数据读取时要从头开始读取 */ byteBuffer.rewind(); /** * 对于{@link Charset#decode(ByteBuffer)}操作实际就是读取 {@link ByteBuffer},会调用{@link ByteBuffer#position(int)}修改{@link ByteBuffer#position}字段数据,记录本次读取bytebuffer的字节长度 */ // 使用UTF-8编码集 将 byteBuffer 转换为 CharBuffer CharBuffer charBuffer = charset.decode(byteBuffer); // 对于当前 操作 默认是按照 bigEndian字节读取方式进行读取数据,因此读取出来的数据会是乱码 // CharBuffer charBuffer = byteBuffer.asCharBuffer(); /** * 由于 {@link CharBuffer} {@code implements CharSequence} * 对于 {@link CharBuffer#toString(int, int)} 中的 start 字段 是从 position 开始到 limit 结束 */ System.out.print(charBuffer); /** * 由于读取操作导致 {@link ByteBuffer#position} 数据发生变化, * 对于{@link ByteBuffer#limit} 字段实际是通过记录上一次的数据读取的长度 * * flip 翻转 * {@link ByteBuffer#flip()} 首先将上一次读取的数据长度{@link ByteBuffer#position}赋值给{@link ByteBuffer#limit},并将 {@link ByteBuffer#position}重置为0 ,以及{@link ByteBuffer#mark}重置为-1 * * 对于{@link Buffer#flip()}和{@link Buffer#clear()} 的唯一区别在于 对于{@link Buffer#limit}字段的操作 * 对于 {@link Buffer#flip()} 操作的好处在于记录了上次读取的最长长度,同时也限制了下一次写入的长度 */ byteBuffer.flip(); // byteBuffer.clear(); } } catch (IOException e) { throw new RuntimeException(e); } } }
new io 相关 复制和移动操作 :对于复制和移动操作 特别需要注意的一点在于 对于 目标PATH中的中间路径(目录)不允许出现不存在的情况,否则会抛出NoSuchFileException;
相关文件查找API增强 , 支持自定义实现类似 linux find 命令操作
/* * Copyright (c) 2020, guoxing, Co,. Ltd. All Rights Reserved */ package com.xingguo.nio; import java.io.File; import java.io.IOException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileAttribute; import java.util.Objects; /** * DirectoryOperateDemo * {@link java.nio.file.Files#createDirectory(Path, FileAttribute[])} 当前操作只能在已存在的目录下创建文件 * {@link java.nio.file.Files#createDirectories(Path, FileAttribute[])} 当前操作对于不存在的目录会按照父子关系依次创建 * * @author guoxing * @date 2020/12/9 3:16 PM * @since */ public class DirectoryOperateDemo { private static final String USER_DIR = System.getProperty("user.dir"); public static void main(String[] args) throws IOException { // directoryBasicOperate(); // 遍历目录 /** * {@link java.nio.file.FileVisitor} * {@link java.nio.file.FileSystem#getPathMatcher(String)} 支持正则匹配文件 * 利用{@link Files#walkFileTree(Path, FileVisitor)} 进行文件查找 */ String javaProjectLocation = getCurrentJavaLocation(); // 查找当前类所在目录下全部java文件 findCommand(javaProjectLocation, "*.java"); // findCommand(USER_DIR, "*.java"); } /** * 获取maven工程下当前类的java文件全路径 * * @return 当前java文件路径 * @author guoxing * @date 2020-12-09 5:42 PM * @since 1.0.0 */ public static String getCurrentJavaLocation() { Class<DirectoryOperateDemo> directoryOperateDemoClass = DirectoryOperateDemo.class; String path = directoryOperateDemoClass.getResource("/").getPath(); String projectPath = path.replace("/target/classes", "/src/main/java"); Package aPackage = directoryOperateDemoClass.getPackage(); String name = aPackage.getName(); // 获取当前maven工程 java文件全路径 return projectPath + name.replace(".", File.separator); } /** * 模拟 find 命令 查找匹配的文件 * * @param pathName 查找根路径 * @param pattern 正则表达式 * @author guoxing * @date 2020-12-09 4:24 PM * @since 1.0.0 */ private static void findCommand(String pathName, String pattern) throws IOException { Path path = Paths.get(pathName); if (!Files.isDirectory(path)) { return; } CustomFileVisitor customFileVisitor = new CustomFileVisitor(pattern); try { Files.walkFileTree(path, customFileVisitor); } catch (IOException e) { throw new RuntimeException(e); } System.out.printf("%s : 匹配到的文件数量为:%s\n", path, customFileVisitor.getCount()); } /** * 自定义 文件查找类 * * @author guoxing * @date 2020-12-09 4:30 PM * @since 1.0.0 */ static class CustomFileVisitor extends SimpleFileVisitor<Path> { // sun.nio.fs.UnixFileSystem.GLOB_SYNTAX private static final String syntax = "glob"; // 采用文件正则匹配工具 private final PathMatcher pathMatcher; // 返回匹配到的数据量 private int count; public int getCount() { return count; } public CustomFileVisitor(String pattern) { this.pathMatcher = FileSystems.getDefault().getPathMatcher(syntax + ":" + pattern); } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { matchFile(dir); return FileVisitResult.CONTINUE; } private void matchFile(Path dir) { // dir.getFileName 获取的是当前文件名,而非全路径名 if (Objects.nonNull(dir) && pathMatcher.matches(dir.getFileName())) { System.out.println(dir); count++; } } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { matchFile(file); return FileVisitResult.CONTINUE; } } private static void directoryBasicOperate() throws IOException { Path path = Files.createDirectory(Paths.get(USER_DIR, "temp")); Files.delete(path); // java.nio.file.NoSuchFileException // path = Files.createDirectory(Paths.get(USER_DIR, "temp", "secondtemp")); // 当前操作会抛出异常 // 对于不存在的父级目录,会优先创建 path = Files.createDirectories(Paths.get(USER_DIR, "temp", "secondtemp")); //遍历 目录 下的所有文件数据 DirectoryStream<Path> paths = Files.newDirectoryStream(path, p -> p.toString().startsWith(USER_DIR)); for (Path value : paths) { System.out.println(value); } // 由于创建了多级目录,因此需要循环删除 // TODO:对于这种循环删除一定要确定终止条件 Path basePath = Paths.get(USER_DIR); while (path.startsWith(USER_DIR) && !path.equals(basePath)) { Files.delete(path); path = path.getParent(); } } }
文件类型
/**
* Basic attributes associated with a file in a file system.
*
* <p> Basic file attributes are attributes that are common to many file systems
* and consist of mandatory and optional file attributes as defined by this
* interface.
*
* <p> <b>Usage Example:</b>
* <pre>
* Path file = ...
* BasicFileAttributes attrs = Files.readAttributes(file, BasicFileAttributes.class); // 使用方法,官方示例
* </pre>
*
* @since 1.7
*
* @see BasicFileAttributeView
*/
java.nio.file.attribute.BasicFileAttributes

浙公网安备 33010602011771号