I/O流的总结
什么是IO流
IO流就是java中读写和操作文件的常用类集合
I是Input就是输入,文件在内存中输入到硬盘中,O就是Output输出是硬盘写入到内存中。
流的概念就是文件在输入和输出的过程中在操作系统中内存与磁盘之间文件会变成类似水流类的数据流。
数据流可以是以二进制的形式,也可以是字符的形式。所以分为字符流与字节流。
Reader与Writer、InputStream与OutputStream为IO的四大抽象类,前两者是以字符的形式操作文件我们称之为字符流,而后两者是以字节的形式操作文件我们称之为字节流。
字符流只能操作纯文本文件,例如.txt文件或者.md文件。字节流则可以操作一切的形式的我文件,诸如图片文件、音频文件、视频文件以及文本文件,可以以叫万能流。
而所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。流可以理解成一个管道,是一个存在于内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费很多资源。
所有的输出流都实现了:java.io.Flushable接口,都是可刷新的,都有flash()方法。养成一个好习惯,输出流在最终输出之后,一定要执行flash()方法,将管道中可能还留存的数据冲刷出来。否则可能丢失数据。
注意:在java中只要是以Stream为结尾的类都是字节流。以Reader/Writer为结尾的都是字符流
为什么要学IO流
在我们学习计算机时,windows操作系统下是在图形界面下操作文件(例如:创建、写文件、删文件等),而在linux操作系统下,我们是通过命令行的形式对文件进行操作。在实际业务中我们程序员是通过编写程序来操作文件,而IO流就为我们提供了一系列的文件操作方式。
在实际业务开发过程中,我们在应用框架中会使用到配置文件,而程序与配置文件之间就会使用到IO流。在拓展中由简单的例子说明。
InputStream与OutputStream
InputStream/OutputStream是输入/输出字节流,字节流是将目标文件以二进制的形式在操作系统中输入输出,这两种都为抽象类,而他们之下的基础常用类有文件流:FileInputStream与FileOutputStream以及缓冲流:BufferdInputStream与BufferdOutputStream这四种常用类。
使用IO流的大致异常捕获机构
package IO;
import java.io.*;
public class FileInputStream_test01 {
public static void main(String[] args) {
FileInputStream fis=null;
try {
//在该目标文件夹下创建lmz.txt文件,而Idea中的默认路径是该工程文件。
fis = new FileInputStream("src//IO//lmz.txt");
//FileInputStream类的read()方法将文件中硬盘中的文件输入到内存中。
int readData=fis.read();//该read方法返回值时读取到的“字节”本身
System.out.println(readData);//得到的数字为97
//但是一次read只读取一个字节,所以一般使用循环读取。
} catch (FileNotFoundException e) {//fis找不到文件时会抛出该异常
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
} finally
{//将关闭操作放入finally中,确保输入流一定会别关闭
if (fis != null){//避免空指针异常
//关闭当前流的前提为流不是空的
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
利用数组存储文件
package IO;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStream_test02 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("src//IO//lmz.txt");
//创建一个4个字节大小的字节数组
byte[] bytes = new byte[4];
//一次从文件中输入四个字节到文件中,得到的字节数用readCount记录
int readCount = fis.read(bytes);
//输出获得的字节数
System.out.println(readCount);//获取到四个字节则为4
//打印出输入的字节对应的字符
System.out.println(new String(bytes));//打印输出asdf
readCount = fis.read(bytes);
System.out.println(readCount);//第二次只获得了一个字节所以为1
System.out.println(new String(bytes));//打印输出ssdf
readCount = fis.read(bytes);
System.out.println(readCount);//read方法已经将文件数据读完后会返回-1
System.out.println(new String(bytes));//由于没有新的数据进入流,所以流中的数据没有变化
//以下为基本操作,可看test01复习
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
} finally {
if (fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
当然结构也可以简化一点
package IO;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStream_test03 {
public static void main(String[] args) throws IOException {
FileInputStream fis = null;
fis = new FileInputStream("src//IO//lmz.txt");
byte[] bytes = new byte[4];
int readCount = 0;
while ((readCount = fis.read(bytes)) != -1){
System.out.println(new String(bytes));
}
fis.close();
}
}
拓展使用available方法
package IO;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStream_test04_available {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("src//IO//lmz.txt");
int available = fis.available();
byte[] bytes = new byte[available];
int Count = fis.read(bytes);
System.out.println(new String(bytes));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e ){
if (fis != null) {
try {
fis.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
}
FileOutputStream
package IO;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStream_test01 {
public static void main(String[] args) throws IOException {
FileOutputStream fos = null;
fos = new FileOutputStream("src//IO//liumz.txt");
byte[] bytes = {88 , 44, 99, 77};
fos.write(bytes);
fos.write(bytes,0,2);
fos.flush();
fos.close();
}
}
Reader与Writer
Reader与Writer是输入/输出字符流,这两类都是在IO体系下的抽象类,在他们之下的基础常用类有文件流:FileReader与FileWriter以及缓冲流:BufferdReader与BufferdWriter。
FileReader的简单使用
package IO;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReader_test01 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("src//IO//lmz.txt");
char[] chars = new char[4];
int count = fr.read(chars);
System.out.println(chars);
fr.close();
}
}
FileWriter的简单使用
package IO;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriter_test01 {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("src//IO//liu.txt",true);
char[] chars = {'我','写','博','客','呢'};
fw.write(chars);
fw.write(chars,2,3);
fw.write("我今天写了一天的博客!");
fw.write("\n");
fw.write("helloworld!");
fw.close();
}
}
一边读一边写
package IO;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Filerw_test {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("src//IO//liu.txt");
FileReader fr = new FileReader("src//IO//liumz.txt");
char[] chars = new char[4];
while (fr.read() != -1){
fr.read(chars);
fw.write(chars);
}
fw.flush();
fw.close();
fr.close();
}
}
序列化与反序列化
序列化:Serialize java对象存储到文件中。将java对象的状态保存下来的过程。
反序列化:DeSerialize 将硬盘上的数据重新恢复到内存当中,恢复成java对象。
想要了解序列化的概念我们首先需要学习ObjectOutputStream与ObjectInputStream的两个类。
Student
package IO;
public class Studnet implements java.io.Serializable {
private String name="java";
private int age=100;
@Override
public String toString() {
return "Studnet{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Studnet(String name, int age) {
this.name = name;
this.age = age;
}
public Studnet(String name) {
this.name = name;
}
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;
}
}
通过ObjectOutputStream将Student对象s序列化
package IO;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class ObjectOutputStream_test01 {
public static void main(String[] args) throws IOException {
Studnet s = new Studnet("liumz",232);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src//IO//Student1.txt"));
oos.writeObject(s);
oos.flush();
oos.close();
}
}
通过ObjectInputStream将序列化后的Studnet对象s反序列化
package IO;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectInputStream_test02 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src//IO//Student1"));
Object obj = ois.readObject();
System.out.println(obj);
ois.close();
}
}
额外拓展
IO流的应用
IO与Properties拓展
Properties是一个Map集合,是key和value都是String类型。
想将userinfo文件总的数据加载到Properties对象当中。
package IO;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
public class IOPropertise_test01 {
public static void main(String[] args) throws IOException {
//新建一个输入流对象
FileReader reader = new FileReader("src//IO//userinfo");
//新建一个Map集合
Properties pro = new Properties();
//调用Properties对象的load方法将文件中的数据加载到Map集合中。
pro.load(reader); //文件中的数据顺着管道加载到Map集合中,其中等号=左边为key,右边做value。
//通过key来获取value
String username = pro.getProperty("username");
System.out.println(username);
}
}
IO+Properties的联合应用
以后经常改变的数据,可以单独写到一个文件中,使用程序动态读取。
将来只需要修改这个文件的内容,java代码不需要改动,不需要重新
编译,服务器也不需要重启。就可以拿到动态的信息。