一.数据输入输出流
数据输入流: DataInputStream
数据输出流: DataOutputStream
这类流的特点是可以读和写基本数据类型
我们通过调用方法来实现这一目的
package org.jimmy.demo;
import java.io.*;
/**
* @Author: Administrator
* @CreateTime: 2019-01-21 15:50
*/
public class IODemo {
public static void main(String[] args) throws IOException {
DataOutputStream out = new DataOutputStream(new FileOutputStream("a.txt"));
DataInputStream in = new DataInputStream(new FileInputStream("a.txt"));
out.writeChar('a');
out.writeUTF("你好");
out.writeBoolean(true);
out.writeInt(12);
out.writeInt(78);
char c = in.readChar();
String s = in.readUTF();
boolean b = in.readBoolean();
int i = in.readInt();
int i1 = in.readInt();
System.out.println(c);
System.out.println(s);
System.out.println(b);
System.out.println(i);
System.out.println(i1);
in.close();
out.close();
}
}
这里,刚开始怎么写入的,就怎么读,顺序不要乱。
a
你好
true
12
78
二.内存操作流
内存操作流,顾名思义,是在内存中进行操作,无需关联文件,数据的读写只在内存中进行,所以内存操作流也无需关闭
内存操作流的概述
内存操作流可以分为:
操作字节数组——
ByteArrayOutputStream
ByteArrayInputStream
操作字符数组——
CharArrayWrite
CharArrayReader
操作字符串——
StringWriter
StringReader
我们来通过一段代码对一些方法作以了解
操作字节数组:
package org.jimmy.demo2;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* @Author: Administrator
* @CreateTime: 2019-01-21 16:08
*/
public class IODemo {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write(19);
out.write("你好".getBytes());
byte[] bytes = out.toByteArray();//取出存在缓冲区的数据
String s = new String(bytes);
System.out.println(s);//将数据转成字符串形式输出
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
byte[] bytes1 = new byte[1024 * 8];
int i = in.read(bytes1,0,4);
System.out.println(new String(bytes1,0,i));
}
}
你
要注意,在进行读的操作时,每次读的最后一个字节要确保是一个数据刚好结束,例如上面代码中,一个汉字占三个字节,如果从零读到第二个字节的话,这个“你”不能输出,输出会是一个乱码,所以从0读到4,则可以将“你”读出来
操作字符数组:
package org.jimmy.demo2;
import java.io.CharArrayWriter;
/**
* @Author: Administrator
* @CreateTime: 2019-01-21 17:01
*/
public class IODemo2 {
public static void main(String[] args) {
CharArrayWriter chw = new CharArrayWriter();
chw.write(2);
chw.write('s');
chw.write(new char[]{'2','d','a','t'},0,2);//读取字符数组的一部分
java.lang.String s = chw.toString();
System.out.println(s);
}
}
s2d
操作字符串的操作与字符数组类似
三.打印流
打印流分为字符流和字节流,而且只能写,不能读,所以一般需要别的写入操作来配合
我们经常用到的输出到屏幕就是用打印流来实现,例如下面这段代码:
public class IODemo3 {
public static void main(String[] args) {
PrintStream out=System.out;//关联屏幕
out.println(100);
out.print(true);
}
}
100
true
这就是输出语句的由来;
字节操作打印流有一个特点,其他的字节流都需要我们来手动刷新,但打印流可以通过传入布尔类型的参数来实现自动刷新,但在写入数据时调用println,printf,format中的一个方法才能执行自动刷新,如果调用write方法时仍需要flush方法来刷新;
public class IODemo4 {
public static void main(String[] args) throws IOException {
PrintWriter prw = new PrintWriter(new FileOutputStream("b.txt"), true);
prw.println("ab");
prw.write(111);
prw.flush();
prw.println("你好");
prw.close();
}
}
b.txt被自动创建,其内容为:
ab
o你好
我们同样可以用打印流来实现文本文件复制,一次读取一行,且实现自动刷新换行:
public class IODemo5 {
public static void main(String[] args) throws IOException {
BufferedReader bfr = new BufferedReader(new FileReader("b.txt"));
PrintWriter prw = new PrintWriter(new FileOutputStream("c.txt"),true);
String line=null;
while ((line=bfr.readLine())!=null){
prw.println(line);
}
bfr.close();
prw.close();
}
}
四.随机访问流
随机访问流(RandomAccessFile)其实并不属于流,它是Object类的一个子类,但他融合了InputStream和OutputStream的功能,所以他有一个很有意思的特点,能读能写,只需要在new的过程中通过参数来决定是否可以读和写;
随机访问流还有一个特点就是他可以设置文件指针,可以不用按顺序来读取文件,可以通过seek方法来读取指定位置的数据。
public class IODemo6 {
public static void main(String[] args) throws IOException {
RandomAccessFile raw = new RandomAccessFile("c.txt", "rw");
raw.writeInt(3);
long pointer = raw.getFilePointer();//获取文件指针
System.out.println(pointer);//4
raw.writeUTF("你好");
long pointer1 = raw.getFilePointer();
System.out.println(pointer1);//12
raw.seek(4);
String s = raw.readUTF();
System.out.println(s);
raw.close();
}
}
4
12
你好
获取文件指针操作时会发现,在获取UTF的指针位置时,明明两个汉字只占了六个字节,前面的int类型占四个字节,加起来应该是十才对,为什么最后的指针位置是12,这里会多读两个字节 是因为writeUTF()会多些两个字节,而seek()方法会将指针转移,这样再次执行操作时,会在转移后的位置进行操作。
五.序列化流与反序列化流
序列化,指的就是将对象通过流的方式存储到文件中,相对的,反序列化就是将文件中存储的对象通过流的方式还原成对象,但这个对象必须要实现Serializable 接口才能被序列化,Serializable 接口只是一个标记接口,里面并没有什么内容。
序列化过程:
public class IODemo7 {
public static void main(String[] args) throws IOException {
Person person = new Person("张三",23);
ObjectOutputStream objout = new ObjectOutputStream(new FileOutputStream("Person.txt"));
objout.writeObject(person);
objout.close();
}
}
反序列化过程:
public class IODemo8 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream objin = new ObjectInputStream(new FileInputStream("Person.txt"));
Person person = (Person) objin.readObject();
System.out.println(person.getName()+"==="+person.getAge());
objin.close();
}
}
我们可以将某个对象通过序列化形式来保存起来,等到要用的时候再反序列化,这样就不用每次去重新创建这么麻烦。