IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【学习笔记】Java基础知识点——第9章·IO流 -> 正文阅读

[Java知识库]【学习笔记】Java基础知识点——第9章·IO流

第9章 ?IO流?

9.1 ?Java流概述

9.1.1 InputStream和OutStream继承结构图:

?9.1.2 Reader和Writer继承结构图:

9.1.3 IO流的分类

有多种分类方式:

????????一种方式是按照流的方向进行分类:以内存作为参照物,

????????????????????????①往内存中去,叫做输入(Input)。或者叫做读(Read)。

????????????????????????②从内存中出来,叫做输出(Output)。或者叫做写(Write)。

????????另一种方式是按照读取数据方式不同进行分类:

????????????????????????①有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。

????????????????????????????????????????这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频文件等....

????????????????????????????????????????假设文件file1.txt,采用字节流的话是这样读的:a中国bc张三fe

????????????????????????????????????????????????????????第一次读:一个字节,正好读到'a'。

????????????????????????????????????????????????????????第二次读:一个字节,正好读到'中'字符的一半。

????????????????????????????????????????????????????????第三次读:一个字节,正好读到'中'字符的另外一半。

????????????????????????②有的流是按照字符的方式读取数据的,一次读取一个字符,

????????????????????????????????????????这种流是为了方便读取普通文本文件而存在的,这种流只能读取纯文本(word文档不属于纯文本)。

????????????????????????????????????????假设文件file1.txt,采用字符流的话是这样读的:?a中国bc张三fe

????????????????????????????????????????????????第一次读:'a'字符('a'字符在windows系统中占用1个字节。)

????????????????????????????????????????????????第二次读:'中'字符('中'字符在windows系统中占用2个字节。)

9.1.4 IO流的四大家族:

在java中只要类名以“Stream”结尾的都是字节流。以“Reader/Writer”结尾的都是字符流。

  1. java.io.InputStream ?字节输入流
  2. java.io.OutputStream 字节输出流
  3. java.io.Reader 字符输入流
  4. java.io.Writer 字符输出流

所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费(占用)很多资源。养成好习惯,用完流一定要关闭。

所有的输出流都实现了:java.io.Flushable接口,都是可刷新的,都有flush()方法。养成一个好习惯,输出流在最终输出之后,一定要记得flush()刷新一下。这个刷新表示将通道/管道当中剩余未输出的数据强行输出完(清空管道!)刷新的作用就是清空管道。注意:如果没有flush()可能会导致丢失数据。

9.1.5 java.io包下需要掌握的16个流:

文件专属:

  • 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(掌握)

9.1.6 InputStream(字节输入流)

  1. abstract int read() 从输入流读取下一个数据字节。
  2. int read(byte[] b) 从输入流中读取一定数量的字节并将其存储在缓冲区数组 b 中。
  3. int read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入字节数组。

9.1.7 OutputStream(字节输出流)

  1. void write(byte[] b) 将 b.length 个字节从指定的字节数组写入此输出流。
  2. void write(byte[] b, int off, int len) 将指定字节数组中从偏移量 off 开始的 len 个字节写入此输出流。
  3. abstract void write(int b) 将指定的字节写入此输出流。

9.1.8 Reader(字符输入流)

  1. int read() 读取单个字符。
  2. int read(char[] cbuf) 将字符读入数组。
  3. abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。

9.1.9 Writer(字符输出流)

  1. Writer append(char c) 将指定字符追加到此 writer。
  2. void write(char[] cbuf) 写入字符数组。
  3. abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。
  4. void write(int c) 写入单个字符。

9.2 ?文件流

9.2.1 FileInputStream(文件字节输入流)

FileInputStream类的其他常用方法:

  • int available():返回流当中剩余没有读到的字节数量。
  • long skip(long n):跳过几个字节不读。
FileInputStream fis = new FileInputStream("绝对/相对路径");
byte[] bytes = new byte[4];
int readCount = 0;
while((readCount = fis.read(bytes)) != -1) {
    System.out.print(new String(bytes, 0, readCount));	//读了几个字节输出几个字节
}

?9.2.2 FileOutputStream(文件字节输出流)

输出的文件不存在的时候会自动创建,并且构造方法后的boolean值决定是追加写入(true)还是覆盖写入(false),默认为false(覆盖写入)。?

FileOutputStream fos = fos =  new FileOutputStream("myfile", true);
byte[] bytes = {97, 98, 99, 100};
// 将byte数组全部写出!
fos.write(bytes); // abcd
// 将byte数组的一部分写出!
fos.write(bytes, 0, 2); // 再写出ab
String s = "我是一个中国人,我骄傲!!!";
// 将字符串转换成byte数组。
byte[] bs = s.getBytes();
fos.write(bs);
// 写完之后,最后一定要刷新
fos.flush();

9.2.3 FileReader(文件字符输入流)

FileReader reader = new FileReader("第10章_IO流/src/temp/example05");
char[] chars = new char[4]; // 一次读取4个字符
int readCount = 0;
while((readCount = reader.read(chars)) != -1) {
    System.out.print(new String(chars,0,readCount));
}

9.2.4 FileWriter(文件字符输出流)

FileWriter out = new FileWriter("file", true);
char[] chars = {'我','是','中','国','人'};
out.write(chars);
out.write(chars, 2, 3);
out.write("我是一名java软件工程师!");
out.flush();

9.3 ?缓冲流

9.3.1 BufferedReader

带有缓冲区的字符输入流,使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组,自带缓冲。

构造方法:BufferedReader(Reader in) 创建使用默认大小的输入缓冲区的缓冲字符输入流。

当一个流的构造方法中需要-个流的时候,这个被传进来的流叫做:节点流。

外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流。

例如:

FileReader reader = new FileReader("documentURL");
BufferedReader br = new BufferedReader(reader);
String s = null;
while((s = br.readLine()) != null){
    System.out.println(s);
}
br.close();

关闭流的时候只需要关闭“包装流”(关闭最外层),里面的“节点流”会自动关闭。

String readLine() 读一行文字。 ?

9.3.2 BufferedWriter

void newLine() 写一行行分隔符。

BufferedWriter bw = new BufferedWriter(new FileWriter("第10章_IO流/src/temp/example06", true));
bw.write("打工人打工魂");
bw.flush();
bw.close();

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

9.4.1 InputStreamReader

public class BufferedReaderTest02 {
    public static void main(String[] args) throws Exception{
        /*// 字节流
        FileInputStream in = new FileInputStream("Copy02.java");
        // 通过转换流转换(InputStreamReader将字节流转换成字符流。)
        InputStreamReader reader = new InputStreamReader(in);
        // 这个构造方法只能传一个字符流。不能传字节流。
        BufferedReader br = new BufferedReader(reader);*/
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("第10章_IO流/src/缓冲流/BufferedReaderTest01.java")));
        String line = null;
        while((line = br.readLine()) != null){
            System.out.println(line);
        }
        // 关闭最外层
        br.close();
    }
}

9.4.2 OutputStreamWriter

BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("f", true)));

9.5 ?数据流

9.5.1 DataOutputStream

java.io.DataOutputStream:数据专属的流。这个流可以将数据连同数据的类型一并写入文件。注意:这个文件不是普通文本文档(这个文件使用记事本打不开。)

public class DataOutputStreamTest {
    public static void main(String[] args) throws Exception{
        // 创建数据专属的字节输出流
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("data"));
        byte b = 100;
        short s = 200;       
        dos.writeByte(b); // 把数据以及数据的类型一并写入到文件当中。
        dos.writeShort(s);
        dos.flush();
        dos.close();
    }
}

9.5.2 DataInputStream

DataInputStream:数据字节输入流。DataOutputStream写的文件,只能使用DataInputStream去读。并且读的时候你需要提前知道写入的顺序。读的顺序需要和写的顺序一致。才可以正常取出数据。

public class DataInputStreamTest01 {
    public static void main(String[] args) throws Exception{
        DataInputStream dis = new DataInputStream(new FileInputStream("data"));
        // 开始读
        byte b = dis.readByte();
        short s = dis.readShort();
        System.out.println(b);
        dis.close();
    }
}

9.6 ?标准输出流

9.6.1 PrintStream

java.io.PrintStream:标准的字节输出流。默认输出到控制台。标准输出流不需要手动close()关闭,并且可以改变标准输出流方向。

public class PrintStreamTest {
    public static void main(String[] args) throws Exception{
        // 联合起来写
        System.out.println("hello world!");
        // 分开写
        PrintStream ps = System.out;
        ps.println("hello 这是输出在控制台上");
        // 标准输出流不再指向控制台,指向“log”文件。
        PrintStream printStream = new PrintStream(new FileOutputStream("第10章_IO流/src/temp/log"));
        // 修改输出方向,将输出方向修改到"log"文件。
        System.setOut(printStream);
        // 再输出
        System.out.println("此语句输出至\"第10章_IO流/src/temp/log\"中");
    }
}

9.6.2 PrintWriter

打印流主要包含两个:PrintStream 和 PrintWriter,分别对应字节流和字符流。

public class PrintWriterTest01 {
    public static void main(String[] args) {
        try {
            PrintWriter pw = new PrintWriter(new FileWriter("第10章_IO流/src/temp/log",true));
            pw.println("PrintWriter是个标准字符输出流");
            pw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

9.7 ?File类

File类和四大家族没有关系,所以File类不能完成文件的读和写。File对象代表文件和目录路径名的抽象表示形式。一个File对象有可能对应的是目录,也可能是文件。File只是一个路径名的抽象表示形式。

构造方法:File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。

需要掌握File类中常用的方法:

  1. boolean createNewFile() 当且仅当具有该名称的文件尚不存在时,创建一个由该抽象路径名命名的新的空文件。
  2. boolean delete() 删除由此抽象路径名表示的文件或目录。
  3. boolean exists() 测试此抽象路径名表示的文件或目录是否存在。
  4. File getAbsoluteFile() 返回此抽象路径名的绝对形式。
  5. String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串。
  6. String getParent() 返回此抽象路径名的父 null的路径名字符串,如果此路径名未命名为父目录,则返回null。 ?
  7. File getParentFile() 返回此抽象路径名的父,或抽象路径名 null如果此路径名没有指定父目录。 ?
  8. String getPath() 将此抽象路径名转换为路径名字符串。 ?
  9. boolean mkdir() 创建由此抽象路径名命名的目录。 ?
  10. boolean mkdirs() 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。 ?
  11. boolean isDirectory() 测试此抽象路径名表示的文件是否为目录。 ?
  12. boolean isFile() 测试此抽象路径名表示的文件是否为普通文件。 ?
  13. long lastModified() 返回此抽象路径名表示的文件上次修改的时间。 ?
  14. long length() 返回由此抽象路径名表示的文件的长度。
  15. File[] listFiles() 返回一个抽象路径名数组,表示由该抽象路径名表示的目录中的文件。

?9.8 ?对象专属流

9.8.1 序列化与反序列化

参与序列化和反序列化的对象,必须实现Serializable接口:

public interface Serializable {}

注意:通过源代码发现,Serializable接口只是一个标志接口:这个接口当中什么代码都没有。起到标识的作用,标志的作用,java虚拟机看到这个类实现了这个接口,可能会对这个类进行特殊待遇。

????????Serializable这个标志接口是给java虚拟机参考的,java虚拟机看到这个接口之后,会为该类自动生成一个序列化版本号。

1.transient

采用 transient 关键字修饰某一属性,序列化时会忽略该属性。

2.serialVersionUID

Java语言中是采用什么机制来区分类的?

  • ?首先通过类名进行比对,如果类名不一样,肯定不是同一个类。
  • ?如果类名一样,再怎么进行类的区别?靠序列化版本号进行区分。

这种自动生成的序列化版本号缺点是:一旦代码确定之后,不能进行后续的修改,因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候java虚拟机会认为这是一个全新的类。

最终结论:凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号。这样,以后这个类即使代码修改了,但是版本号不变,java虚拟机会认为是同一个类,便不会报错

9.8.2 ObjectInputStream与ObjectOutputStream

定义一个User类(继承了Serializable接口):

public class User implements Serializable {
    private int no;
    // transient关键字表示游离的,不参与序列化。
    private transient String name; // name不参与序列化操作!
    public User(int no, String name) {
        this.no = no;
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
                "no=" + no +
                ", name='" + name +
                '}';
    }
}

一次序列化多个对象,可以将对象放置集合中,序列化集合:

public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws Exception{
        List<User> userList = new ArrayList<>();
        userList.add(new User(1,"zhangsan"));
        userList.add(new User(2, "lisi"));
        userList.add(new User(3, "wangwu"));
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("第10章_IO流/src/对象类/序列化与反序列化/users"));
        // 序列化一个集合,这个集合对象中放了很多其他对象。
        oos.writeObject(userList);
        oos.flush();
        oos.close();
    }
}

反序列化集合:

public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("第10章_IO流/src/对象类/序列化与反序列化/users"));
        //Object obj = ois.readObject();
        //System.out.println(obj instanceof List);  //true
        List<User> userList = (List<User>)ois.readObject();
        for(User user : userList){
            System.out.println(user);
        }
        ois.close();
    }
}

自动生成的序列号一经确认再修改时,会重新编译,生成新的序列化版本号,JVM认为这是一个全新的类便会报错,因此应在User类中声明一个固定的序列号版本号:

private static final long serialVersionUID = -111111111111111222L;

9.9 ?IO和Properties联合使用

IO+Properties的联合应用是非常好的一个设计理念: 以后经常改变的数据,可以单独写到一个文件中,使用程序动态读取。将来只需要修改这个文件的内容,java代码不需要改动,不需要重新编译,服务器也不需要重启。就可以拿到动态的信息。

类似于以上机制的这种文件被称为配置文件。并且当配置文件中的内容格式是:“key1=value”的时候,我们把这种配置文件叫做属性配置文件。

Java规范中有要求:属性配置文件建议以.properties结尾,但这不是必须的。这种以.properties结尾的文件在java中被称为:属性配置文件。其中Properties是专门存放属性配置文件内容的一个类。配置文件最好“=”两边不要有空格。

public class IoPropertiesTest01 {
    public static void main(String[] args) throws Exception{
        /*
        Properties是一个Map集合,key和value都是String类型。
        想将userinfo文件中的数据加载到Properties对象当中。
         */
        // 新建一个输入流对象
        FileReader reader = new FileReader("chapter23/userinfo.properties");

        // 新建一个Map集合
        Properties pro = new Properties();

        // 调用Properties对象的load方法将文件中的数据加载到Map集合中。
        pro.load(reader); // 文件中的数据顺着管道加载到Map集合中,其中等号=左边做key,右边做value

        String username = pro.getProperty("username");
        System.out.println(username);

        String password = pro.getProperty("password");
        System.out.println(password);
    }
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-06 09:29:41  更:2021-08-06 09:31:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/12 19:10:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码