IO

输入和输出

Java API中,可从中读入一个字节序列的对象叫输入流,可以写入一个直接对象成为输出流;

抽象类InputStreamOutputStreamI/O包的基础。

因为面向字节的流不便于处理Unicode编码信息,抽象出来ReaderWriter专门处理,衍生类的读去和写入操作都是基于两个字节的Char值的。

InputStream

操作内容
int read() throws IOException;读取并返回一个字节,结束返回-1
int available() throws IOException;返回可读入的字节数量

read其他方法都基于read()实现

OutputStream

操作内容
int write(int b) throws IOException;写入一个字节

write其他方法都基于write(int b)实现

阻塞

readwrite在执行时都将阻塞,直到字节确实被读入或写出。这意味着等待过程=线程阻塞。当完成操作后,应当调用close关闭I/O流。 对于任何Closeable接口可以使用try-with-resouce进行自动关闭操作.

结合 输入/输出流

文件流File{Input|Output}Stream提供了对磁盘文件的文件流。

java.io 中的类相对路径的解释以用户工作目录开始,通过System.getProperty("user.dir")查看

Java中的流可以嵌套使用,即继承之FilterInputStream/FilterOutputStream的类可用于向处理字节的流添加额外的功能。

    public static void main(String[] args) throws IOException {
        Path p = Paths.get(System.getProperty("user.dir"), "resources", "1.txt");
        InputStream inputStream = new FileInputStream(p.toFile());
        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
    }

文本流

Java内部使用UTF-16编码,即一个字符使用16位(2个字节)保存,字符串“1234”编码为(0031 0032 0033 0034).

OutputStreamWriter将输出流转换为字节流,InputStreamReader将字节流转换位Java可以理解的字符。

例如 从键盘获取一行输入

    public static void main(String[] args) throws IOException {
        try (
                BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        ) {
            String s = in.readLine();
            System.out.println(s);
        }
    }

写文本

文本输出,可使用PrintWriter对象,使用print,printlnprintf方法输出。

        try (PrintWriter out = new PrintWriter("1.txt", StandardCharsets.UTF_8.toString());) {
            out.println("hello world");
        }

读文本

使用Scanner读取文本输入,可以从InputStream构建,

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println(scanner.nextLine());
    }

早期Java版本,只能通过BufferedReaderreadLine获取下一行文本。

BufferedReader加入了一个lines方法,可以产生一个Stream<String>数组.

Scanner可以读取非字符串类型,而BufferedReader当前版本不可以。

文件API

Path

获取

Path表示一个路径,

通过静态方法Paths.get(String first, String... more)获取路径

路径不必对于某个实际存在的文件,它只是一个抽象的名称序列.

相对路解析

获取Path对象后,可调用resolve获得相对路径. resolveSibling得到同级兄弟目录

resolve的反向操作时relative 例如在/home/fred/myprog/home/cay调用relative会产生../fred/myprog

normalize删除冗余的...

toAbsoultPath产生绝对路径

getRoot 根路径 / D:\getFileName 文件(夹)名 getParent() 父路径 toFile 获得File对象

通过File对象的toPath可以获得Path对象

Files

读写文件

Files.readAllBytes读取一个文件的所有字节内容 List<String> readAllLines 获得所有行 newInputStream/newOutputStream/newBufferedReader/newBufferedWriter 从路径获得指定流 Files.write向指定路径写入字节

文件/目录创建

createDirectory 创建单个目录(要求目录前置目录以存在) createDirectories 创建目录(自动创建中间目录) createFile 创建文件(如果文件已存在,调用抛出异常, 检测和创建时原子操作) 临时文件创建 createTempDirectory/createTempFile

复制/移动/删除

File.copy复制 File.move移动 (覆盖使用 REPLACE_EXISTING, 复制文件属性 使用COPY_ATTRIBUTES)

Files.copy(f, f.resolveSibling("test.txt.cpy"), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);

File.delete(path) 删除(如果文件不存在,会抛出异常) File.deleteIfExists 如果存在才删除

获取文件信息

检测文件属性

exists 存在 notExists不存在 isReadableisWritableisExecutableisSymbolicLink 链接文件 isDirectoryisRegularFile 常规文件

size 文件字节数 getOwner文件所有者

readAttributes读取封装信息 例如获取基础属性

        BasicFileAttributes attributes =   Files.readAttributes(f, BasicFileAttributes.class);
        System.out.println(attributes);

BasicFileAttributes封装了lastModifiedTime等信息

目录检索

Stream<Path>list(Path dir) 返回一个路径流,目录读取是惰性的 list不会进入子目录 Stream<Path> walk可对目录中所有子目录进行检索(深度优先),可以指定深度。

目录流

newDirectoryStream可以产生一个目录流,它是专门用于遍历目录的接口,可以使用增强for循环.

public interface DirectoryStream<T>
    extends Closeable, Iterable<T>

这个方法可以使用glob来过滤文件,例如只要java结尾的文件

细粒度的控制

使用walkFileTree,传入一个FileVisitor

FileVisitor

preVisitDirectory 访问目录前

visitFile 访问文件

visitFileFailed 访问文件失败

postVisitDirectory 访问文件夹后

方法返回FileVisitResult枚举

Last Updated:
Contributors: himcs, himcs