字节流

字符流可以操作任意文件。

img
Image

1. 字节流的父类(抽象类)

  • InputStream

    字节输入流

    • public int read(){}
    • public int read(byte[] b){}
    • public int read(byte[] b,int off,int len){}
  • OutputStream

    字节输出流

    • public void write(int n){}
    • public void write(byte[] b){}
    • public void write(byte[] b,int off,int len){}

2. 字节流的子类

2.1. 文件字节流

  • FileInputStream
    • public int read()从输入流中读取一个字节数据,返回读到的字节数据,如果达到文件末尾,返回-1。
    • public int read(byte[] b)输入流中读取字节数组长度的字节数据存入数组中,返回实际读到的字节数;如果达到文件的尾部,则返回-1。

data.txt

abcdef
String path = "/Users/admin/Downloads/data.txt";
FileInputStream fis = new FileInputStream(path);

// read()读取单个字节
//        int data = fis.read();
//        System.out.println((char) data); // a
// 如read() == -1,则表示已经读完,否则返回当前字节
//        while ((data = fis.read()) != -1) {
//            System.out.print((char) data);  // bcdef
//        }

// 一次性读取多个字节并输出
int cnt = 0;
byte[] data = new byte[1024];
// 如read(byte[] byte) == -1,则表示已经读完,否则返回读取的数量
while ((cnt = fis.read(data)) != -1) {
  // 根据读取的数量截取String长度并进行输出
  System.out.print(new String(data, 0, cnt));    // abcdef
}


fis.close();
  • FileOutputStream
    • public void write(int b)将指定字节写入输出流。
    • public void write(bute[] b)一次写多个字节,将b数组中所有字节,写入输出流。
String path = "/Users/admin/Downloads/data.txt";
FileOutputStream fos = new FileOutputStream(path);//默认覆盖
//        new FileOutputStream(path, true);   // 第二个参数表示追加

// 将一个字节输入到文件中
//        fos.write(97);  // a
//        fos.write('b'); // b


// 将多个字节输入到文件中
byte[] data = new String("helloworld").getBytes(StandardCharsets.UTF_8);
fos.write(data);    // helloworld
fos.close();

案例

String inputPath = "/Users/admin/Downloads/1.png";
String outputPath = "/Users/admin/Downloads/2.png";

FileInputStream fis = new FileInputStream(inputPath);
FileOutputStream fos = new FileOutputStream(outputPath);

byte[] data = new byte[1024];
int count = 0;

while ((count = fis.read(data)) != -1) {
  fos.write(data, 0, count);
}


fis.close();
fos.close();

2.2. 字节缓冲流

  • 缓冲流:BufferedInputStream/BufferedOutputStream
    • 提高IO效率,减少访问磁盘的次数;
    • 数据存储在缓冲区中。flush可以将缓存区的内容写入文件,也可以直接close。
    • 缓冲区默认大小为8192 bytes,即8kb。

BufferedInputStream

String path = "/Users/admin/Downloads/data.txt";

// 使用该输入流每次会从硬盘读入
FileInputStream fis = new FileInputStream(path);
// 缓冲流需要一个底层流
// 缓冲流每次从缓冲区读取
BufferedInputStream bis = new BufferedInputStream(fis);

// 读取
//        int data;
//        while ((data = bis.read()) != -1) {
//            System.out.print((char) data);
//        }

// 我们也可以自己创建一个缓冲区;
// 每次读取从自己创建的缓冲区中读取。
int count;
byte[] buf = new byte[1024];
while ((count = bis.read(buf)) != -1) {
  System.out.println(new String(buf, 0, count));
}

bis.close();    // 缓冲流在关闭的同时也会关闭底层流,所以底层流可以不用手动关闭

BufferedOutputStream

String path = "/Users/admin/Downloads/data.txt";

FileOutputStream fos = new FileOutputStream(path);
BufferedOutputStream bos = new BufferedOutputStream(fos);

for (int i = 0; i < 10; i++) {
  bos.write("Hello world\n".getBytes());    // 调用此方法会写入缓冲区中,并不会写入磁盘
  bos.flush();    // 将缓冲区的内容写入磁盘
}

bos.close();

2.3. 对象流

  • 对象流:ObjectOutputStream/ObjectInputStream
    • 增加了缓冲区功能。
    • 增强了读写8种基本数据类型和字符串功能。
    • 增强了读写对象的功能:
      • readObject()从流中读取一个对象。
      • writeObject(Object obj)向流中写入一个对象。

序列化和反序列化

使用流传输对象的过程称为序列化、反序列化。

  • 注:序列化的类必要要实现Serializable接口

其中,Serializable为标志接口,仅作为标识。

public interface Serializable {
}

Student类

package demo.pojo;

import java.io.Serializable;

/**
 * @author admin
 * @date 2021/8/15 6:54 下午
 */
public class Student implements Serializable {
      @Serial
    private static final long serialVersionUID = 5697270298722545258L;
    String name;
    int age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student() {
    }
}

使用ObjectOutputStream实现对象的序列化

String path = "/Users/admin/Downloads/student.bin";

FileOutputStream fos = new FileOutputStream(path);
ObjectOutputStream oos = new ObjectOutputStream(fos);

Student student = new Student("张三", 15);

oos.writeObject(student);
oos.flush();


oos.close();

:如果执行上述代码后抛出java.io.NotSerializableException,意思是类不能被序列化,需要实现Serializable接口。

student.bin打开如下:

image-20210815190135441
Image

使用ObjectInputStream实现反序列化(读取重构对象)

String path = "/Users/admin/Downloads/student.bin";

FileInputStream fis = new FileInputStream(path);
ObjectInputStream ois = new ObjectInputStream(fis);

Object o = ois.readObject();

System.out.println(o);

if (o instanceof Student student){
  System.out.println(student.getName());
  System.out.println(student.getAge());
}

ois.close();
Student{name='张三', age=15}
张三
15
序列化和反序列化注意事项
  • 序列化类必须实现Serializable接口,前文已经说过。
  • 序列化类中的对象属性也要求实现Serializable接口。也就是说如果Student类中有一个Grad类型的属性private Grad info;那么Grad这个类也要实现Serializable接口。
  • 序列化类中可以添加序列化版本号ID,以保证序列化的类和被序列化的类是同一个类。在上面的代码中我并没有添加序列号版本,虽然IDE没有报错,但是会显示一个警告,提示我添加序列化版本号(串行版本标识)。我们可以在Student类中添加:
private static final long serialVersionUID = 66666L;
  • 使用transient(短暂的)修饰属性,可以避免该属性被序列化。用它来修饰age:
private transient int age;

​ 把tang这个对象序列化后再反序列化,这个对象的age属性就变成了0。

  • 静态属性不能被序列化。
  • 可以利用集合来序列化多个对象:
ArrayList<Student> arrayList=new ArrayList<Student>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
objectOutputStream.writeObject(arrayList);
ArrayList<Student> list=(ArrayList<Student>)objectInputStream.readObject();

3. 编码方式

  • IOS-8859-1

    收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。采用1个字节来表示,最多只能表示256个字符。

  • UTF-8

    针对Unicode码表的可变长度字符编码。国际上使用的编码,也称为“万国码”,收录了几乎所有国家的常用字符。采用1至3个字节来表示一个字符。

  • GB2312

    简体中文,采用1个或2个字节来表示字符,95年之前所采用的编码。

  • GBK

    简体中文的扩充,GB2312的升级版本。

  • BIG5

    台湾,繁体中文。

当编码方式和解码方式不一致时,会出现乱码。

Copyright © rootwhois.cn 2021-2022 all right reserved,powered by GitbookFile Modify: 2023-03-05 10:55:52

results matching ""

    No results matching ""