一、IO流原理
二、IO流的分类
根据操作数据单位划分:字节流、字符流
根据数据的流向划分: 输入流、输出流
根据流的角色划分:节点流、处理流
三、IO流的体系结构
1.字符流的读写操作
1.1 读取文件
//读取文件操作
FileReader fr = null;
try {
// 实例化File类的对象,指明要操作的文件
File file = new File("1.txt");
// 提供具体的流
fr = new FileReader(file);
// read():返回读入的一个字符,如果达到文件末尾,返回-1
int read;
do {
read = fr.read();
System.out.println((char) read);
} while (read != -1);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
// 流的关闭
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
说明:
1.read()的理解: 返回读入的一个字符。如果达到文件末尾,返回-1
2.异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
3.读入的文件一定要存在,否则就会报FiLeNotFoundException。
char[] cbuf = new char[5];
//read(char[] cbuf): 返回每次读入cbuf数组中的字符个数。如果达到文件末尾,返回-1
int len;
while ((len = fr.read(cbuf)) != -1) {
// 错误的写法:最后一次的长度不足字符数组的长度时,会有遗留数据
/* for (int i = 0; i < cbuf.length; i++) {
System.out.println(cbuf[i]);
}*/
for (int i = 0; i < len; i++) {
System.out.println(cbuf[i]);
}
// 错误的写法二:和上面原理一样
// String str = new String(cbuf);
String str = new String(cbuf, 0, len);
System.out.println(str);
}
1.2 写入文件
FileWriter fw = null;
try {
// 1.提供File类的对象,指明写出到的文件
File file = new File("hello.txt");
// 2.提供FLeWriter的对象,用于数据的写出
fw = new FileWriter(file, true);
// 3.写出的操作
fw.write("I have a dream!\n");
fw.write("you need to have a dream!");
} catch (IOException e) {
throw new RuntimeException();
} finally {
// 4.流资源的关闭
try {
fw.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
2. 字节流的读写操作
File srcFile = new File( pathname::"爱情与友情.jpg");
File destFile = new File( pathname:"爱情与友情2.jpg");
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
//复制的过程
byte[] buffer = new byte[5];
int len;
while((len = fis.read(buffer)) != -1){
fos .write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
if (fos != null) {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
结论:
1.对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
2.对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...)使用字节流处理
3.文本文件的复制,不在控制台展示可以用字节流操作
3. 缓冲流的读写操作(处理流)
1.作用:提升流的读取、写入的速度
2.原因:内部提供了一个缓冲区,默认8192字节大小
3.处理流:包裹节点流的一种流
使用BufferedReader和BufferedWriter实现文本的复制
public void testBufferedReaderBufferedWriter(){
BufferedReader br = null;
BufferedWriter bw = null;
try {
//创建文件和相应的流
br = new BufferedReader(new FileReader(new File( pathname: "dbcp.txt")));
bw = new BufferedWriter(new FileWriter(new File( pathname: "dbcp1.txt")));
//读写操作
/* //方式一:
char[] cbuf = new char[1024];
int len;
while((len = br.read(cbuf)) != -1){
bw.write(cbuf, off: 0,len);
//bw.flush(); 刷新缓存,write操作会自动刷新
} */
//方式二:使用String
String data;
while((data = br.readLine()) != null) {
bw.writeLine(data); //data不包含换行符
bw.newLine(); // 提供换行的操作
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭资源
if(bw != null){
try {
bw.close();
} catch(IOException e) {
e.printStackTrace();
}
}
if(br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
说明: 关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略。
4. 转换流(处理流)
1.转换流:属于字符流
InputstreamReader: 一个字节的输入流转换为字符的输入流
OutputstreamWriter: 一个字符的输出流转换为字节的输出流
2.作用
提供字节流到字符流之间的转换
3.编码与解码
解码:字节、字节数组 --->字符数组、字符串
编码:字符数组、字符串 ---> 字节、字节数组
4.字符集
转换流实现utf-8格式文件转gbk格式
//1.造文件、造流
File file1 = new File( pathname: "dbcp.txt");
File file2 = new File( pathname: "dbcp_gbk.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
InputStreamReader isr = new InputStreamReader(fis, charsetName: "utf-8");
OutputStreamWriter osw = new Outputstreamwriter(fos , charsetName: "gbk");
//2.读写过程
char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
osw.write(cbuf, off: 0,len);
}
//3.关闭资源
isr.close();
osw.close();
5. 标准输入、输出流(处理流)
6. 打印流(处理流)
重新指定打印位置:打印字符到文件
7. 数据流(处理流)
8. 对象流
1.对象的序列化
Person需要满足如下的要求,方可序列化
1.需要实现接口: Serializable
2.当前类提供一个全局常量: serialVersionUID
3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。
public class Person implements Serializable {
public static final long serialVersionUID = 475463534532L;
private String name;
private int age;
private int id;
}
对象的序列化操作
public void testObjectOutputStream() {
ObjectOutputStream oos = null;
try {
//1.
oos = new ObjectOutputStream(new FileOutputStream( name: "object.dat"))
//2.
oos.writeObject(new string( original:"我爱北京天安门"));
oos.flush();//刷新操作
oos.writeObject(new Persion(name: "张三",age: "23")));
oos.flush();//刷新操作
} catch (IOException e) {
e.printStackTrace();
}finally {
if(oos != null){
// 3.
try {
foos.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
2.对象的反序列化:
将磁盘文件中的对象还原为内存中的一个java对象使用objectInputStream来实现
public void testobjecinputStream(){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream( name: "object.dat"));
Object obj = ois.readobject();
String str = (String) obj;
Person p = (Person) ois.readobject();
System.out.println(str);
System.out.println(p);
}
) catch (IOException e) {
e.printStackTrace();
}catch (ClassNotFoundException e) {
e.printStackTrace();
}
注意:
ObjectOutputStream和ObjectlnputStream不能序列化static和transient修饰的成员变量
9. 随机存取文件流
RandomAccessFile的使用
1.RandomAccessFile直接继承于java.lang.Object类,实现了DataInputDataoutput接口
2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
3.如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)