Java IO流
1、什么是IO
Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列。Java的I/O流提供了读写数据的标准方法。任何Java中表示数据源的对象都会提供以数据流的方式读写它的数据的方法。
IO又分为流IO(java.io)和块IO(java.nio)
Java.io是大多数面向数据流的输入/输出类的主要软件包。此外,Java也对块传输提供支持,在核心库 java.nio中采用的便是块IO。
流IO的好处是简单易用,缺点是效率较低。块IO效率很高,但编程比较复杂。
这里先讲流IO。
2、什么是流
在电脑上的数据有三种存储方式,一种是外存,一种是内存,一种是缓存。比如电脑上的硬盘,磁盘,U盘等都是外存,在电脑上有内存条,缓存是在CPU里面的。外存的存储量最大,其次是内存,最后是缓存,但是外存的数据的读取最慢,其次是内存,缓存最快。这里总结从外存读取数据到内存以及将数据从内存写到外存中。对于内存和外存的理解,我们可以简单的理解为容器,即外存是一个容器,内存又是另外一个容器。那又怎样把放在外存这个容器内的数据读取到内存这个容器以及怎么把内存这个容器里的数据存到外存中呢?
在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:
? 标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流等等,java中将输入输出抽象称为流,就好像水管,将两个容器连接起来。将数据从外存中读取到内存中的称为输入流,将数据从内存写入外存中的称为输出流。
3、根据流向分为输入流和输出流
注意输入流和输出流是相对于程序而言的。
4、字节流和字符流
按处理数据单位不同分为:字节流、字符流
字节流和字符流的原理是相同的,只不过处理的单位不同而已。
- 后缀是stream是字节流,而后缀是Reader , Writer是字符流。
字符流的由来:Java中字符是采用unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,Java引入了处理字符的流。因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查指定的码表。
字节流和字符流的区别:
设备上的数据无论是图片或者视频,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据
5、根据功能分为节点流和包装流
节点流:可以从或向一个特定的地方(节点)读写数据,直接连接数据源。如最常见的是文件的FileReader,还可以是数组、管道、字符串,关键字分别为ByteArray/CharArray,Piped,String。.
处理流(包装流):并不直接连接数据源,是对一个已存在的流的连接和封装,是一种典型的装饰器设计模式,使用处理流主要是为了更方便的执行输入输出工作,如PrintStream,输出功能很强大,又如BufferedReader提供缓存机制,推荐输出时都使用处理流包装。
? 一个流对象经过其他流的多次包装,称为流的链接。
注意:一个IO流可以即是输入流又是字节流又或是以其他方式分类的流类型,是不冲突的。比如FileInputStream,它既是输入流又是字节流还是文件节点流。
6、IO流整体构架图
7、节点流
节点流:直接和数据相连,读入或者读出
字节流:每次读取(写出)一个字节,当传输的资源文件有中文时,就会出现乱码
read()方法每次调用都读取一个字
8、 FileInputStream输入流
@Test
public void readData1() throws IOException {
FileInputStream fis = null;
File file = new File("src/main/resources/1.txt");
if (file.exists()){
fis = new FileInputStream(file);
int ch;
while((ch = fis.read()) != -1){
System.out.println((char) ch);
}
fis.close();
}
}
@Test
public void readData2() throws IOException {
FileInputStream fis = null;
File file = new File("src/main/resources/1.txt");
if (file.exists()){
fis = new FileInputStream(file);
System.out.println("输入流里面剩余的字节数有:" + fis.available());
byte[] bytes = new byte[5];
int length = fis.read(bytes);
System.out.println(fis.available());
fis.close();
}
}
9、FileOutputStream
@Test
public void writeData1() throws IOException {
File file = new File("src/main/resources/1.txt");
FileOutputStream fos = new FileOutputStream(file,true);
fos.write(98);
byte[] bytes = new byte[]{11,12,12,123};
fos.write(bytes);
String str = "你好呀";
byte[] bytes1 = str.getBytes();
fos.write(bytes1);
fos.close();
}
实现文件复制
@Test
public void copyData1() throws IOException {
File file = new File("src/main/resources/1.txt");
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream("src/main/resources/3.txt");
byte[] bytes = new byte[10];
int len;
while((len=fis.read(bytes))>-1){
fos.write(bytes,0,len);
}
fis.close();
fos.close();
}
10、字符流
- FileReader() 和字节输入流差不多,就是读入的时候一个字符一个读入.read()
- FileWriter()
- 方法多了个getEncoding()
11、缓冲流
缓冲流能有效提高文件的读写速度
BufferedInputStream
BufferedOutputStream
@Test
public void Test2() throws IOException {
File file = new File("src/main/resources/1.txt");
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream("src/main/resources/11.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] bytes = new byte[100];
int len;
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
bos.close();
bis.close();
}
BufferedReader
BufferedWriter
12、转换流:把字节流转换为字符流
解决中英文都存在的文件时乱码问题,是字符与字节之间的桥梁
InputStreamReader:把字节输入流转换为字符输入流
OutputStreamWriter:把字节输出流转换为字符输出流
13、序列化与反序列化
13.1、什么是序列化与反序列化?
序列化:指把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传输)。这个过程称为序列化。通俗来说就是将数据结构或对象转换成二进制串的过程
反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。也就是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程
13.2、为什么要做序列化?
①、在分布式系统中,此时需要把对象在网络上传输,就得把对象数据转换为二进制形式,需要共享的数据的 JavaBean 对象,都得做序列化。
②、服务器钝化:如果服务器发现某些对象好久没活动了,那么服务器就会把这些内存中的对象持久化在本地磁盘文件中(Java对象转换为二进制文件);如果服务器发现某些对象需要活动时,先去内存中寻找,找不到再去磁盘文件中反序列化我们的对象数据,恢复成 Java 对象。这样能节省服务器内存。
13.3、Java 怎么进行序列化?
①、需要做序列化的对象的类,必须实现序列化接口:Java.lang.Serializable 接口(这是一个标志接口,没有任何抽象方法),Java 中大多数类都实现了该接口,比如:String,Integer
②、底层会判断,如果当前对象是 Serializable 的实例,才允许做序列化,Java对象 instanceof Serializable 来判断。
③、在 Java 中使用对象流来完成序列化和反序列化
ObjectOutputStream:通过 writeObject()方法做序列化操作
ObjectInputStream:通过 readObject() 方法做反序列化操作
|