JavaIO流
一、什么是IO流?
IO,即输入和输出,是指应用程序和外部设备间的数据传输。
流:代表任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象
< Thinking in Java>
流的本质:数据传输,根据数据传输特性将流抽象为各种类
,方便更直观的进行数据操作。
流的特征:
- 先进先出
- 顺序存取。即顺序读或顺序写(RandomAccessFile除外)
- 只读或只写。即流通道是单向的,只能读或写。想同时读写就要建立两个通道。
Java中通过流处理IO
二、IO流的分类
IO流分类主要三种:
- 按流的方向:输入流、输出流
- 按流处理的数据:字节流、字符流
- 按功能:节点流、处理流
1.输入流和输出流
输入流:外部向程序输入;输出流:从程序向外部输出
2.字节流和字符流
字节流处理的是字节;字符流处理的是字符。流操作的数据单元不同。
为什么使用字符流:
Java中字符采用Unicode编码,中文占用2个字符。如果使用字节流,读写时如果将其分开,就会产生乱码。
字节流和字符流区别:
字节流可以处理一切文件
(图像、视频、音频、PPT、Word等),而字符流只能处理纯文本文件
字节流本身没有缓冲区
,缓冲字节流相对于字节流,效率提升非常高。而字符流本身就带有缓冲区
。
3.节点流和处理流
节点流:直接操作数据读写的流
处理流:对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装
,即采用了装饰者模式
三、IO流的分析
1.File
File类是对文件系统中文件以及文件夹进行封装的对象,可以以对象的方式来操作文件和文件夹。 File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法,但它不能操作文件中的数据
2.InputStream
抽象类,所有字节输入流的基类。
FileInputStream
:文件输入流,很重要,对文件进行读操作。- PipedInputStream:管道字节输入流,能实现多项承建的管道通信。
- ByteArrayInputStream:字节数组输入流。以字节为单位读取传入构造函数的数组数据或操作。
- FilterInputStream:装饰实现类基类,只是对InputStream类的一些方法的重写,但可能后续会修改。
//源码注释
The class <code>FilterInputStream</code>
- itself simply overrides all methods of
- <code>InputStream</code> with versions that
- pass all requests to the contained input
- stream. Subclasses of <code>FilterInputStream</code>
- may further override some of these methods
- and may also provide additional methods
- and fields.
- DataInputStream:数据输入流,装饰类。作用是“允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型”,就是可以将数据读取成Java基本类型。
BufferedInputStream
:缓冲流,装饰类。内部有一个缓存区,用来存放字节,每次都是将缓存区存满然后发送,而不是一个字节或两个字节这样发送。效率更高ObjectInputStream
:对象输入流,也是一个装饰类。用来提供对基本数据或对象的持久存储。也就是能直接传输对象,通常应用在反序列化中。
3.OutputStream
与InputStream类似,注意还有PrintStream
4.Reader
抽象类,所有字符输出流的基类
-
InputStreamReader
:字节流到字符流的桥梁,传入参数为InputStream的实例对象,读取字节后使用指定编码方式将其编码为字符。如果不指定使用默认编码
-
BufferedReader
:字符缓冲流,装饰Reader。从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 -
FileReader
:用于读取字符文件的便利类。new FileReader(File file)等同于new
InputStreamReader(new FileInputStream(file,
true),“UTF-8”),但FileReader不能指定字符编码和默认字节缓冲区大小。
-
PipedReader :管道字符输入流。实现多线程间的管道通信
-
CharArrayReader:从Char数组中读取数据的介质流
-
StringReader :从String中读取数据的介质流
4.Writer
与Reader类似,方向相反。注意还有PrintWriter
四、IO流的方法
字节流方法
InputStream主要方法:
- read() :从此输入流中读取数据下一个字节
- read(byte[] b) :从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中
- read(byte[] b, int off, int len) :从此输入流中将最多 len 个字节的数据读入一个 byte 数组中
- close():关闭此输入流并释放与该流关联的所有系统资源
- skip(long n):跳过和丢弃此输入流中数据的 n个字节
OutputStream主要方法:
- write(byte[] b) :将 b.length 个字节从指定 byte 数组写入此文件输出流中
- write(byte[] b, int off, int len) :将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流
- write(int b) :将指定字节写入此文件输出流
- close() :关闭此输入流并释放与该流关联的所有系统资源
- void flush():刷新此输出流并强制写出所有缓冲的输出字节
字符流方法
Reader主要方法:
- read():读取单个字符
- read(char[] cbuf) :将字符读入数组
- read(char[] cbuf, int off, int len) : 将字符读入数组的某一部分
- read(CharBuffer target) :试图将字符读入指定的字符缓冲区
- close() :关闭此流
Writer主要方法:
- write(char[] cbuf) :写入字符数组
- write(char[] cbuf, int off, int len) :写入字符数组的某一部分
- write(int c) :写入单个字符
- write(String str) :写入字符串
- write(String str, int off, int len) :写入字符串的某一部分
- flush() :刷新该流的缓冲
- close() :关闭此流,但要先刷新它
字符缓冲流还有两个独特的方法:
BufferedWriter类newLine() :写入一个行分隔符。这个方法会自动适配所在系统的行分隔符。
BufferedReader类readLine() :读取一个文本行。
五、序列化和反序列化
将保存在内存中的对象数据转化为二进制数据流进行传输,任何对象都可以序列化
实现方法:实现Serializable接口
测试代码:
import java.io.*;
class Book implements Serializable{
private String name;
private double price;
public Book(String name,double price){
this.name=name;
this.price=price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
public class SerializableTest {
public static void main(String[] args){
//使用ObjectOutputStream实现对Book对象序列化并写入serTest.txt文件
ObjectOutputStream writer;
try {
writer=new ObjectOutputStream(new FileOutputStream
(new File("C:\\Users\\DXS\\Desktop"+File.separator+"serTest.txt")));
writer.writeObject(new Book("java编程思想",50));
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
//使用ObjectInputStream读取serTest.txt文件并反序列化得到Book对象
ObjectInputStream reader;
try {
reader=new ObjectInputStream(new FileInputStream
(new File("C:\\Users\\DXS\\Desktop"+File.separator+"serTest.txt")));
Book book=(Book) reader.readObject();
System.out.println(book.toString());
reader.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
结果:
Book{
name='java编程思想', price=50.0}
transient关键字
为上面Book中的price添加关键字
transient private double price;
结果:
Book{
name='java编程思想', price=0.0}
在写入文件时,price并没有被序列化,所以读取时并没有得到price的值,所以price为初始化的值
参考
https://blog.csdn.net/sinat_37064286/article/details/86537354
https://blog.csdn.net/mu_wind/article/details/108674284
https://blog.csdn.net/MAGIC_JSS/article/details/51475923