1. 基本字节输入输出流实现类
2. 输入输出字节流的分类
按方向:
① 输入流:将[存储设备]中的内容输入到[内存]中;
② 输出流:将[内存]中的内容输出到[存储设备]中。
相对于程序操作的内存,进入内存为输入,从内存出去为输出。
按单位:
① 字节流:以字节为单位,可以读写所有数据;
② 字符流:以字符为单位,只能读写文本数据。
按功能:
① 节点流:具有实际传输数据的读写功能;
② 过滤流:在节点流的基础之上增强功能。
3. 抽象父类:InputStream & OutputStream
InputStream字节输入流:
public abstract class InputStream
extends Object
implements Closeable
这个抽象类是表示输入字节流的所有类的超类。需要定义InputStream子类的应用InputStream必须始终提供一种返回输入的下一个字节的方法。
abstract int read()
从输入流读取数据的下一个字节。
int read(byte[] b)
从输入流读取一些字节数,并将它们存储到缓冲区 b 。
int read(byte[] b, int off, int len)
从输入流读取最多 len字节的数据到一个字节数组。
OutputStream字节输出流:
public abstract class OutputStream
extends Object
implements Closeable, Flushable
这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。需要定义OutputStream子类的应用OutputStream必须至少提供一个写入一个字节输出的方法。
void write(byte[] b)
将 b.length字节从指定的字节数组写入此输出流。
void write(byte[] b, int off, int len)
从指定的字节数组写入 len个字节,从偏移 off开始输出到此输出流。
abstract void write(int b)
将指定的字节写入此输出流。
3.1 实现类:字节节点流 FileOutputStream & FileInputStream
- FileOutputStream类(字节节点输出流):
public class FileOutputStream
extends OutputStream
核心方法:
void write(int b)
将指定的字节写入此文件输出流。
void write(byte[] b)
将 b.length个字节从指定的字节数组写入此文件输出流。
void write(byte[] b, int off, int len)
将 len字节从位于偏移量 off的指定字节数组写入此文件输出流。
构造方法:
FileOutputStream(File file)
创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(File file, boolean append)
创建文件输出流以写入由指定的 File对象表示的文件,append==true追加,不覆盖。
FileOutputStream(FileDescriptor fdObj)
创建文件输出流以写入指定的文件描述符,表示与文件系统中实际文件的现有连接。
FileOutputStream(String name)
创建文件输出流以指定的名称写入文件。
FileOutputStream(String name, boolean append)
创建文件输出流以指定的名称写入文件。
示例代码:
public class TestFileOutputStream {
public static void main(String[] args) throws IOException {
// 1.输出字节流 OutputStream
// 2.输出字节节点流,具有实际传输数据的功能,boolean append == true不覆盖原文件内容,追加写入
// 3.路径正确,文件不存在,会自动创建文件
// 4.使用相对路径,相对于当前项目的路径,寻找路径和文件
FileOutputStream fos = new FileOutputStream(".\\files\\target.txt", true);
try {
String s = "你";
fos.write(s.getBytes()); // 写入中文
fos.write(65); // 写入字符
fos.write(66);
fos.write(67);
fos.write('D');
byte[] bs = new byte[] {65, 66, 67, 68, 69, 'Z'}; // 写入字符数组
fos.write(bs);
System.out.println("OK");
} catch (IOException e) {
e.getStackTrace();
} finally {
fos.close();
}
}
}
- FileInputStream类(字节节点输入流):
public class FileInputStream
extends InputStream
核心方法:
int read()
从该输入流读取一个字节的数据。
int read(byte[] b)
从流中读取多个字节,将读到内容存入b数组,返回实际读到的字节数;如果达到文件尾部,返回-1
int read(byte[] b, int off, int len)
从该输入流读取最多 len字节的数据为字节数组。
构造方法:
FileInputStream(File file)
通过打开与实际文件的连接创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
FileInputStream(FileDescriptor fdObj)
创建 FileInputStream通过使用文件描述符 fdObj ,其表示在文件系统中的现有连接到一个实际的文件。
FileInputStream(String name)
通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
示例代码:
public class TestFileInputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream(".\\files\\target.txt");
try {
// 逐个字节读入
// while (true) {
// int n = fis.read();
// if (n < 0) { // -1, 文件结尾EOF
// break;
// }
// System.out.println((char)n);
// }
// 按照数组读入
byte[] bs = new byte[4];
while(true) {
int count = fis.read(bs); // count:每次读取到的有效字节个数
if (count < 0) { // -1, 文件结尾EOF
break;
}
// 读多少个,输出多少个
for (int i = 0; i < count; i++) {
System.out.print((char)bs[i]);
}
System.out.println();
}
//read(bs, off, len); // 读入bs数组中,从off下标开始,每次读入len
} catch (Exception e) {
e.printStackTrace();
} finally {
fis.close();
}
}
}
输入输出综合使用场景:
public class TestFileIOcopy {
public static void main(String[] args) throws IOException {
// 拷贝一张图片
FileInputStream fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\test.jpg");
FileOutputStream fos = new FileOutputStream("files\\new.jpg");
int data = 0;
try {
// 无参的read()返回的是数据
while ((data = fis.read()) >= 0) {
System.out.println(data);
fos.write(data);
}
} finally {
fis.close();
fos.close();
}
}
}
3.2 实现类:字节过滤流(缓冲流)BufferedOutputStream & BufferedInputStream
特点:
- 提高IO效率,减少访问磁盘次数;
- 数据存储在缓冲区中,flush是讲缓存区的内容写入文件中,也可以直接close;
public class BufferedOutputStream
extends FilterOutputStream
public class BufferedInputStream
extends FilterInputStream
示例演示:
public class TestBufferredOutput {
public static void main(String[] args) throws IOException {
// 输出节点流
FileOutputStream fos = new FileOutputStream("files\\buffer.txt");
// 增强节点流:有参构造需要一个字节输出节点流
BufferedOutputStream bos = new BufferedOutputStream(fos);
try {
// 过滤流的write方法,是先写入到缓冲区数组里
bos.write('A');
bos.write('B');
bos.write('C');
// 刷新缓冲区:将缓冲区的数据,或一次性写入文件中,并清空当前缓冲区
bos.flush();
bos.write('E');
// 每次均需刷新缓冲区
//bos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
// .close() 级联的执行了flush();释放了资源的同时,将缓冲器的数据一次性写入到文件中
bos.close();
System.out.println("写入OK");
}
// 输入字节流 - 普通的即可
FileInputStream fis = new FileInputStream("files\\buffer.txt");
//BufferedInputStream bis = new BufferedInputStream(fis);
byte[] b = new byte[100];
fis.read(b);
for (int i = 0; i < b.length; i++) {
System.out.println((char)b[i]);
}
fis.close();
}
}
3.3 实现类:字节过滤流(对象流)ObjectOutputStream & ObjectInputStream
public class ObjectOutputStream
extends OutputStream
implements ObjectOutput, ObjectStreamConstants
public class ObjectInputStream
extends InputStream
implements ObjectInput, ObjectStreamConstants
特点:
- 增强了缓冲区功能
- 增强了读写8种基本数据类型和字符串功能
- 增强了读写对象的功能:
- Object readObject() // 从流中读取一个对象
- void writeObject(Object obj) // 向流中写入一个对象
- 对象序列化:
使用流传输对象的过程称为序列化、反序列化。
- 必须实现Serializable接口;
- 对象自身和类中属性都必须序列化(即实现Serializable这个空接口即可,基本数据类型数组可不序列化,引用数据类型必须序列化);
- transient 关键字修饰为临时属性,不参与序列化;
- 对象的默认序列化机制写入对象的类、类签名和所有非瞬态和非静态字段的值,因此属性不能使用static修饰,否则取的都是最后一次的值(static属于类本身,会影响序列化)。
- 序列化对象流读取到文件尾,会抛出 EOFException 异常 - 捕获后停止读取文件。
public class TestObjectStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 写
OutputStream os = new FileOutputStream("files\\target.txt");
ObjectOutputStream oos = new ObjectOutputStream(os);
Student stu = new Student("小明", 12, "男", 100D);
Student stu1 = new Student("小黑", 13, "男", 60D);
oos.writeObject(stu); // NotSerializableException: 类实现Serializable接口即可
oos.writeObject(stu1);
oos.flush();
oos.close();
// 读
InputStream is = new FileInputStream("files\\target.txt");
ObjectInputStream ois = new ObjectInputStream(is);
while (true) {
try {
Object obj = ois.readObject();
System.out.println(obj);
} catch (EOFException e) {
// 到达文件尾,抛出EOFException文件尾异常
break;
}
}
ois.close();
}
}
// 对象需要实现序列化
// 属性也需要实现序列化
class Student implements Serializable {
private static final long serialVersionUID = 1L;
/*static*/String name; // static为类所有,会影响该属性值变为一个相同的值
Integer age;
String sex;
transient Double score; // transient修饰的属性不参与序列化,均为null
public Student() {
super();
}
public Student(String name, Integer age, String sex, Double score) {
super();
this.name = name;
this.age = age;
this.sex = sex;
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex + ", score=" + score + "]";
}
}