您的位置 首页 java

放弃new File。Java 文件操作神器:NIO

#java#

#nio#

文件路径拼接

首先来看下基本概念:URI, URL

URI:

格式:{scheme}: //{user}@{host}:{port}{path}?{query}#{fragment}
demo:#meat

 
@Test
    public void testURI() {
        String uriPath = "#meat";
        URI uri = URI.create(uriPath);
        assertEquals("http", uri.getScheme());
        assertEquals("yunzhong.com", uri.getHost());
        assertEquals("/yunzhong/eat", uri.getPath());
        assertEquals("yunzhong", uri.getUserInfo());
        System.out.println("Authority = " + uri.getAuthority());
        System.out.println("Fragment = " + uri.getFragment());
        System.out.println("Host = " + uri.getHost());
        System.out.println("Path = " + uri.getPath());
        System.out.println("Port = " + uri.getPort());
        System.out.println("Query = " + uri.getQuery());
        System.out.println("Scheme = " + uri.getScheme());
        System.out.println("Scheme-specific part = " + uri.getSchemeSpecificPart());
        System.out.println("User Info = " + uri.getUserInfo());
        System.out.println("URI is absolute: " + uri.isAbsolute());
        System.out.println("URI is opaque: " + uri.isOpaque());
    }
  
 
Authority = yunzhong@yunzhong.com:8080
Fragment = meat
Host = yunzhong.com
Path = /yunzhong/eat
Port = 8080
Query = when=afternoon
Scheme = http
Scheme-specific part = //yunzhong@yunzhong.com:8080/yunzhong/eat?when=afternoon
User Info = yunzhong
URI is absolute: true
URI is opaque: false  

URL

是URI的一个子集,一般用于网络上。

 @Test
    public void testHttps() throws MalformedURLException {
        URL url = new URL("#j2se");
        assertEquals("https",url.getProtocol());
        assertEquals("www.yunzhong.com", url.getHost());
        assertEquals(8080, url.getPort());
        assertEquals(443, url.getDefaultPort());
        assertEquals("/index.html", url.getPath());
        System.out.println("URL 为:" + url.toString());
        System.out.println("协议为:" + url.getProtocol());
        System.out.println("验证信息:" + url.getAuthority());
        System.out.println("文件名及请求参数:" + url.getFile());
        System.out.println("主机名:" + url.getHost());
        System.out.println("路径:" + url.getPath());
        System.out.println("端口:" + url.getPort());
        System.out.println("默认端口:" + url.getDefaultPort());
        System.out.println("请求参数:" + url.getQuery());
        System.out.println("定位位置:" + url.getRef());
    }  

Path路径拼接

URL转成Path:

     Path path = Paths.get(resource.toURI());  

URI可以直接作为参数传递给Path。
Path还可以拼接多级路径,不需要用户处理”/”,””等问题。

     @Test
    public void testAppend() {
        System.out.println(Paths.get("D:/temp", "hello/world", "files").toString());
        System.out.println(Paths.get("D:/temp", "hello\\world", "files").toString());
        System.out.println(Paths.get("D:/temp", "hello", "world", "files").toString());
        
        Path path = Paths.get("D:/temp");
        Path resolve = path.resolve("hello").resolve("world").resolve("files");
        System.out.println(resolve.toString());
    }  

文件夹操作

  • 文件夹下的遍历操作
    一种方式是使用Files.walkFileTree接口。这个接口遍历目录下所有的文件和文件夹。接口的参数需要传入FileVisitor,提供了文件、文件夹的操作接口。
    一种方式是使用Files.newDirectoryStream。这个接口只打印第一层的文件和文件夹。另外,因为是打开了一个stream,需要在finally中close stream。比较好的是用户可以自己定义过滤条件,支持“*”等通配符。
    最后一种方式,是采用File.listFiles列举所有的第一层文件。
  • 创建文件夹操作
    文件夹的创建分为两个接口:Files.createDirectory和Files.createDirectories。
    Files.createDirectory只能创建一级目录。比如说已经存在了“/home/yunzhong”,可以创建“/home/yunzhong/temp”,但是不可以创建“/home/yunzhong/temp/firstDir”。
    Files.createDirectories则是会将路径上不存在的文件夹都创建出来,相当于是Files.createDirectory的更便利的封装。
  • 删除文件夹
    删除的文件夹,必须没有子文件或者子文件夹,所以不管怎么操作都需要先删除文件夹的内容,再删除文件夹。
    可以采用Files.walkFileTree进行删除。也可以通过递归的方式删除文件夹。
    代码:
 public static void printFileTree(String rootPath) throws IOException {
Path path = Paths.get(rootPath);
if (Files.notExists(path)) {
log.warn("there is no path {}", rootPath);
return;
}
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {

@Override
public FileVisitResult visitFile(Path path, BasicFileAttributes arg1) throws IOException {
System.out.println(path.toString());
return FileVisitResult.CONTINUE;
}

});
System.out.println("split--------------------------------------");
Files.walkFileTree(path, new FileVisitor<Path>() {

@Override
public FileVisitResult visitFile(Path path, BasicFileAttributes arg1) throws IOException {
System.out.println(path.toString());
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult postVisitDirectory(Path arg0, IOException arg1) throws IOException {
System.out.println("post visit directory:" + arg0.toString());
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult preVisitDirectory(Path arg0, BasicFileAttributes arg1) throws IOException {
System.out.println("pre visit directory:" + arg0.toString());
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFileFailed(Path arg0, IOException arg1) throws IOException {
return FileVisitResult.CONTINUE;
}

});
}

/**
 * print file in folder
 * 
 * @param rootPath
 * @throws IOException
 */public static void printFileDirectory(String rootPath) throws IOException {
Path path = Paths.get(rootPath);
if (Files.notExists(path)) {
log.warn("there is no path {}", rootPath);
return;
}
File[] listFiles = path.toFile().listFiles();
for (File file : listFiles) {
System.out.println("file :" + file.getAbsolutePath());
}
}

/**
 * @param rootPath
 * @param glob
 * @throws IOException
 */public static void printDirectory(String rootPath, String glob) throws IOException {
Path path = Paths.get(rootPath);
if (Files.notExists(path)) {
log.warn("there is no path {}", rootPath);
return;
}
DirectoryStream<Path> newDirectoryStream = null;
try {
if (glob != null) {
newDirectoryStream = Files.newDirectoryStream(path, glob);
} else {
newDirectoryStream = Files.newDirectoryStream(path);
}
for (Path directory : newDirectoryStream) {
System.out.println("path:" + directory.toString());
}
} finally {
if (newDirectoryStream != null) {
newDirectoryStream.close();
}
}
}

/**
 * @param rootPath
 * @param attr
 * @throws Exception
 */public static void createDirectory(String rootPath, String attr) throws Exception {
Path createDirectory = null;
if (StringUtils.isEmpty(attr)) {
Path path = Paths.get(rootPath);
createDirectory = Files.createDirectory(path);
} else {
Set<PosixFilePermission> attrSet = PosixFilePermissions.fromString(attr);
FileAttribute<Set<PosixFilePermission>> fileAttribute = PosixFilePermissions.asFileAttribute(attrSet);
Path path = Paths.get(rootPath);
createDirectory = Files.createDirectory(path, fileAttribute);
}
if (!Files.exists(createDirectory)) {
throw new Exception();
}
}

/**
 * @param rootPath
 * @param attr
 * @throws Exception
 */public static void createDirectories(String rootPath, String attr) throws Exception {
Path createDirectory = null;
if (StringUtils.isEmpty(attr)) {
Path path = Paths.get(rootPath);
createDirectory = Files.createDirectories(path);
} else {
Set<PosixFilePermission> attrSet = PosixFilePermissions.fromString(attr);
FileAttribute<Set<PosixFilePermission>> fileAttribute = PosixFilePermissions.asFileAttribute(attrSet);
Path path = Paths.get(rootPath);
createDirectory = Files.createDirectories(path, fileAttribute);
}
if (!Files.exists(createDirectory)) {
throw new Exception();
}
}

/**
 * @param rootPath
 * @throws IOException
 */public static void removeDirectory(String rootPath) throws IOException {
Path directory = Paths.get(rootPath);
EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);

Files.walkFileTree(directory, opts, Integer.MAX_VALUE, new FileVisitor<Path>() {

@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.deleteIfExists(file);
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
throw exc;
}

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (exc != null) {
log.error("Failed to delete file of path {}", dir.toString());
throw exc;
}
Files.deleteIfExists(dir);
return FileVisitResult.CONTINUE;
}
});
}

public static void removeDirectoryRecursive(String rootPath) throws IOException {
Path directory = Paths.get(rootPath);
if (!Files.exists(directory)) {
return;
}
deleteDirectory(directory);
}

private static void deleteDirectory(Path directory) throws IOException {
if (!Files.isDirectory(directory)) {
Files.delete(directory);
return;
}
File[] files = directory.toFile().listFiles();
for (File file : files) {
deleteDirectory(file.toPath());
}
Files.delete(directory);
}  

文件操作

如果文件很小,可以直接一次性读到内存。如果文件很大,就需要使用流、buffer的概念了。

NIO还提供了异步文件操作,从而应对高性能的情况。使用起来复杂,在一般情况下建议不要使用。

小文件操作

一次性读取到内存。

     public static void printSmallFile(String filePath) throws IOException {
        Path path = Paths.get(filePath);
        System.out.println(Files.readString(path));
    }

    public static void printSmallFileByLine(String filePath) throws IOException {
        Path path = Paths.get(filePath);
        List<String> readAllLines = Files.readAllLines(path);
        for (String line : readAllLines) {
            System.out.println(line);
        }
    }
  

异步文件操作

AsynchronousFileChannel进行文件的读写。实现起来很复杂,一般不要用了。

    public static void printAsync(String filePath) throws IOException, InterruptedException, ExecutionException {
        Path file = Paths.get(filePath);
        try (AsynchronousFileChannel channel = AsynchronousFileChannel.open(file)) {
            // 从jdk7开始,支持数字中下划线,增强数字的可读性
            // ByteBuffer buffer = ByteBuffer.allocate(4_000);
            ByteBuffer buffer = ByteBuffer.allocate(4);
            int position = 0;
            while (true) {
                Future<Integer> result = channel.read(buffer, position);
                while (!result.isDone()) {
                }
                if (result.get() <= 0) {
                    System.out.println(" ");
                    System.out.println("all data done.");
                    break;
                }
                buffer.flip();
                while (buffer.hasRemaining()) {
                    System.out.print((char) buffer.get());
                }
                position += 4;
                buffer.clear();
            }
            System.out.println(" ");
        }
    }

    public static void printAsyncHandler(String filePath) throws IOException {
        Path file = Paths.get(filePath);
        ByteBuffer buffer = ByteBuffer.allocate(4_000_000);
        try (AsynchronousFileChannel channel = AsynchronousFileChannel.open(file)) {
            int position = 0;
            channel.read(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() {
                @Override
                public void completed(Integer result, ByteBuffer attachment) {
                    attachment.flip();
                    while (attachment.hasRemaining()) {
                        System.out.print((char) attachment.get());
                    }
                    attachment.clear();
                }

                @Override
                public void failed(Throwable exc, ByteBuffer attachment) {
                    System.out.println("error" + exc.getLocalizedMessage());
                }
            });
        }
    }
  

文章来源:智云一二三科技

文章标题:放弃new File。Java 文件操作神器:NIO

文章地址:https://www.zhihuclub.com/183657.shtml

关于作者: 智云科技

热门文章

网站地图