IO流
IO流(eclipse)
IO流的概念
IO:input(输入)读取文件中的数据
output(输出)将程序中的数据写入到文件之中
IO的分类
文件流
- FileReader 读文件(字符流)
- FileWriter 写文件(字符流)
- FileInputStram 读文件(字节流)
- FileOutputStream 写文件(字节流)
字符流及对应缓冲区FileWriter,FileReader,Buffer···
public static void main(String[] args) {
FileWriter fw = null;
FileReader fr = null;
try {
fw = new FileWriter("一个文件");
fw.write("插入字符abc");
fw.flush(); // 把缓冲区的数据刷入硬盘
fr = new FileReader("一个文件");
char[] buf = new char[1];
int realCount = fr.read(buf);
while (realCount != -1) {
// 处理数据
System.out.print(buf);
// ....
// 继续读
realCount = fr.read(buf);
}
} catch (Exception e) {
e.printStackTrace();
}
}
这个是比较普通的IO流写法,通常我们在传输文章数据时,会用这个方法,然而,当你想要传输音乐或者是视频文件的时候,则会出现错误,这个错误既不是编译错误也不是运行错误
因为我们的这个方法是字符流传输,是两个字节,而音乐和视频是一个字节,是使用字节流传输的
而且我们想要读取这个文件中的信息,我们还要用字符将文件中的字符提取出来,然后再通过判断是否读到最后,输出得到的字符,这样太麻烦了,一个字符一个字符读对于硬盘的利用率来说就是灾难
那么该怎么办呢,我们可以设置一个缓冲区,一次性的读取硬盘一个扇面的一大堆数据,然后再去处理
public static void main(String[] args) {
FileWriter fileWriter = null;
BufferedWriter bufferedWriter = null;
try {
fileWriter = new FileWriter("一个文件");
bufferedWriter = new BufferedWriter(fileWriter);
String[] content = {"asldfkjalskjdflkasjfd",
"我要写一些数据到文本文件",
"再来一行",
"再来一行吧...."};
for (String string : content) {
bufferedWriter.write(string);
bufferedWriter.newLine();// 最有价值方法, 写入跨平台的换行
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bufferedWriter != null) {
try {
bufferedWriter.close();
} catch (Exception e2) {
}
}
}
}
源节点(文件)>>>filereader(读文件)>>>bufferedreader(缓冲区)>>>程序
程序>>>bufferedwriter(缓冲区)>>>filewriter(写文件)>>>目标节点(文件)
缓冲区是为了更高效的利用硬盘,不同的缓冲区对应不同的读写方法
字节流及对应的缓冲区FileOutputStream
缓冲流:(输入流):BufferedInputStream、BufferedReader
(输出流):BufferedOutputStream、BufferedWriter
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
fos = new FileOutputStream("一个文件");
bos = new BufferedOutputStream(fos);
String[] content = {"asldfkjalskjdflkasjfd",
"我要写一些数据到文本文件",
"再来一行",
"再来一行吧...."};
bos.write(1);
//bos.write("w");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (Exception e2) {
}
}
}
这个时候我们用字节流输入,结果发现这个方法太可怜了,只能输入int,byte,输入一个String类型的数据都显示编译报错,那么我们来试着改善
可序列化对象
我们可以使用Serializable接口,直接添加对象,也可以使用ObjectOutputStream类,将缓冲区放入这个可序列化对象里,这用我们就可以通过调用这个对象的方法来实现写入操作
class Student implements Serializable{
private String name;
private int age;
private String gender;
private int score;
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 String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public Student(String name, int age, String gender, int score) {
super();
this.name = name;
this.age = age;
this.gender = gender;
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", gender=" + gender + ", score=" + score + "]";
}
}
public class Test {
public static void main(String[] args) {
FileOutputStream fos = null;
BufferedOutputStream bos = null;
ObjectOutputStream oos = null;
FileInputStream fis = null;
BufferedInputStream bis = null;
ObjectInputStream ois = null;
try {
fos = new FileOutputStream("序列化");
bos = new BufferedOutputStream(fos);
oos = new ObjectOutputStream(bos);
Student s1 = new Student("夏新", 21, "男", 100);
Student s2 = new Student("冷雪瞳", 21, "女", 90);
Student s3 = new Student("舒月舞", 20, "女", 80);
Student s4 = new Student("张妍", 19, "女", 70);
List<Student> list = new ArrayList<Student>();
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
/*oos.writeObject(new Student("夏新", 21, "男", 100));
oos.writeObject(new Student("冷雪瞳", 21, "女", 90));
oos.writeObject(new Student("舒月舞", 20, "女", 80)); 这个写法也是可以的
oos.writeObject(new Student("张妍", 19, "女", 70));*/
oos.writeObject(list);
oos.flush();//刷新,我们不关闭这个执行写的对象也可以得到数据
} catch (Exception e) {
e.printStackTrace();
}finally {
if(oos!=null) {
try {
oos.close();
} catch (Exception e2) {
// TODO: handle exception
}
}
}
try {
fis = new FileInputStream("序列化");//选择我们要打开的文件
bis = new BufferedInputStream(fis);
ois = new ObjectInputStream(bis);
//System.out.println(ois.readObject());
List<Student> list = (List<Student>) ois.readObject();
Iterator<Student> iterator = list.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
} catch (Exception e) {
// TODO: handle exception
}finally {
if(ois!=null) {
try {
ois.close();
} catch (Exception e2) {
// TODO: handle exception
}
}
}
}
}
ObjectOutputStream这个类真是太贴近人的心意了,我们甚至可以通过这个类的对象调用writeobject方法来添加对象,这样子我们可以同过list数组来选择排序或者添加操作,所以ObjectOutputStream这个类的IO流中是必不可少的
在我们的Student类中,实现了Serializable{接口,事实上这个接口一个方法也没有,但是我们还是要执行实现接口这个操作,不然会出现错误显示未序列化
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。
可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络(文件)之间。
序列化是为了解决在对对象流进行读写操作时所引发的问题。
序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,
implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造
一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以
将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
转换流
OutputStreamWriter就是一个例子,我们可以通过在创建是传入参数
new OutputStreamWriter(fos, “gbk”);
第一个参数是确认是写入流的对象
第二个参数是确实控制数据的格式
通常情况下eclipse能看到的格式是gbk,用utf8格式在eclipse下则会出现乱码,写文本文件时编码方式就是utf8。
其实这个转换流用的很少,转来转去很麻烦,只要文件打开可视,谁在乎一个文字到底是由两个字节组成还是三个字节组成的呢?
个人总结
按流向来说可以分为输入流和输出流
按类型来说可以分为节点流,处理流,缓冲流,转换流,打印流和对象流