概念

  • I :input
  • O:output
  • java.io.* 包
  • 通过IO可以完成对硬盘的读和写

字节流

  • 万能流,一次读一个字节(byte) = 8个二进制位
  • 啥都能读取

字符流

  • 一次读一个字符
  • 只能读纯文本文件 .txt

区分

  • 在Java中类名以Stream结尾的都是字节流
  • 以Writer/Reader结尾的都是字符流

所有的流都实现了Closeable接口,都是可以关闭的

  • 流用完一定要关

所有的输出流都实现了Flushable接口,都是可刷新的

  • 最后输出之后一定要flush()刷新一下(清空管道)

image.png

IO四大家族(都是抽象类)

  • java.io.InputStream 字节输入流
  • java.io.OutputStream 字节输出流
  • java.io.Reader 字符输入流
  • java.io.Writer 字符输出流

文件复制原理

image.png

需要掌握的流

文件专属流

  • java.io.FileInputStream
  • java.io.FileOutputStream
  • java.io.FileReader
  • java.io.FileWriter

转换流
(将字节流转换成字符流)

  • java.io.InputStreamReader
  • java.io.OutputStreamWriter

缓冲流专属

  • java.io.BufferedReader
  • java.io.BufferedWriter
  • java.io.BufferedInputStream
  • java.io.BufferedOutputStream

数据流专属

  • java.io.DataInputStream
  • java.io.DataOutputStream

标准输出流

  • java.io.PrintWriter
  • java.io.PrintStream

对象专属流

  • java.io.ObjectInputStream
  • java.io.ObjectOutputStream

File In/Out putStream

万能流,所有文件都可以用来读

int read() 读取第一个字节(每调用一次向下移一个)
int i = stream.read();
返回一个ascll码 读到末尾 ,读不到了就返回-1

int available() 返回流当中剩余的没有读到的字节数量

作用:一上来就可以获取它的总字节数量

int i = stream.available();
long skip() 跳过几个字节不读

用while循环读取文件

  1. FileInputStream s = null;
  2. try {
  3. s = new FileInputStream("I_O/src/FileInputStreamTast01/My");
  4. byte[] bytes = new byte[14]; int i1 = 0 ;
  5. while( (i1 = s.read(bytes)) != -1){
  6. System.out.println(i1);
  7. }
  8. } catch (FileNotFoundException e) {
  9. e.printStackTrace();
  10. } catch (IOException e) {
  11. e.printStackTrace();
  12. } finally{
  13. if (s != null) {
  14. try {
  15. s.close();
  16. } catch (IOException e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. }

FileOutputStream
写完一定要flush() 刷新一下
构造方法里跟一个地址(只有地址)
会把地址里面的文件清空,后写入
构造方法里跟一个地址,true 表示追加写入

write() 写入
write(byte[]数组,开始下标,结束下标) 写入指定长度的文件

文件复制

FileInputStream in = null;
FileOutputStream out = null;
try {
    in = new FileInputStream("E:\\仝子瑜\\tongziyu.jpg"); //创建输入流
    out = new FileOutputStream("E:\\tongziyu.jpg"); //创建输出流
    byte[] bytes = new byte[1024];
    int i = 0;
    while ((i = in.read(bytes)) != -1){ //读文件
        out.write(bytes,0,i); //写文件
    }
    out.flush(); //刷新一下
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally{
    if (in != null) {
        try {
            in.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
if (out != null) {
    try {
        out.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
}

FileReader

一次读取一个字符,只能读取普通文本文件
char数组接收
和FileInputStream差不多,就是用char[]数组接收数据

FileWriter
一个写入一个字符 “a/中”
引用.flush() 刷新不要忘

BufferedReader/PrintStream

BufferedReader概念

  1. 带有缓冲区的字符输入流
  2. 使用时不惜要byte[] 或者 char[] 数组 自带缓冲
  3. 当一个流(包装流,处理流)的构造方法需要传进去一个流(节点流)的时候
  4. 关闭流时只需要管理包装流即可

String readLine() // 读取一行
String s = 引用.readLine();
读不到内容时会返回null
bufferedReader的构造方法里只能跟字符流
如果要用字节流,就需要转换流

转换流
FileInputStream in = new FileInputStream("路径"); //字节流
InputStreamReady ready  = new InputStreamReady(in);  // 转换成字符流

使用缓冲字符输入流读文件

    BufferedReader s = null;
    FileReader reader = null;
    try {
        reader = new FileReader("E:\\java\\Java 资料\\JAVA语法.TXT");
        s = new BufferedReader(reader);
        String s5 = null;
        // 因为 readLine() 在都不到的情况下会返回null  由此判断
        while ((s5 = s.readLine()) != null ){     
            System.out.println(s5);
        }
    }

PrintStream

  • 标准输出字节
  • 不需要使用close()关闭
  • 标准输出流是指不再向控制台输出,而是指向这个文件输出↓
  • PrintStream ps = new PrintStream(new FileOutputStream(“log”))
  • System.setOut(ps); // 改变输出方向
  • System.out.println(“HelloWorld”); // 不会输出到控制台,会输出到log文件里

File类

和四大家族无关,所以不能读和写

file对象
  • 可能对应的是一个目录,或者文件
  • 只是一个路径名的抽象表示形式

掌握File类的常用方法

  1. File s = new File(“路径”) // 创建file对象
  2. boolean exists(); //判断是否存在
  3. boolean mkdir() //以目录形式新建
  4. boolean mddirs() //以多重目录新建
  5. File getAbsoluteFile() //获取绝对路径
  6. String getParent() //获取父路径
  7. String getName() //获取文件名

序列化

image.png

  • 序列化:Serialize
  • 反序列化:DeSerialize

参与序列化的和反序列化的对象必须都要实现Serializable接口
Serializable只是一个标志性接口,里面没有任何代码

在java中如何区分一个类
  • 类名
  • 序列化版本号(实现Serializeble接口)

    Jvm会自动给这个类一个序列化版本号<br />但是后期修改代码的时候,序列化版本号也会自动修改<br />**所以建议给一个不变的序列化版本号:**<br />private static final long serialVersionVID = ~~~L; //可参考源码
    

序列化多个对象,创建一个list集合,对象放进去,序列化集合即可
transient关键字(不参加序列化操作)

  • 例如private transient String name;
  • 表示序列化多个对象,创建一个e不参加序列化操作

writeObject(对象或者引用); // 序列化
readObject (); 反序列化

    ObjectOutputStream s = null;
    ObjectInputStream a = null;
    try {
        /*  s = new ObjectOutputStream(new FileOutputStream("E:\\asd.TXT"));
                 s.writeObject(1);*/   // 序列化对象
        a = new ObjectInputStream(new FileInputStream("E:\\asd.TXT"));
        Object s1 = a.readObject();  //反序列化
        System.out.println(s1);  
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally{
        /*try {
                    *//*s.close();*//*
                } catch (IOException e) {
                    e.printStackTrace();
                }*/
    }

路径问题

获取文件绝对路径
以前
FileReader reader = new FileReader(“thread/peizhi”)
这种路径的缺点是:移植性差,在IDEA中默认的当前路径是project的根
假设离开了IDEA换到了其他位置,可能当前路径就不是当前project的根了,此时路径无效
通用
只适合文件放在类路径下的
什么是类路径:凡是在src下的都是类路径下
src是类的根路径
String path = Thread.currentThread().getContextClassLoader().getResource(“classinfo.properties”).getPath();
解释:

  • Thread.currentThread() // 得到当前线程对象
  • getContextClassLoader() // 是线程对象的方法,可以获取到当前线程的类加载器对象。
  • getResource() // 是类加载器的方法,当前线程的类加载器默认从类的根路径下加载资源。
    适用于 linux系统

直接以流的方式返回

InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("classinfo.properties");

直接返回一个InputStream流

资源绑定器

java.util.ResourceBundle 包下
实现
ResourceBundle resourceBundle = ResourceBundle.getBundle(“classinfo”);
通过key得到value
String value = resourceBundle.getString(“classname”);
// 得到对应的classname的value
注意

  • 这里的后缀一定要去掉
  • 只能绑定类路径下的配置文件(src下的 .properties文件)