java-IO

字节流:InputStream, OutputStream

字符流:Reader, Writer

File

表示文件和目录路径,以及创建、删除文件和目录。

3种路径形式

File f = new File("../zc/src/Main.java");

f.getPath();//返回构造方法传入的路径  ..\zc\src\Main.java
f.getAbsolutePath();//返回绝对路径  D:\code\java\zc\..\zc\src\Main.java
f.getCanonicalPath();//和绝对路径类似,但是返回的是规范路径  D:\code\java\zc\src\Main.java

文件和目录属性

boolean isDirectory();
boolean canRead();
boolean canWrite();
boolean canExecute();//对目录而言,是否可执行表示能否列出它包含的文件和子目录
long length();//文件字节大小

创建和删除文件

//新建文件
//返回true(文件不存在,且创建成功)
//返回false(文件已存在)
//throws IOException(创建文件错误)
boolean createNewFile() throws IOException;
//删除文件或目录(目录需要为空)
//返回true(删除成功)
//返回false(删除失败)
boolean delete();

创建临时文件:

/* 如果前缀小于3个字符,则异常 */
// 提供临时文件的前缀和后缀,使用系统的临时文件目录
File f = File.createTempFile("tmp-", ".txt");
// 提供临时文件的前缀和后缀,指定临时文件存放目录(目录必须存在)
File f2 = File.createTempFile("tmp-", ".txt", new File("./tmp"));

// JVM退出时自动删除
f.deleteOnExit();
System.out.println(f.getAbsolutePath());//C:\Users\zc\AppData\Local\Temp\tmp-4816163966082070967.txt

创建和删除目录

boolean mkdir(); //创建当前File对象表示的目录
boolean mkdirs();//创建当前File对象表示的目录,并在必要时将不存在的父目录也创建出来
boolean delete();//删除当前File对象表示的目录,当前目录必须为空才能删除成功

遍历文件和目录

String[] list();//返回当前目录下的所有文件和目录,名字数组
String[] list(FilenameFilter filter);//指定过滤规则

File[] listFiles();//返回当前目录下的所有文件和目录,File数组
File[] listFiles(FilenameFilter filter);//指定过滤规则
File[] listFiles(FileFilter filter);//指定过滤规则

过滤规则:

public interface FilenameFilter {
    boolean accept(File dir, String name);
}

public interface FileFilter {
    boolean accept(File pathname);
}

Path

Java标准库还提供了一个Path对象,它位于java.nio.file包。Path对象和File对象类似,但操作更加简单:

Path只表示文件和目录的路径,没有创建和删除等能力。

Path p1 = Paths.get(".", "project", "study"); // 构造一个Path对象
System.out.println(p1); // .\project\study

Path p2 = p1.toAbsolutePath(); // 转换为绝对路径
System.out.println(p2); // D:\code\java\zc\.\project\study

Path p3 = p2.normalize(); // 转换为规范路径
System.out.println(p3); // D:\code\java\zc\project\study

File f = p3.toFile(); // 转换为File对象
System.out.println(f); // D:\code\java\zc\project\study

/* 遍历Path中每个子路径
 * >code
 * >java
 * >zc
 * >project
 * >study
 */
for (Path p : p3) {
    System.out.println(">" + p);
}

常用的流分类

分类字节输入流字节输出流字符输入流字符输出流
抽象基类InputStreamOutputStreamReaderWriter
访问文件FileInputStreamFileOutputStreamFileReaderFileWriter
访问数组ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter
访问管道PipedInputStreamPipedOutputStreamPipedReaderPipedWriter
访问字符串StringReaderStringWriter
缓冲流BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter
转换流InputStreamReaderOutputStreamWriter
对象流ObjectInputStreamObjectOutputStream
过滤类(作基类用)FilterInputStreamFilterOutputStreamFilterReaderFilterWriter
打印流PrintStreamPrintWriter
推回输入流PushbackInputStreamPushbackReader
特殊流DataInputStreamDataOutputStream

(1)流的分类:

  1. 输入流 - 输出流
  2. 字节流 - 字符流
  3. 节点流 - 处理流

节点流:提供数据源的流。

处理流:用于对一个已存在的流进行连接或封装,通过封装后的流来实现数据读/写功能。

(2)PrintStream和PrintWriter区别:

2个类的功能基本相同,PrintStream能做的PrintWriter也都能实现,并且PrintWriter的功能更为强大。但是由于PrintWriter出现的比较晚,较早的System.out使用的是PrintStream来实现的,所以为了兼容就没有废弃PrintStream。

PrintStream在输出字符,将字符转换为字节时采用的是系统默认的编码格式。而PrintWriter可以在传入Writer时OutputStreamWriter(OutputStream out, Charset cs)可由程序员指定字符转换为字节时的编码格式。

try(resource)语法

Java 7引入的新的try(resource)的语法,只需要编写try语句,让编译器自动为我们关闭资源。

实际上,编译器并不会特别地为InputStream加上自动关闭。编译器只看try(resource = ...)中的对象是否实现了java.lang.AutoCloseable接口,如果实现了,就自动加上finally语句并调用close()方法。InputStreamOutputStream都实现了这个接口,因此,都可以用在try(resource)中。

关于flush()

OutputStream什么时候自动调用flush():缓冲区满、调用close()时。

读写文件

手动逐行读

static void f1() {
    try (
            InputStream is = new FileInputStream("./src/Main.java");
            InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
            BufferedReader br = new BufferedReader(isr)
    ) {
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
    } catch (IOException e) {
        System.out.println("发生错误");
    }
}

手动逐行写

static void f2() {
    try (
            OutputStream os = new FileOutputStream("./src/z.txt");
            OutputStreamWriter osw = new OutputStreamWriter(os, StandardCharsets.UTF_8);
            BufferedWriter bw = new BufferedWriter(osw)
    ) {
        bw.write("one");
        bw.newLine();
        bw.write("two");
    } catch (IOException e) {
        System.out.println("发生错误");
    }
}

一次性读

一次性读文件:自己创建好数组

//一次性读文件:自己创建好数组
static String readToString(String file) throws IOException {
    //获取文件大小
    long fileLength = new File(file).length();
    //创建数组
    byte[] fileContent = new byte[(int) fileLength];
    //文件 -> byte[]
    try (FileInputStream fis = new FileInputStream(file)) {
        fis.read(fileContent); //读文件
    }
    //byte[] -> String
    return new String(fileContent, StandardCharsets.UTF_8);
}

一次性读文件:让库返回数组(更好方案)

//一次性读文件:让库返回数组(更好方案)
static String readToString2(String file) throws IOException {
    //文件 -> byte[]
    byte[] result = Files.readAllBytes(Paths.get(file));
    //byte[] -> String
    return new String(result, StandardCharsets.UTF_8);
}

一次性写

static void writeFromString2(String file, String content) throws IOException {
    //String -> byte[]
    byte[] data = content.getBytes(StandardCharsets.UTF_8);
    //byte[] -> 文件
    Files.write(Paths.get(file), data);
}

按行读写

//按行读
List<String> lines = Files.readAllLines(Paths.get("in.txt"), StandardCharsets.UTF_8);
//按行写
Files.write(Paths.get("out.txt"), lines, StandardCharsets.UTF_8);

自定义封装InputStream

下面的例子演示了如何编写一个CountInputStream,它的作用是对输入的字节进行计数:

public class Main {
    public static void main(String[] args) throws IOException {
        byte[] data = "hello, world!".getBytes("UTF-8");
        try (CountInputStream input = new CountInputStream(new ByteArrayInputStream(data))) {
            int n;
            while ((n = input.read()) != -1) {
                System.out.println((char)n);
            }
            System.out.println("Total read " + input.getBytesRead() + " bytes");
        }
    }
}

// 为什么是继承 FilterInputStream,因为它已经帮我们实现了基本方法,并包含了内部 InputStream
class CountInputStream extends FilterInputStream {
    private int count = 0;

    CountInputStream(InputStream in) {
        super(in);
    }

    public int getBytesRead() {
        return this.count;
    }

    public int read() throws IOException {
        int n = in.read();
        if (n != -1) {
            this.count ++;
        }
        return n;
    }

    public int read(byte[] b, int off, int len) throws IOException {
        int n = in.read(b, off, len);
        if (n != -1) {
            this.count += n;
        }
        return n;
    }
}

读取classpath资源

Java存放.class的目录或jar包也可以包含任意其他类型的文件,从classpath读取文件就可以避免不同环境下文件路径不一致的问题:如果我们把default.properties文件放到classpath中,就不用关心它的实际存放路径。

在classpath中的资源文件,路径总是以开头,调用Class.getResourceAsStream()就可以直接从classpath读取任意的资源文件,需要特别注意的一点是,如果资源文件不存在,它将返回null。因此,我们需要检查返回的InputStream是否为null,如果为null,表示资源文件在classpath中没有找到:

try (InputStream input = getClass().getResourceAsStream("/com/zc/demo/default.properties")) {
    if (input != null) {
        // TODO:
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值