一、全文概览
在学习文件系统之前,需要了解下Java在I/O上的发展史:在Java7之前,打开和读取文件需要编写特别笨拙的代码,涉及到很多的InputStream、OutputStream等组合起来使用,每次在使用时或许都需要查一下文档才能记得如何打开一个文件;而在Java 7面世后,这些被人诟病的设计得到了巨大的改进,这些新元素被打包放在了java.nio.file之下。这个包对Java对文件的操作提升到了可以与其他编程语言媲美的程度。
本篇文章就主要学习记录下操作文件的两个基本组件:
- 文件或目录的路径-Path
- 文件本身-File
二、组件一:Path(路径)
1、Path简介
Path对象代表的是一个文件或目录的路径,它是在不同的操作系统和文件系统之上的抽象。它的目的是,我们不必要注意底层的操作系统,我们的代码不需要重写就能在不同的操作系统上工作 —来自:《OnJava-基础篇》
2、Path创建
介绍完Path出现的目的后,我们再来看下如果获取Path。正是java.nio.file.Paths类下重载的static get方法,这个方法的参数可以是接受一个String序列(也就是全路径,系统能够找到的);也可以是一个统一的资源标识符(URI),然后将其转换为Path
下面是对Path以及Files工具类的使用示例
package com.markus.java.file;import com.markus.java.file.constant.FileConstant;import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;/*** @Author: zhangchenglong06* @Date: 2023/2/7* @Description:*/
public class PathInfo {static void show(String id, Object p) {System.out.println(id + p);}static void info(Path path) {show("toString: \n", path);// 路径是否存在show("Exists: ", Files.exists(path));// 是否是常规文件,也就是我们常规意义上的文件,例如.txt .png等,而非目录show("RegularFile: ", Files.isRegularFile(path));// 是否是目录show("Directory: ", Files.isDirectory(path));// 展示绝对路径show("Absolute: ", path.toAbsolutePath());// 展示文件名(最后一级)show("FileName: ", path.getFileName());// 展示父路径show("Parent: ", path.getParent());// 展示根路径show("Root: ", path.getRoot());System.out.println("****************************************************************************************");}public static void main(String[] args) {System.out.println(System.getProperty("os.name"));info(FileSystems.getDefault().getPath(""));info(Paths.get("io/src/main/resources", "file", "file.txt"));Path path = Paths.get(FileConstant.CURRENT_BASE_PATH, "/PathInfo.java");info(path);Path ap = path.toAbsolutePath();info(ap);info(ap.getParent());try {info(ap.toRealPath());} catch (IOException e) {System.out.println(e);}URI uri = path.toUri();System.out.println("URI:\n" + uri);Path pathUri = Paths.get(uri);System.out.println(Files.exists(pathUri));// 不要被骗了File f = ap.toFile();}
}
/** 输出* Mac OS X* toString:** Exists: true* RegularFile: false* Directory: true* Absolute: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples* FileName:* Parent: null* Root: null* ***************************************************************************************** toString:* io/src/main/resources/file/file.txt* Exists: false* RegularFile: false* Directory: false* Absolute: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/resources/file/file.txt* FileName: file.txt* Parent: io/src/main/resources/file* Root: null* ***************************************************************************************** toString:* io/src/main/java/com/markus/java/file/PathInfo.java* Exists: true* RegularFile: true* Directory: false* Absolute: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file/PathInfo.java* FileName: PathInfo.java* Parent: io/src/main/java/com/markus/java/file* Root: null* ***************************************************************************************** toString:* /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file/PathInfo.java* Exists: true* RegularFile: true* Directory: false* Absolute: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file/PathInfo.java* FileName: PathInfo.java* Parent: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file* Root: /* ***************************************************************************************** toString:* /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file* Exists: true* RegularFile: false* Directory: true* Absolute: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file* FileName: file* Parent: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java* Root: /* ***************************************************************************************** toString:* /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file/PathInfo.java* Exists: true* RegularFile: true* Directory: false* Absolute: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file/PathInfo.java* FileName: PathInfo.java* Parent: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file* Root: /* ***************************************************************************************** URI:* file:///Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file/PathInfo.java* true** Process finished with exit code 0*/
3、Path片段
所谓Path片段即是Path对象路径的各个部分,例如/Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java中每个//之间的内容都是一个片段
package com.markus.java.file;import com.markus.java.file.constant.FileConstant;import java.nio.file.Path;
import java.nio.file.Paths;/*** @Author: zhangchenglong06* @Date: 2023/2/7* @Description:*/
public class PartsOfPaths {public static void main(String[] args) {System.out.println(System.getProperty("os.name"));Path p = Paths.get(FileConstant.CURRENT_BASE_PATH, "/PartsOfPaths.java");for (int i = 0; i < p.getNameCount(); i++) {System.out.println(p.getName(i));}System.out.println("ends with '.java': " + p.endsWith(".java"));for (Path path : p) {System.out.print(path + ": ");System.out.print(p.startsWith(path) + " : ");System.out.println(p.endsWith(path));}System.out.println("Starts with " + p.toAbsolutePath().getRoot() + " " + p.toAbsolutePath().startsWith(p.toAbsolutePath().getRoot()));}
}
/** 输出* Mac OS X* io* src* main* java* com* markus* java* file* PartsOfPaths.java* ends with '.java': false* io: true : false* src: false : false* main: false : false* java: false : false* com: false : false* markus: false : false* java: false : false* file: false : false* PartsOfPaths.java: false : true* Starts with / true*/
我们还可以对片段进行添加和删除,需要学习api如下:
- Path#relativize : 在路径首部删除基准路径形成新的路径
- Path#normalize : 删除冗余名称元素的路径
- Path#resolve : 在Path对象后面增加路径片段
package com.markus.java.file;import com.markus.java.file.constant.FileConstant;import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;/*** @Author: zhangchenglong06* @Date: 2023/2/8* @Description: 添加或删除路径片段* relativize 删除基准路径* resolve 增加路径*/
public class AddAndSubtractPaths {static Path base = Paths.get("..", "..", "..").toAbsolutePath().normalize();static void show(int id, Path result) {if (result.isAbsolute()) {// result 在 路径首部删除base基准路径形成新的路径System.out.println("(" + id + ")r" + base.relativize(result));} else {System.out.println("(" + id + ")" + result);}try {System.out.println("RealPath: " + result.toRealPath());} catch (IOException e) {System.out.println(e);}}public static void main(String[] args) {System.out.println(System.getProperty("os.name"));System.out.println(base);Path p = Paths.get(FileConstant.CURRENT_BASE_PATH, "/AddAndSubtractPaths.java").toAbsolutePath();show(1, p);Path convoluted = p.getParent().getParent().resolve("strings").resolve("..").resolve(p.getParent().getFileName());show(2, convoluted);show(3, convoluted.normalize());Path p2 = Paths.get("..", "..");show(4, p2);// normalize 意为删除了冗余名称元素的路径// 例如 ./ 直接删除即可// 例如 strings/../ 直接删除两个元素即可show(5, p2.normalize());show(6, p2.toAbsolutePath());Path p3 = Paths.get(".").toAbsolutePath();// p3在自身路径后面追加p2组成新的路径Path p4 = p3.resolve(p2);show(7, p4);show(8, p4.normalize());Path p5 = Paths.get("").toAbsolutePath();show(9, p5);show(10, p5.resolveSibling("strings"));show(11, Paths.get("nonexistent"));}
}
/** 输出* Mac OS X* /Users* (1)rzhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file/AddAndSubtractPaths.java* RealPath: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file/AddAndSubtractPaths.java* (2)rzhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/strings/../file* java.nio.file.NoSuchFileException: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/strings/../file* (3)rzhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file* RealPath: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples/io/src/main/java/com/markus/java/file* (4)../..* RealPath: /Users/zhangchenglong* (5)../..* RealPath: /Users/zhangchenglong* (6)rzhangchenglong/IdeaProjects/OnJava8-Examples/../..* RealPath: /Users/zhangchenglong* (7)rzhangchenglong/IdeaProjects/OnJava8-Examples/./../..* RealPath: /Users/zhangchenglong* (8)rzhangchenglong* RealPath: /Users/zhangchenglong* (9)rzhangchenglong/IdeaProjects/OnJava8-Examples* RealPath: /Users/zhangchenglong/IdeaProjects/OnJava8-Examples* (10)rzhangchenglong/IdeaProjects/strings* java.nio.file.NoSuchFileException: /Users/zhangchenglong/IdeaProjects/strings* (11)nonexistent* java.nio.file.NoSuchFileException: nonexistent*/
4、删除目录
Files工具类包含了操作目录和文件所需要的大部分操作,但其中缺乏删除目录树的工具方法,这里我们做个删除目录树工具的练习
package com.markus.java.file;import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;/*** @Author: zhangchenglong06* @Date: 2023/2/9* @Description:*/
public class RmDir {public static void rmdir(Path dir) throws IOException {Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {/*** 在这个目录下的每个文件上运行* @param file* @param attrs* @return* @throws IOException*/@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {Files.delete(file);return FileVisitResult.CONTINUE;}/*** 先进入当前目录下的文件和目录(包括所有的子目录),最后在当前目录上运行* @param dir* @param exc* @return* @throws IOException*/@Overridepublic FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {Files.delete(dir);return FileVisitResult.CONTINUE;}/*** 先在当前目录上运行,然后进入这个目录下的文件和目录* @param dir* @param attrs* @return* @throws IOException*/@Overridepublic FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {return super.preVisitDirectory(dir, attrs);}/*** 当文件无法访问时调用* @param file* @param exc* @return* @throws IOException*/@Overridepublic FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {return super.visitFileFailed(file, exc);}});}
}
下面来检验下删除工具的有效性
package com.markus.java.file;import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;import static com.markus.java.file.constant.FileConstant.CURRENT_BASE_PATH;/*** @Author: zhangchenglong06* @Date: 2023/2/9* @Description:*/
public class Directories {static Path test = Paths.get(CURRENT_BASE_PATH, "test");static String sep = FileSystems.getDefault().getSeparator();static List<String> parts = Arrays.asList("foo", "bar", "baz", "bag");static Path makeVariant() {// 移动指定列表的元素 distance 位// 例如 [1, 2, 3, 4, 5] 执行Collections.rotate(list.subList(1,4),1)// 结果 [1, 4, 3, 4, 5]Collections.rotate(parts, 1);return Paths.get(CURRENT_BASE_PATH, "test", String.join(sep, parts));}static void refreshTestDir() throws IOException {// 如果文件存在则删除,否则创建目录if (Files.exists(test)) {RmDir.rmdir(test);}if (!Files.exists(test)) {Files.createDirectory(test);}}static void populateTestDir() throws IOException {for (int i = 0; i < parts.size(); i++) {Path variant = makeVariant();if (!Files.exists(variant)) {Files.createDirectories(variant);Files.copy(Paths.get(CURRENT_BASE_PATH, "Directories.java"), variant.resolve("File" + i + ".txt"));Files.createTempFile(variant, null, null);}}}public static void main(String[] args) throws IOException {// 刷新测试目录refreshTestDir();// 在test路径下增加Hello.txt文件路径 并创建此路径文件Files.createFile(test.resolve("Hello.txt"));// 创建文件Path variant = makeVariant();try {// 创建一级目录的函数,当创建多级目录时会抛出文件不存在的异常Files.createDirectory(variant);} catch (Exception e) {System.out.println("Nope, that doesn't work." + e);}populateTestDir();Path tempDir = Files.createTempDirectory(test, "DIR_");Files.createTempFile(tempDir, "pre", ".non");// newDirectoryStream 只显示指定目录下的子目录或文件Files.newDirectoryStream(test).forEach(System.out::println);System.out.println("********************");// walk 可以浏览指定目录下的所有内容(目录树)Files.walk(test).forEach(System.out::println);}
}
/** 控制台* Nope, that doesn't work.java.nio.file.NoSuchFileException: io/src/main/java/com/markus/java/file/test/bag/foo/bar/baz* io/src/main/java/com/markus/java/file/test/DIR_260744175083605522* io/src/main/java/com/markus/java/file/test/foo* io/src/main/java/com/markus/java/file/test/baz* io/src/main/java/com/markus/java/file/test/bar* io/src/main/java/com/markus/java/file/test/bag* io/src/main/java/com/markus/java/file/test/Hello.txt* ********************* io/src/main/java/com/markus/java/file/test* io/src/main/java/com/markus/java/file/test/DIR_260744175083605522* io/src/main/java/com/markus/java/file/test/DIR_260744175083605522/pre7111318949801779914.non* io/src/main/java/com/markus/java/file/test/foo* io/src/main/java/com/markus/java/file/test/foo/bar* io/src/main/java/com/markus/java/file/test/foo/bar/baz* io/src/main/java/com/markus/java/file/test/foo/bar/baz/bag* io/src/main/java/com/markus/java/file/test/foo/bar/baz/bag/File2.txt* io/src/main/java/com/markus/java/file/test/foo/bar/baz/bag/2694156263661518806.tmp* io/src/main/java/com/markus/java/file/test/baz* io/src/main/java/com/markus/java/file/test/baz/bag* io/src/main/java/com/markus/java/file/test/baz/bag/foo* io/src/main/java/com/markus/java/file/test/baz/bag/foo/bar* io/src/main/java/com/markus/java/file/test/baz/bag/foo/bar/File0.txt* io/src/main/java/com/markus/java/file/test/baz/bag/foo/bar/6305328343447758907.tmp* io/src/main/java/com/markus/java/file/test/bar* io/src/main/java/com/markus/java/file/test/bar/baz* io/src/main/java/com/markus/java/file/test/bar/baz/bag* io/src/main/java/com/markus/java/file/test/bar/baz/bag/foo* io/src/main/java/com/markus/java/file/test/bar/baz/bag/foo/File1.txt* io/src/main/java/com/markus/java/file/test/bar/baz/bag/foo/5478658539929705751.tmp* io/src/main/java/com/markus/java/file/test/bag* io/src/main/java/com/markus/java/file/test/bag/foo* io/src/main/java/com/markus/java/file/test/bag/foo/bar* io/src/main/java/com/markus/java/file/test/bag/foo/bar/baz* io/src/main/java/com/markus/java/file/test/bag/foo/bar/baz/File3.txt* io/src/main/java/com/markus/java/file/test/bag/foo/bar/baz/5014150493260271159.tmp* io/src/main/java/com/markus/java/file/test/Hello.txt*/
5、Path监听和查找
FileSystems(文件系统)可以获得两个的API:
- WatchService: 监听Path
- TreeMatcher: 查找Path
下面我们看下代码示例:
- WatchService
package com.markus.java.file;import com.markus.java.file.constant.FileConstant;import java.io.IOException;
import java.nio.file.*;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;/*** @Author: zhangchenglong06* @Date: 2023/2/10* @Description:*/
public class PathWatcher {static Path test = Paths.get(FileConstant.CURRENT_BASE_PATH, "test");static void delTxtFiles() {try {Files.walk(test).filter(f -> f.toString().endsWith(".txt")).forEach(f -> {System.out.println("deleting " + f);try {Files.delete(f);} catch (IOException e) {throw new RuntimeException(e);}});} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException, InterruptedException {// 刷新目录Directories.refreshTestDir();// 创建目录下的文件Directories.populateTestDir();Files.createFile(test.resolve("Hello.txt"));WatchService watcher = FileSystems.getDefault().newWatchService();// 只能监听到当前目录下操作,子目录下的文件操作不会被监听到test.register(watcher, ENTRY_DELETE);Executors.newSingleThreadScheduledExecutor().schedule(PathWatcher::delTxtFiles, 250, TimeUnit.MILLISECONDS);WatchKey key = watcher.take();for (WatchEvent<?> evt : key.pollEvents()) {System.out.println("evt.context(): " + evt.context() +"\nevt.count(): " + evt.count() +"\nevt.kind(): " + evt.kind());System.exit(0);}}
}
/** 控制台* deleting io/src/main/java/com/markus/java/file/test/foo/bar/baz/bag/File3.txt* deleting io/src/main/java/com/markus/java/file/test/baz/bag/foo/bar/File1.txt* deleting io/src/main/java/com/markus/java/file/test/bar/baz/bag/foo/File2.txt* deleting io/src/main/java/com/markus/java/file/test/bag/foo/bar/baz/File0.txt* deleting io/src/main/java/com/markus/java/file/test/Hello.txt* evt.context(): Hello.txt* evt.count(): 1* evt.kind(): ENTRY_DELETE*/
上面的代码会有个缺陷,就是它只能监听到当前目录的操作,而无法查找当前目录下所有的子目录的操作行为,如果想监听整个目录树,则必须在整个树的每个子目录上设置一个WatchService
package com.markus.java.file;import com.markus.java.file.constant.FileConstant;import java.io.IOException;
import java.nio.file.*;
import java.util.concurrent.Executors;import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;/*** @Author: zhangchenglong06* @Date: 2023/2/10* @Description:*/
public class TreeWatcher {static void watchDir(Path dir) {try {WatchService watcher = FileSystems.getDefault().newWatchService();dir.register(watcher, ENTRY_DELETE);Executors.newSingleThreadScheduledExecutor().submit(() -> {try {WatchKey key = watcher.take();for (WatchEvent<?> evt : key.pollEvents()) {System.out.println("evt.context(): " + evt.context() +"\nevt.count(): " + evt.count() +"\nevt.kind(): " + evt.kind());System.exit(0);}} catch (InterruptedException e) {return;}});} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {Directories.refreshTestDir();Directories.populateTestDir();Files.walk(Paths.get(FileConstant.CURRENT_BASE_PATH, "test")).filter(Files::isDirectory).forEach(TreeWatcher::watchDir);PathWatcher.delTxtFiles();}
}
/** 控制台* deleting io/src/main/java/com/markus/java/file/test/foo/bar/baz/bag/File3.txt* deleting io/src/main/java/com/markus/java/file/test/baz/bag/foo/bar/File1.txt* deleting io/src/main/java/com/markus/java/file/test/bar/baz/bag/foo/File2.txt* deleting io/src/main/java/com/markus/java/file/test/bag/foo/bar/baz/File0.txt* evt.context(): File1.txt* evt.count(): 1* evt.kind(): ENTRY_DELETE* evt.context(): File0.txt* evt.count(): 1* evt.kind(): ENTRY_DELETE*/
- PathMatcher
package com.markus.java.file;import com.markus.java.file.constant.FileConstant;import java.io.IOException;
import java.nio.file.*;/*** @Author: zhangchenglong06* @Date: 2023/2/10* @Description:*/
public class Find {public static void main(String[] args) throws IOException {Path test = Paths.get(FileConstant.CURRENT_BASE_PATH, "test");Directories.refreshTestDir();Directories.populateTestDir();Files.createDirectory(test.resolve("dir.tmp"));PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:**/*.{tmp,txt}");Files.walk(test).filter(matcher::matches).forEach(System.out::println);System.out.println("*******************");PathMatcher matcher2 = FileSystems.getDefault().getPathMatcher("glob:*.tmp");Files.walk(test).map(Path::getFileName).filter(matcher2::matches).forEach(System.out::println);System.out.println("*******************");Files.walk(test).filter(Files::isRegularFile).map(Path::getFileName).filter(matcher2::matches).forEach(System.out::println);}
}
/** 控制台* io/src/main/java/com/markus/java/file/test/foo/bar/baz/bag/File3.txt* io/src/main/java/com/markus/java/file/test/foo/bar/baz/bag/2767500121528410890.tmp* io/src/main/java/com/markus/java/file/test/baz/bag/foo/bar/File1.txt* io/src/main/java/com/markus/java/file/test/baz/bag/foo/bar/5789074899285883862.tmp* io/src/main/java/com/markus/java/file/test/dir.tmp* io/src/main/java/com/markus/java/file/test/bar/baz/bag/foo/File2.txt* io/src/main/java/com/markus/java/file/test/bar/baz/bag/foo/5458649986440731775.tmp* io/src/main/java/com/markus/java/file/test/bag/foo/bar/baz/File0.txt* io/src/main/java/com/markus/java/file/test/bag/foo/bar/baz/5568292198534480479.tmp* ******************** 2767500121528410890.tmp* 5789074899285883862.tmp* dir.tmp* 5458649986440731775.tmp* 5568292198534480479.tmp* ******************** 2767500121528410890.tmp* 5789074899285883862.tmp* 5458649986440731775.tmp* 5568292198534480479.tmp*/
三、组件二:File(文件)
在上面,主要学习记录了对路径目录的操作,现在来学习下如果操作文件本身的内容,也就是如何进行读写文件:
- 通过Files.readAllLines 可以一次性的读入整个文件,生成一个List<String>。ps:这里不建议一次性读入大文件,会撑爆内存的
package com.markus.java.file;import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;/*** @author: markus* @date: 2023/2/15 10:39 PM* @Description:* @Blog: https://markuszhang.com* It's my honor to share what I've learned with you!*/
public class ListOfLines {public static void main(String[] args) throws IOException {Files.readAllLines(Paths.get("io/src/main/resources/file_writer.txt")).forEach(System.out::println);}
}
/** 控制台* Hello,IO*/
- 通过Files.write可以将byte数组或任何实现了Iterable接口的类的对象写入文件
package com.markus.java.file;import com.markus.java.file.constant.FileConstant;import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Random;/*** @author: markus* @date: 2023/2/16 10:33 PM* @Description:* @Blog: https://markuszhang.com* It's my honor to share what I've learned with you!*/
public class Writing {static Random rand = new Random(47);static final int SIZE = 1000;public static void main(String[] args) throws IOException {// 将字节写入一个文件byte[] bytes = new byte[SIZE];rand.nextBytes(bytes);
// Files.write(Paths.get(FileConstant.CURRENT_BASE_PATH, "bytes.txt"), bytes, Charset.forName("charset"));Files.write(Paths.get(FileConstant.CURRENT_BASE_PATH, "bytes.txt"), bytes);System.out.println("bytes.txt: " + Files.size(Paths.get(FileConstant.CURRENT_BASE_PATH, "bytes.txt")));// 将实现了Iterable接口的类的对象写入一个文件List<String> lines = Files.readAllLines(Paths.get("io/src/main/resources/file_writer.txt"));Files.write(Paths.get("io/src/main/resources/file_writer.txt"), lines);System.out.println("file_writer.txt: " + Files.size(Paths.get("io/src/main/resources/file_writer.txt")));}
}
/*** 控制台* bytes.txt: 1000* file_writer.txt: 9*/
- 通过Files.lines可以很方便的将一个文件变为一个由行组成的Stream,这样可以应对当文件非常大,而我们只需要文件的一部分时,进行读取,而非全部读入内存当中
package com.markus.java.file;import com.markus.java.file.constant.FileConstant;import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;/*** @author: markus* @date: 2023/2/16 10:47 PM* @Description:* @Blog: https://markuszhang.com* It's my honor to share what I've learned with you!*/
public class ReadLineStream {public static void main(String[] args) throws IOException {Files.lines(Paths.get(FileConstant.CURRENT_BASE_PATH, "PathInfo.java")).skip(13).findFirst().ifPresent(System.out::println);}
}
/** 控制台* * @Author: zhangchenglong06*/
- 通过Files.lines我们也可以实现由行组成的输入流来在流中完成读取、处理、写入等操作
package com.markus.java.file;import com.markus.java.file.constant.FileConstant;import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;/*** @author: markus* @date: 2023/2/16 10:52 PM* @Description:* @Blog: https://markuszhang.com* It's my honor to share what I've learned with you!*/
public class StreamInAndOut {public static void main(String[] args) {try (Stream<String> input = Files.lines(Paths.get(FileConstant.CURRENT_BASE_PATH, "StreamInAndOut.java"));PrintWriter writer = new PrintWriter(FileConstant.CURRENT_BASE_PATH + "StreamInAndOut.txt");) {input.map(String::toUpperCase).forEachOrdered(writer::println);} catch (IOException e) {e.printStackTrace();}}
}
四、全文总结
本文记录了基于Path、Paths、File、Files等抽象对文件、目录相关的操作,摒弃了传统的Java I/O操作类,它使得我们对文件等的操作更加简单,它屏蔽了用户与底层的交互,也使得代码可以跨平台运行。