我是靠谱客的博主 个性眼神,最近开发中收集的这篇文章主要介绍重拾Java基础知识:文件前言,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文件

  • 前言
    • File类
    • 文件和目录路径
      • 选取路径部分片段
      • 路径分析
      • Paths的增减修改
    • 目录
    • 文件系统
    • 路径监听
    • 文件查找
    • 文件读写
    • 本章小结

前言

IO流,也就是输入输出流,从文件出发到文件结束,至始至终都离不开文件,所以IO流还得从文件File类讲起。

File类

专门对文件进行操作的类,只能对文件本身进行操作,不能对文件内容进行操作,主要用于文件和目录的创建、查找和删除等操作。

public class NewFileTest {
    public static void main(String[] args) throws IOException {
        File file = new File("C:\mnt\test1");
        String[] list = file.list();//获取目录下的文件名
        File[] files = file.listFiles();//获取目录下的文件
        System.out.println("path:"+file.getPath());//获取路径
        System.out.println("absolutePath:"+file.getAbsolutePath());//获取绝对路径
        System.out.println("parent:"+file.getParent());//获取父文件
        file = new File("C:\mnt\test\t1");
        System.out.println("name:"+file.getName());//获取文件名
        System.out.println("isAbsolute:"+file.isAbsolute());//判断是不是绝对路径
        System.out.println("isHidden:"+file.isHidden());//判断是不是隐藏文件
        System.out.println("isDirectory:"+file.isDirectory());//判断是不是文件夹
        System.out.println("isFile:"+file.isFile());//判断是不是文件
        System.out.println("exists:"+file.exists());//判断文件或文件夹是否存在
        System.out.println("mkdir:"+file.mkdir());//创建单个文件夹(父级文件必须存在)
        System.out.println("mkdirs:"+file.mkdirs());//创建多层级文件夹
        file = new File("C:\mnt\test\t1\t.txt");
        System.out.println("createNewFile:"+file.createNewFile());//创建文件
        System.out.println("setReadOnly:"+file.setReadOnly());//设置文件为只读
        System.out.println("canRead:"+file.canRead());//判断文件是否可读
        System.out.println("canWrite:"+file.canWrite());//判断文件是否可写
        System.out.println("delete:"+file.delete());//立即删除
        file.deleteOnExit();//待jvm终止才进行删除
    }
}

执行结果

path:C:mnttest1
absolutePath:C:mnttest1
parent:C:mnt
name:t1
isAbsolute:true
isHidden:false
isDirectory:false
isFile:false
exists:false
mkdir:false
mkdirs:true
createNewFile:true
setReadOnly:true
canRead:true
canWrite:false
delete:true

由于 I/O 糟糕的设计以至于 很少有人能够在不依赖其他参考代码的情况下完成打开文件的操作。好像 Java 设计者终于意识到了 Java 使用者多年来的痛苦,在 Java7 中对此引入了巨大的改进。这些新元素被放在 java.nio.file 包下面,过去人们通常把 nio 中的 n 理解为 new 即新的 io,现在更应该当成是 non-blocking 非阻塞 io(io就是input/output输入/输出)。java.nio.file 库终于将 Java 文件操作带到与其他编程语言相同的水平。最重要的是 Java8 新增的 streams 与文件结合使得文件操作编程变得更加优雅。我们将看一下文件操作的两个基本组件:

  • 文件或者目录的路径;
  • 文件本身。

文件和目录路径

一个 Path 对象表示一个文件或者目录的路径,是一个跨操作系统(OS)和文件系统的抽象,目的是在构造路径时不必关注底层操作系统,代码可以在不进行修改的情况下运行在不同的操作系统上。java.nio.file.Paths 类包含一个重载方法 static get(),该方法接受一系列 String 字符串或一个统一资源标识符(URI)作为参数,并且进行转换返回一个 Path 对象:

public class NewFileTest {
    public static void main(String[] args) throws IOException, URISyntaxException {
//        Path path = Paths.get(new URI("D:\mnt"));
//        Path path = Paths.get("D:\mnt");
        Path path = Paths.get("D:","mnt","test.txt");
        System.out.println("转换为绝对路径:"+path.toAbsolutePath());
        System.out.println("转换为File:"+path.toFile());
        System.out.println("转换为URI:"+path.toUri());
        System.out.println("toString:"+path.toString());
        System.out.println("toRealPath:"+path.toRealPath());//实际地址
        System.out.println("root:"+path.getRoot());//获取根目录
        System.out.println("parent:"+path.getParent());//获取父目录
        System.out.println("fileName:"+path.getFileName());//获取文件名
        System.out.println("isAbsolute:"+path.isAbsolute());//判断是不是绝对路径
        System.out.println("isHidden:"+Files.isHidden(path));//判断是不是隐藏文件
        System.out.println("isDirectory:"+Files.isDirectory(path));//判断是不是文件夹
        System.out.println("isRegularFile:"+Files.isRegularFile(path));//判断是不是文件
        System.out.println("exists:"+Files.exists(path));//判断文件或文件夹是否存在
        path = Paths.get("D:","mnt","dic");
        System.out.println("createDirectory:"+Files.createDirectory(path));//创建单个文件夹(上一层文件夹不存在,则抛异常)
        path = Paths.get("D:","mnt","dic","t1");
        System.out.println("createDirectories:"+Files.createDirectories(path));//创建多层级文件夹
        Path createTempFile = Files.createTempFile("test", ".txt");
        System.out.println("createTempFile:"+createTempFile);//创建临时文件,返回临时文件地址
        path = Paths.get("D:","mnt","dic","this.txt");
        System.out.println("createFile:"+Files.createFile(path));//创建文件
        System.out.println("deleteIfExists:"+Files.deleteIfExists(createTempFile));//删除存在的文件
        Files.list(Paths.get("D:","mnt")).forEach(item-> System.out.println(item.toString()));//遍历路径下所有文件
    }
}

执行结果

转换为绝对路径:D:mnttest.txt
转换为File:D:mnttest.txt
转换为URI:file:///D:/mnt/test.txt
toString:D:mnttest.txt
toRealPath:D:mnttest.txt
root:D:
parent:D:mnt
fileName:test.txt
isAbsolute:true
isHidden:false
isDirectory:false
isRegularFile:true
exists:true
createDirectory:D:mntdic
createDirectories:D:mntdict1
createTempFile:C:UsersShancwAppDataLocalTemptest2955572342747349825.txt
createFile:D:mntdicthis.txt
deleteIfExists:true
D:mntdic
D:mnttest.txt
D:mnttest1.txt

上面的例子,通过使用 Files 工具类(我们接下来将会更多地使用它),可以测试一个文件是否存在,测试是否是一个"普通"文件还是一个目录等等。

选取路径部分片段

Path 对象可以非常容易地生成路径的某一部分:

public class NewFileTest {
    public static void main(String[] args) {
        Path path = Paths.get("D:\mnt\dic\t1").toAbsolutePath();
        System.out.println("getNameCount:"+path.getNameCount());
        for (int i = 0; i < path.getNameCount(); i++) {
            System.out.println(path.getName(i));
        }
//        for (Path p:path) {
//            //todo
//        }
        System.out.println("startsWith:"+path.startsWith(path.getRoot()));
        System.out.println("endsWith:"+path.endsWith("t1"));
        /** Output:
		 * getNameCount:3
		 * mnt
		 * dic
		 * t1
		 * startsWith:true
		 * endsWith:true
		 */
    }
}

Path 也实现了 Iterable 接口,,因此我们也可以通过增强的 for-each 进行遍历,遍历 Path 对象并不包含根路径,startsWith()endsWith() 可以检测路径的开始和结尾,只有匹配时才会返回true

路径分析

在文章最开始介绍了一些基本的用法,接着继续介绍:

public class NewFileTest {
    public static void main(String[] args) throws IOException, URISyntaxException {
        Path path = Paths.get("D:","mnt","test.txt");
        System.out.println("isExecutable:"+Files.isExecutable(path));//判断是否是可执行文件
        System.out.println("isReadable:"+Files.isReadable(path));//判断是否是可读文件
        System.out.println("isWritable:"+Files.isWritable(path));//判断是否是可写文件
        System.out.println("isRegularFile:"+Files.isRegularFile(path));//判断是否是常规文件
        System.out.println("isSymbolicLink:"+Files.isSymbolicLink(path));//判断地址是不是符号链接
        System.out.println("size:"+Files.size(path));//文件大小(字节)
        System.out.println("getFileStore:"+Files.getFileStore(path));//获取文件存储位置
        System.out.println("getLastModifiedTime:"+Files.getLastModifiedTime(path));//获取文件最后一次修改时间
        System.out.println("getOwner:"+Files.getOwner(path));//获取文件所有权信息
        System.out.println("probeContentType:"+Files.probeContentType(path));//获取文件内容类型
		/** Output:
		 * isExecutable:true
		 * isReadable:true
		 * isWritable:true
		 * isRegularFile:true
		 * isSymbolicLink:false
		 * size:41
		 * getFileStore:Data (D:)
		 * getLastModifiedTime:2022-01-23T14:52:32.339137Z
		 * getOwner:LAPTOP-33SV7QS9Shancw (User)
		 * probeContentType:text/plain
		 */
    }
}

Paths的增减修改

我们必须能通过对 Path 对象增加或者删除一部分来构造一个新的 Path 对象。我们使用 relativize() 构造两个路径之间的相对路径,使用 resolve() 添加 Path 的尾路径,使用normalize()标准化输出。

public class NewFileTest {
    public static void main(String[] args) {
        Path p = Paths.get("Test.java").toAbsolutePath();
        System.out.println(p);
        Path resolve = p.resolve("..");
        System.out.println(resolve);
        System.out.println(resolve.normalize());
        Path study = resolve.relativize(Paths.get("D:\abc"));
        System.out.println(study);
        /** Output:
		 * D:studyTest.java
		 * D:studyTest.java..
		 * D:study
		 * ......abc
		 */
    }
}

目录

Files 工具类包含大部分我们需要的目录操作和文件操作方法。

public class NewFileTest {
    public static void main(String[] args) throws IOException {
        Path p = Paths.get("D:","mnt","test.txt");
         Files.walkFileTree(p, new SimpleFileVisitor(){
            @Override
            public FileVisitResult postVisitDirectory(Object dir, IOException exc) throws IOException {
                System.out.println("1 "+dir);
                return super.postVisitDirectory(dir, exc);
            }

            @Override
            public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs) throws IOException {
                System.out.println("2 "+dir);
                return super.preVisitDirectory(dir, attrs);
            }

            @Override
            public FileVisitResult visitFile(Object file, BasicFileAttributes attrs) throws IOException {
                System.out.println("3 "+file);
                return super.visitFile(file, attrs);
            }

            @Override
            public FileVisitResult visitFileFailed(Object file, IOException exc) throws IOException {
                System.out.println("4 "+file);
                return super.visitFileFailed(file, exc);
            }
        });
		/** Output:
		 * 3 D:mnttest.txt
		 */
    }
}

删除目录树的方法实现依赖于 Files.walkFileTree(),“walking” 目录树意味着遍历每个子目录和文件。Visitor 设计模式提供了一种标准机制来访问集合中的每个对象,然后你需要提供在每个对象上执行的操作。 此操作的定义取决于实现的 FileVisitor 的四个抽象方法,包括:

  1. preVisitDirectory():在访问目录中条目之前在目录上运行。
  2. visitFile():运行目录中的每一个文件。
  3. visitFileFailed():调用无法访问的文件。
  4. postVisitDirectory():在访问目录中条目之后在目录上运行,包括所有的子目录。

文件系统

为了完整起见,我们需要一种方法查找文件系统相关的其他信息。在这里,我们使用静态的 FileSystems 工具类获取"默认"的文件系统,但你同样也可以在 Path 对象上调用 getFileSystem() 以获取创建该 Path 的文件系统。你可以获得给定 URI 的文件系统,还可以构建新的文件系统(对于支持它的操作系统)。

public class NewFileTest {
    public static void main(String[] args) throws IOException {
        Path p = Paths.get("D:","mnt","test.txt");
        System.out.println(System.getProperty("os.name"));
        System.out.println(p.getFileSystem());
        /** Output: 
         * Windows 10
         * sun.nio.fs.WindowsFileSystem@29453f44
         */
    }
}

路径监听

通过 WatchService 可以设置一个进程对目录中的更改做出响应。

public class NewFileTest {
    public static void main(String[] args) throws IOException, InterruptedException {
        Path p = Paths.get("D:","mnt");
        WatchService watchService = FileSystems.getDefault().newWatchService();
        p.register(watchService, ENTRY_DELETE);
        Executors.newSingleThreadScheduledExecutor()
                .schedule(NewFileTest::del,
                250, TimeUnit.MILLISECONDS);
        WatchKey key = watchService.take();
        for(WatchEvent evt : key.pollEvents()) {
            System.out.println("evt.context(): " + evt.context() +
                    "nevt.count(): " + evt.count() +
                    "nevt.kind(): " + evt.kind());
            System.exit(0);
        }
    }
    static void del(){
        System.out.println("delete");
    }
}

一旦我们从 FileSystem 中得到了 WatchService 对象,我们将其注册到 mnt 路径以及我们感兴趣的项目的变量参数列表中,可以选择 ENTRY_CREATEENTRY_DELETEENTRY_MODIFY(其中创建和删除不属于修改)。接下来对 watcher.take() 的调用会在发生某些事情之前停止所有操作。Executors.newSingleThreadScheduledExecutor() 产生一个 ScheduledExecutorService 对象,然后调用 schedule() 方法传递所需函数的方法引用,并且设置在运行之前应该等待的时间。此时,watcher.take() 将等待并阻塞在这里。当目标事件发生时,会返回一个包含 WatchEventWatchkey 对象。展示的这三种方法是能对 WatchEvent 执行的全部操作。

文件查找

到目前为止,为了找到文件,我们一直使用相当粗糙的方法,在 path 上调用 toString(),然后使用 string 操作查看结果。事实证明,java.nio.file 有更好的解决方案:通过在 FileSystem 对象上调用 getPathMatcher() 获得一个 PathMatcher,然后传入您感兴趣的模式。模式有两个选项:globregexglob 比较简单,实际上功能非常强大,因此您可以使用 glob 解决许多问题。如果您的问题更复杂,可以使用 regex

public class NewFileTest {
    public static void main(String[] args) throws IOException{
        Path p = Paths.get("D:","mnt");
        PathMatcher matcher = FileSystems.getDefault()
                .getPathMatcher("glob:**/*.{tmp,txt}");
        Files.walk(p)
                .filter(matcher::matches)
                .forEach(System.out::println);
    }
        /** Output: 
         * D:mntdicthis.txt
         * D:mnttest.txt
         * D:mnttest1.txt
         */
}

在 matcher 中,glob 表达式开头的 **/ 表示“当前目录及所有子目录”,这在当你不仅仅要匹配当前目录下特定结尾的 Path 时非常有用。单 * 表示“任何东西”,然后是一个点,然后大括号表示一系列的可能性—我们正在寻找以 .tmp 或 .txt 结尾的东西。您可以在 getPathMatcher() 文档中找到更多详细信息。

文件读写

此时,我们可以对路径和目录做任何事情。 现在让我们看一下操纵文件本身的内容。如果一个文件很“小”,也就是说“它运行得足够快且占用内存小”,那么 java.nio.file.Files 类中的实用程序将帮助你轻松读写文本和二进制文件。Files.readAllLines() 一次读取整个文件(因此,“小”文件很有必要),乱码时或许你需要通过Charset来指定你的编码格式,产生一个List
Files.write() 被重载以写入。byte 数组或任何 Iterable 对象(它也有 Charset 选项):

public class NewFileTest {
    public static void main(String[] args) throws IOException, InterruptedException {
        Path p = Paths.get("D:","mnt","test.txt");
        Files.write(p,"hello,world!!!".getBytes());
        Files.readAllLines(p,Charset.forName("utf-8")).forEach(System.out::print);
        /** Output:
         *  hello world!!!!
         */
    }
}

本章小结

Java 7 和 8 对于处理文件和目录的类库做了大量改进。当你真正熟练掌握时,这对你的代码编写有很大的提高。

最后

以上就是个性眼神为你收集整理的重拾Java基础知识:文件前言的全部内容,希望文章能够帮你解决重拾Java基础知识:文件前言所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部