Java基础学习生疏知识点总结(17)——IO字符流和其它流

1、字符流

字符流产生的原因

  • 用字节流读取英文字符与数字
    • 没有问题 能够正常显示
  • 用字节流读取中文字符
    • 可能会有问题

编解码

  • 一个字符在计算机当中是怎样存储的?
    • 基于某个编码表,有与之对应的整数值(编码值)存储在计算机当中的
  • 编码
    • 基于某个编码表,把字符数据转化成编码值的过程(把人看懂的东西转化成计算机看懂的东西)
  • 解码
    • 基于某个编码表,把编码值转化成字符数据的过程(把计算机看懂的东西转化成人看懂的东西)

产生乱码的原因

编解码的不一致

中文编码表 : ‘你’ 123

日文编码表 : ‘の’ 123

编码表

ASCII:美国标准信息交换码。
用一个字节的7位可以表示。 128
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。 0000 0000 - 1111 1111

GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
GB18030:GBK的取代版本
BIG-5码 :通行于台湾、香港地区的一个繁体字编码方案,俗称“大五码”。

Unicode:国际标准码,融合了多种文字。

UTF-8:可变长度来表示一个字符。
UTF-8不同,它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容:

它将Unicode编码为00000000-0000007F的字符,用单个字节来表示 0111 1111 = 7F
它将Unicode编码为00000080-000007FF的字符用两个字节表示
它将Unicode编码为00000800-0000FFFF的字符用3字节表示

1字节 0xxxxxxx
2字节 110xxxxx 10xxxxxx
3字节 1110xxxx 10xxxxxx 10xxxxxx

utf-16:

jvm使用的编码表,用2个字节来编解码

char : 2 字节

开发中常用的编码表

utf-8 GBK ISO8859-1 ASCII

默认编码表

  • idea中默认utf-8
  • 操作系统Win GBK

字符流的本质
字符流的本质:字节流+编码表

1.1 字符输出流

1.1.1 抽象基类Writer

在这里插入图片描述
在这里插入图片描述

1.1.2 具体子类

1.1.2.1 OutputStreamWriter转换流

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
构造方法

OutputStreamWriter(OutputStream out) 创建使用默认字符编码OutputStreamWriter。

OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的OutputStreamWriter。

例子:``

package com.cskaoyan.charstream;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 * @description:
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo {
    public static void main(String[] args) throws IOException {
        // 第一种构造方法
        FileOutputStream fileOutputStream = new FileOutputStream("a.txt");
        // 采用默认字符集 utf-8
        OutputStreamWriter out = new OutputStreamWriter(fileOutputStream);
        
        // 第二种
        OutputStreamWriter outputStreamWriter = 
                new OutputStreamWriter(new FileOutputStream("a.txt"), "GBk");
    }
}

成员方法
5个write方法

package com.cskaoyan.charstream;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 * @description: write方法
 * @author: songtao@cskaoyan.onaliyun.com
 **/

public class Demo2 {
    public static void main(String[] args) throws IOException {
        // 定义字符串
        String s = "我要为你写65页ppt";

        // 创建转换输出流对象
        OutputStreamWriter out =
                new OutputStreamWriter(new FileOutputStream("a.txt"));
        // 写数据
        // 写单个字符
        //writeSingle(s, out);

        // 写字符数组
        //writeMuti(s, out);

        out.write(s);

        out.flush();
        out.close();
    }

    private static void writeMuti(String s, OutputStreamWriter out) throws IOException {
        char[] chars = s.toCharArray();
        out.write(chars);
    }

    private static void writeSingle(String s, OutputStreamWriter out) throws IOException {
        char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            // 逐个字符写
            out.write(chars[i]);
        }
    }
}
1.1.2.2 FileWriter简化流

用来写入字符文件的便捷类
构造方法

FileWriter(File file) 根据给定的 File 对象构造一个 FileWriter 对象。
FileWriter(File file, boolean append) 根据给定的 File 对象构造一个 FileWriter 对象。
FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象。
FileWriter(String fileName, boolean append) 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

例子:

public class Demo1 {
    public static void main(String[] args) throws IOException {
        // 第一种
        FileWriter fileWriter = new FileWriter(new File("a.txt"));
        
        // 第二种
        FileWriter fileWriter1 = new FileWriter("a.txt");
    }
}

成员方法

5个write方法

例子

public class Demo2 {
    public static void main(String[] args) throws IOException {
        // 创建文件字符输出流对象
        FileWriter fileWriter = new FileWriter("a.txt");
        // 写数据
        String s = "什么是快乐星球?";
        fileWriter.write(s);
        fileWriter.close();
    }
}
1.1.2.3 BuffferedWriter

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

构造方法

BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out, int sz) 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

默认缓冲区大小

  • 16KB

特有方法

  • voidnewLine() 写入一个行分隔符。

例子:

public class Demo {
    public static void main(String[] args) throws IOException {
        // 创建缓冲输出流对象
        BufferedWriter bw = new BufferedWriter(
                new FileWriter("a.txt"));
        // 写数据
        bw.write("RNG夺冠");
        bw.newLine();
        bw.write("卢本伟牛逼");
        bw.close();
    }
}

1.2 字符输入流

1.2.1 抽象基类Reader

在这里插入图片描述
成员方法

intread() 读取单个字符。
intread(char[] cbuf) 将字符读入数组。
abstract intread(char[] cbuf, int off, int len)

read():

作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1

1.2.2 具体子类

1.2.2.1 InputStreamReader转换流

构造方法

  • InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。
  • InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader。

例子:

public class Demo {
    public static void main(String[] args) throws IOException {
        // 第一种构造方法
        InputStreamReader in = new InputStreamReader(
                new FileInputStream("a.txt"));
        // 第二种构造方法
        InputStreamReader inputStreamReader = new InputStreamReader(
                new FileInputStream("a.txt"), "GBk");
    }
}

成员方法

  • 3个read方法

例子:读数据

public class Demo2 {
    public static void main(String[] args) throws IOException {
        // 创建输入流对象
        InputStreamReader in = new InputStreamReader(
                new FileInputStream("a.txt"));
        // read数据

        // 单个
        //readSingle(in);

        // 多个
        readMuti(in);

        // close
        in.close();
    }

    private static void readMuti(InputStreamReader in) throws IOException {
        char[] chars = new char[1024];
        // readCount表示读取到的字符的个数
        int readCount = in.read(chars);
        System.out.println(new String(chars,0,readCount));
    }

    private static void readSingle(InputStreamReader in) throws IOException {
        int readData = in.read();
        System.out.println(((char) readData));

        int readData2 = in.read();
        System.out.println(((char) readData2));
    }
}

复制文件

  • 文本文件复制
public class Demo3 {
    public static void main(String[] args) throws IOException {
        // 创建输入流对象
        InputStreamReader in = new InputStreamReader(
                new FileInputStream("D:\\aa.txt"));
        // 创建输出流对象
        OutputStreamWriter out = new OutputStreamWriter(
                new FileOutputStream("aa.txt"));
        // 边读边写
        // 单个字符的方式
        //copySingle(in, out);

        // 多个字符的方式
        char[] chars = new char[1024];
        int readCount;
        while ((readCount = in.read(chars)) != -1) {
            out.write(chars,0,readCount);
        }

        // close
        in.close();
        out.close();
    }

    private static void copySingle(InputStreamReader in, OutputStreamWriter out) throws IOException {
        int readData;
        while ((readData = in.read()) != -1) {
            out.write(readData);
        }
    }
}

图片文件复制

public class Demo4 {
    public static void main(String[] args) throws IOException {
        InputStreamReader in = new InputStreamReader(
                new FileInputStream("D:\\mm.jpg"));
        OutputStreamWriter out = new OutputStreamWriter(
                new FileOutputStream("mm.jpg"));
        char[] chars = new char[1024];
        int readCount;
        while ((readCount = in.read(chars)) != -1) {
            out.write(chars,0,readCount);
        }
        out.flush();
        in.close();
        out.close();

    }
}
// 虽然看起来复制成功 但是根本打不开

乱码问题解决

public class Demo5 {
    public static void main(String[] args) throws IOException {
        InputStreamReader in = new InputStreamReader(
                new FileInputStream("a.txt"),"GBk");
        char[] chars = new char[1024];

        int readCount = in.read(chars);
        System.out.println(new String(chars,0,readCount));
    }
}
1.2.2.2 FileReader简化流

用来读取字符文件的便捷类

构造方法

FileReader(File file) 在给定从中读取数据的 File 的情况下创建一个新 FileReader。
FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader。

成员方法

3个read方法

例子:

public class Demo3 {
    public static void main(String[] args) throws IOException {
        //  创建一个字符文件输入流

        FileReader reader = new FileReader("a.txt");

        // 读取数据
        char[] chars = new char[1024];
        int readCount = reader.read(chars);
        System.out.println(new String(chars, 0, readCount));

        reader.close();
    }
}
1.2.2.3 转化流 VS简化流
  • 转化流使用麻烦,简化流使用相对简单
  • 转化流可以显示的指定字符集(构造方法) 简化流没有办法指定字符集,只能使用平台默认字符集
1.2.2.4 BufferedReader

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

构造方法

BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流。

特有的成员方法

StringreadLine() 读取一个文本行。

注意:

读取一个文本行。通过下列字符之一即可认为某行已终止:换行 (’\n’)、回车 (’\r’) 或回车后直接跟着换行。

返回:
包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

Demo:

public class Demo2 {
    public static void main(String[] args) throws IOException {
        // 创建缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader("a.txt"));
        // 读数据
        //readSingleLine(br);

        // while循环做
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }

        br.close();
    }

    private static void readSingleLine(BufferedReader br) throws IOException {
        String s = br.readLine();
        System.out.println(s);
        String s2 = br.readLine();
        System.out.println(s2);
        String s3 = br.readLine();
        System.out.println(s3);
    }
}

2 其他流

2.1 数据流

引入:向文本文件当中写入整数 1000 用字符流怎么做?

我们没有办法通过字节流 字符流去写入java基本数据类型 所以就有了数据流

2.1.1 DataOutputStream数据输出流

数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入

构造方法

DataOutputStream(OutputStream out) 创建一个新的数据输出流,将数据写入指定基础输出流。

成员方法

  • 每种java基本数据类型 都有1个write方法与之对应

Demo

public class Demo {
    public static void main(String[] args) throws IOException {
        // 用数据流
        // 创建数据输出流对象
        DataOutputStream out = new DataOutputStream(
                new FileOutputStream("a.txt"));
        // 写入整数1000
        out.writeInt(1000);
        out.writeDouble(3.14);
        out.close();


        // 创建数据输入流对象
        DataInputStream in = new DataInputStream(
                new FileInputStream("a.txt"));

        // 读取数据
        int i = in.readInt();
        System.out.println(i);
        double v = in.readDouble();
        System.out.println(v);
    }
}

2.1.2 DataInputStream 数据输入流

构造方法

DataInputStream(InputStream in) 使用指定的底层 InputStream 创建一个DataInputStream。

成员方法:

  • 每种java基本数据类型 都有1个read方法与之对应

注意:

我们按照怎样的顺序去写入,就需要我们按照相同的顺序去读取

在这里插入图片描述

public class Demo2 {
    public static void main(String[] args) throws IOException {
        write();
        read();
    }

    private static void read() throws FileNotFoundException, IOException {
        DataInputStream dis = new DataInputStream(
                new FileInputStream("dos.txt"));
        byte b = dis.readByte();
        System.out.println(b);
        short s = dis.readShort();
        System.out.println(s);
        int i = dis.readInt();
        System.out.println(i);
        long l = dis.readLong();
        System.out.println(l);
        float f = dis.readFloat();
        System.out.println(f);
        double d = dis.readDouble();
        System.out.println(d);
        char ch = dis.readChar();
        System.out.println(ch);
        boolean bb = dis.readBoolean();
        System.out.println(bb);
        dis.close();
    }

    private static void write() throws IOException {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream(
                "dos.txt"));
        dos.writeByte(1);
        dos.writeShort(20);
        dos.writeInt(300);
        dos.writeLong(4000);
        dos.writeFloat(12.34f);
        dos.writeDouble(12.56);
        dos.writeChar('a');
        dos.writeBoolean(true);
        dos.close();
    }
}

2.2 打印流

练习:

写一个工具类 PrintUtils

成员变量 OutputStream

printInt(int) 专门写入int类型的数据的方法

printIntLn(int) 专门写入int类型的数据的方法 带换行

printDouble(double) 专门写入double类型的数据的方法

printDoubleLn(double) 专门写入double类型的数据的方法 带换行

close方法

提示:核心方法就是把相应的数据类型转换成String 写入文本

public class PrintUtils {
    public OutputStream out;

    public PrintUtils(OutputStream out) {
        this.out = out;
    }

    public void printInt(int intType) throws IOException {
        String s = String.valueOf(intType);
        out.write(s.getBytes());
    }

    public void printlnInt(int intType) throws IOException {
        String s = String.valueOf(intType);
        out.write(s.getBytes());
        out.write(System.lineSeparator().getBytes());
    }
}

2.2.1 PrintStream字节打印流和printWriter字符打印流

打印流的4个特点

  • 只能操作目的地,不能操作数据来源。

    • 没有一个输入流与之对应
  • 可以操作任意类型的数据。

    • 通过把不同的类型转化成字符串写入
  • 如果启动了自动刷新,能够自动刷新。

    • PrintWriter(Writer out, boolean autoFlush) 创建新 PrintWriter。
    • autoFlush - boolean 变量;如果为 true,则 println、printf 或 format 方法将刷新输出缓冲区
      在这里插入图片描述
      在这里插入图片描述
  • 可以操作文件的流

    • 直接使用构造方法去传文件名作为参数

2.2.2 标准输入流与标准输出流

  • 标准输出流 System.out 默认的输出设备是显示器
    • 是一个字节打印流
  • 标准输入流 System.in 默认的输入设备是键盘
    • 是普通的字节输入流

练习:

利用System.in 去实现 Scanner当中的一个nextLine功能

需求:不停的去接收键盘输入的数据,当输入"88" 终止程序

提示:利用BufferedReader

public class Demo7 {
    public static void main(String[] args) throws IOException {
        // 利用转换流
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in));
        //System.out.println("before");
        //String s = br.readLine();
        //System.out.println("after");
        //System.out.println(s);
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
            // 给出约定 当输入"88" break
            if (line.equals("88")) {
                break;
            }
        }
        br.close();
    }
}

2.3 对象流

为啥会有对象流?

Student student = new Student("张三",18);
// 通过序列化流  把这个学生对象给存储起来 
// 通过反序列化流去 把这个学生对象给还原回来

2.3.1 ObjectOutPutStream 序列化流

只能将支持 java.io.Serializable 接口的对象写入流中

构造方法

ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream 的 ObjectOutputStream。

成员方法

writeObject(Object obj) 将指定的对象写入 ObjectOutputStream。

2.3.2 ObjectInputStream反序列化流

构造方法

ObjectIntputStream(InputStream in)

成员方法

readObject()

注意:

  • java.io.NotSerializableException

  • Serializable是空接口 只起到标记的作用

  • transient修饰的属性 是不会被序列化的  只有默认值
    
  • java.io.InvalidClassException 类发生了变化 serialVersionUID变了

    • 如何强行解决
    • static final long serialVersionUID = -1141965245606624166l;

3、总结

类型字节输出流字节输入流字符输出流字符输入流
基类OutputStreamInputStreamWriterReader
文件相关FileOutputStreamFileInputStreamFileWriterFileReader
缓冲相关BufferedOutputStreamBufferedInputStreamBufferedWriterBufferedReader
转换流OutputStreamWriterInputStreamReader
数据流DataOutputStreamDataInputStream
打印流PrintStreamPrintWriter
对象流ObjectOutputStreamObjectInputStream
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值