标签:count 文件查找 pen 解决方案 views stream 怎么 delete 结果
在丑陋的 Java I/O 编程方式诞生多年以后,Java终于简化了文件读写的基本操作。
两个基本组件
这块基本都是些记忆性的东西,没什么过多的需要写的地方,用的时候搜一下就好,记住当然好,但是本人智商记不住。并且只看看NIO就可以。
文件系统
// files/FileSystemDemo.java import java.nio.file.*; public class FileSystemDemo { static void show(String id, Object o) { System.out.println(id + ": " + o); } public static void main(String[] args) { System.out.println(System.getProperty("os.name")); FileSystem fsys = FileSystems.getDefault(); for(FileStore fs : fsys.getFileStores()) show("File Store", fs); for(Path rd : fsys.getRootDirectories()) show("Root Directory", rd); show("Separator", fsys.getSeparator()); show("UserPrincipalLookupService", fsys.getUserPrincipalLookupService()); show("isOpen", fsys.isOpen()); show("isReadOnly", fsys.isReadOnly()); show("FileSystemProvider", fsys.provider()); show("File Attribute Views", fsys.supportedFileAttributeViews()); } } /* 输出: Windows 10 File Store: SSD (C:) Root Directory: C:Root Directory: D:Separator: UserPrincipalLookupService: sun.nio.fs.WindowsFileSystem$LookupService$1@15db9742 isOpen: true isReadOnly: false FileSystemProvider: sun.nio.fs.WindowsFileSystemProvider@6d06d69c File Attribute Views: [owner, dos, acl, basic, user] */
路径监听
通过 WatchService 可以设置一个进程对目录中的更改做出响应。在这个例子中,delTxtFiles() 作为一个单独的任务执行,该任务将遍历整个目录并删除以 .txt 结尾的所有文件,WatchService 会对文件删除操作做出反应:
// files/PathWatcher.java // {ExcludeFromGradle} import java.io.IOException; import java.nio.file.*; import static java.nio.file.StandardWatchEventKinds.*; import java.util.concurrent.*; public class PathWatcher { static Path test = Paths.get("test"); static void delTxtFiles() { try { Files.walk(test) .filter(f -> f.toString() .endsWith(".txt")) .forEach(f -> { try { System.out.println("deleting " + f); Files.delete(f); } catch(IOException e) { throw new RuntimeException(e); } }); } catch(IOException e) { throw new RuntimeException(e); } } public static void main(String[] args) throws Exception { 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); } } } /* Output: deleting test\bag\foo\bar\baz\File.txt deleting test\bar\baz\bag\foo\File.txt deleting test\baz\bag\foo\bar\File.txt deleting test\foo\bar\baz\bag\File.txt deleting test\Hello.txt evt.context(): Hello.txt evt.count(): 1 evt.kind(): ENTRY_DELETE */
文件查找
到目前为止,为了找到文件,我们一直使用相当粗糙的方法,在 path
上调用 toString()
,然后使用 string
操作查看结果。事实证明,java.nio.file
有更好的解决方案:通过在 FileSystem
对象上调用 getPathMatcher()
获得一个 PathMatcher
,然后传入您感兴趣的模式。模式有两个选项:glob
和 regex
。glob
比较简单,实际上功能非常强大,因此您可以使用 glob
解决许多问题。如果您的问题更复杂,可以使用 regex
,这将在接下来的 Strings
一章中解释。
在这里,我们使用 glob
查找以 .tmp
或 .txt
结尾的所有 Path
:
// files/Find.java // {ExcludeFromGradle} import java.nio.file.*; public class Find { public static void main(String[] args) throws Exception { Path test = Paths.get("test"); Directories.refreshTestDir(); Directories.populateTestDir(); // Creating a *directory*, not a file: 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) // Only look for files .filter(Files::isRegularFile) .map(Path::getFileName) .filter(matcher2::matches) .forEach(System.out::println); } } /* Output: test\bag\foo\bar\baz\5208762845883213974.tmp test\bag\foo\bar\baz\File.txt test\bar\baz\bag\foo\7918367201207778677.tmp test\bar\baz\bag\foo\File.txt test\baz\bag\foo\bar\8016595521026696632.tmp test\baz\bag\foo\bar\File.txt test\dir.tmp test\foo\bar\baz\bag\5832319279813617280.tmp test\foo\bar\baz\bag\File.txt *************** 5208762845883213974.tmp 7918367201207778677.tmp 8016595521026696632.tmp dir.tmp 5832319279813617280.tmp *************** 5208762845883213974.tmp 7918367201207778677.tmp 8016595521026696632.tmp 5832319279813617280.tmp */
在 matcher
中,glob
表达式开头的 **/
表示“当前目录及所有子目录”,这在当你不仅仅要匹配当前目录下特定结尾的 Path
时非常有用。单 *
表示“任何东西”,然后是一个点,然后大括号表示一系列的可能性---我们正在寻找以 .tmp
或 .txt
结尾的东西。您可以在 getPathMatcher()
文档中找到更多详细信息。
matcher2
只使用 *.tmp
,通常不匹配任何内容,但是添加 map()
操作会将完整路径减少到末尾的名称。
注意,在这两种情况下,输出中都会出现 dir.tmp
,即使它是一个目录而不是一个文件。要只查找文件,必须像在最后 files.walk()
中那样对其进行筛选。
文件读写
文件很小的话
// files/ListOfLines.java import java.util.*; import java.nio.file.*; public class ListOfLines { public static void main(String[] args) throws Exception { Files.readAllLines( Paths.get("../streams/Cheese.dat")) .stream() .filter(line -> !line.startsWith("//")) .map(line -> line.substring(0, line.length()/2)) .forEach(System.out::println); } } /* Output: Not much of a cheese Finest in the And what leads you Well, it‘s It‘s certainly uncon */
跳过注释行,其余的内容每行只打印一半。 这实现起来很简单:你只需将 Path
传递给 readAllLines()
(以前的 java 实现这个功能很复杂)。readAllLines()
有一个重载版本,包含一个 Charset
参数来存储文件的 Unicode 编码。
// files/Writing.java import java.util.*; import java.nio.file.*; public class Writing { static Random rand = new Random(47); static final int SIZE = 1000; public static void main(String[] args) throws Exception { // Write bytes to a file: byte[] bytes = new byte[SIZE]; rand.nextBytes(bytes); Files.write(Paths.get("bytes.dat"), bytes); System.out.println("bytes.dat: " + Files.size(Paths.get("bytes.dat"))); // Write an iterable to a file: List<String> lines = Files.readAllLines( Paths.get("../streams/Cheese.dat")); Files.write(Paths.get("Cheese.txt"), lines); System.out.println("Cheese.txt: " + Files.size(Paths.get("Cheese.txt"))); } } /* Output: bytes.dat: 1000 Cheese.txt: 199 */
如果文件大小有问题怎么办? 比如说:
文件太大,如果你一次性读完整个文件,你可能会耗尽内存。
您只需要在文件的中途工作以获得所需的结果,因此读取整个文件会浪费时间。
Files.lines()
方便地将文件转换为行的 Stream
:
流是很快的,且可控,这个例子就蛮不错的
// files/StreamInAndOut.java import java.io.*; import java.nio.file.*; import java.util.stream.*; public class StreamInAndOut { public static void main(String[] args) { try( Stream<String> input = Files.lines(Paths.get("StreamInAndOut.java")); PrintWriter output = new PrintWriter("StreamInAndOut.txt") ) { input.map(String::toUpperCase) .forEachOrdered(output::println); } catch(Exception e) { throw new RuntimeException(e); } } }
切记,不要再用以前的java IO了,直接上手NIO,Files这个类很强
标签:count 文件查找 pen 解决方案 views stream 怎么 delete 结果
原文地址:https://www.cnblogs.com/CherryTab/p/11973704.html