基本介绍
1)节点流可以从一个特定的数据源读写数据,如:FileReader、FileWriter;
2)处理流(包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写能力,如:BufferedReader、BufferedWriter;
类属 | 分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
抽象基类 | InputStream | OutputStream | Reader | Writer | |
节点流 | 访问文件 | FileInuputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInuputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter | |
访问管道 | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter | |
访问字符串 | StringReader | StringWriter | |||
处理流 | 缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputStreamWriter | |||
对象流 | ObjectInputStream | ObjectOutputStream | |||
抽象基类 | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter | |
打印流 | PrintStream | PrintWriter | |||
推回输入流 | PushbackInputStream | PushbackReader | |||
特殊流 | DataInputStream | DataOutputStream |
节点流和处理流的区别和联系
1)节点流是底层流/低级流,直接跟数据源相接;
2)处理流包装节点流,即可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出;
3)处理流(包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连;
处理流的功能主要体现在以下两个方面:
1)性能的提高:主要以增加缓冲的方式来提高输入输出的效率;
2)操作的便捷:处理流可能提供了一系列的便捷方法,来一次输入输出大批量的数据,使用更加灵活方便。
字符处理流BufferedReader和BufferedWriter
★BufferedReader和BufferedWriter属于字符流,按照字符来读取数据;
★关闭时,只需要关闭外层流即可,包装流会自动关闭被包装的节点流。
BufferedReader测试代码
package com.pero.demo;
import org.junit.jupiter.api.Test;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* @author Pero
* @version 1.0
*/
public class BufferedReader_ {
public static void main(String[] args) {
}
@Test
public void test() throws IOException {
String path = "d:\\:demo\\test\\Story.txt";
String line;
BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
while ((line = bufferedReader.readLine()) != null){ //表示按行读取,如果达到流的末尾则返回null
System.out.println(line);
}
bufferedReader.close();
}
}
bufferedReader.close()源码
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close(); //FileReader关闭
} finally {
in = null;
cb = null;
}
}
}
BufferedWriter测试代码
package com.pero.demo;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
/**
* @author Pero
* @version 1.0
*/
public class BufferedWriter_ {
public static void main(String[] args) throws IOException {
//创建路径
String path = "d:\\demo\\test\\Story.txt";
//创建BufferedWriter(字符输出缓冲流)
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(path,true));
String str = "床前明月光,疑是地上霜";
bufferedWriter.write('a');
bufferedWriter.write(str+'\n');
bufferedWriter.write(str.toCharArray(),0,5);
//关闭外层流,传入的节点流new FileWriter(),会在底层关闭
bufferedWriter.close();
}
}
使用BufferedReader和BufferedWriter进行文本拷贝
package com.pero.demo;
import org.junit.jupiter.api.Test;
import java.io.*;
/**
* @author Pero
* @version 1.0
*/
public class BufferedCopy_ {
public static void main(String[] args) throws IOException {
//读取目标文件地址
String readerPath = "d:\\demo\\test\\Story.txt";
//拷贝数据存放地址
String writerPath = "d:\\demo\\test\\Book.txt";
char[] chars = new char[1024];
int length = 0;
//创建BufferedReader
BufferedReader bufferedReader = new BufferedReader(new FileReader(readerPath));
//创建BufferedWriter
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(writerPath));
while((length = bufferedReader.read(chars)) != -1) {
bufferedWriter.write(chars,0,length);
}
bufferedReader.close();
bufferedWriter.close();
}
@Test
public void test(){
//读取目标文件地址
String readerPath = "d:\\demo\\test\\Story.txt";
//拷贝数据存放地址
String writerPath = "d:\\demo\\test\\Book.txt";
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
String line = null;
try {
bufferedReader = new BufferedReader(new FileReader(readerPath));
bufferedWriter = new BufferedWriter(new FileWriter(writerPath));
while ((line = bufferedReader.readLine()) != null){
bufferedWriter.write(line);
bufferedWriter.newLine(); //换行,不进行换行操作的话,打印内容会在一行
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
if (bufferedReader != null){
try {
bufferedReader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (bufferedWriter != null){
try {
bufferedWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
BufferedInputStream和BufferedOutputStream字节处理流
BufferedInputStream是字节输入缓冲流,在创建BufferedInputStream时,会创建一个内部缓冲区数组;BufferedOutputStream是字节输出缓冲流,实现缓冲的输出流,可以将多个字节写入底层输出流中,而不必对每次字节写入调用底层系统。
字节处理流拷贝文件
package com.pero.demo;
import org.junit.jupiter.api.Test;
import java.io.*;
/**
* 字节流可以操作二进制文件,也可以操作文本文件
*
* @author Pero
* @version 1.0
*/
public class BufferedCopy02_ {
public static void main(String[] args) throws IOException {
String inputPath = "C:\\Users\\Pero\\Desktop\\4.jpeg";
String outputPath = "d:\\demo\\test\\boom.jpeg";
int length = 0;
byte[] bytes = new byte[1024];
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(inputPath));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(outputPath));
while((length = bufferedInputStream.read(bytes)) != -1){
bufferedOutputStream.write(bytes,0,length);
}
System.out.println("文件拷贝完毕");
if (bufferedInputStream != null){
bufferedInputStream.close();
}
if (bufferedOutputStream != null){
bufferedOutputStream.close();
}
}
@Test
public void test(){
String inputPath = "C:\\Users\\Pero\\Desktop\\4.jpeg";
String outputPath = "d:\\demo\\test\\boom.jpeg";
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
int length = 0;
byte[] bytes = new byte[1024];
try {
bufferedInputStream = new BufferedInputStream(new FileInputStream(inputPath));
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(outputPath));
while((length = bufferedInputStream.read(bytes)) != -1){
bufferedOutputStream.write(bytes,0,length);
}
System.out.println("文件拷贝完毕");
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
if (bufferedInputStream != null){
try {
bufferedInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (bufferedOutputStream != null){
try {
bufferedOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
对象流ObjectInputStream和ObjectOutputStream
将基本数据类型或者对象进行序列化和反序列化操作。
★序列化和反序列化
1)序列化是指保存数据时,保存数据的值和数据类型;
2)反序列化是指在恢复数据时,恢复数据的值和数据类型;
3)需要让某个对象支持序列化机制,则必须让其类是可序列化的,也就是让该类必须实现如下两个接口之一:
☆Serializable接口(标记接口)
☆Externalizable接口
ObjectOutputStream测试代码
package com.pero.demo;
import java.io.*;
/**
* @author Pero
* @version 1.0
*/
public class ObjectOutputStream_ {
public static void main(String[] args) throws IOException {
//保存文件路径
String path = "d:\\demo\\test.dat"; //序列化后,保存文件格式是按照特定格式来保存的
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(path));
//序列化数据到文件中
objectOutputStream.write(100); //int ->Integer(实现了Serializable接口)
objectOutputStream.writeBoolean(true);
objectOutputStream.writeChar('a');
objectOutputStream.writeByte(11010);
objectOutputStream.writeObject(new Dog("tom",16));
objectOutputStream.close();
}
}
//如果序列化类的对象,该类必须实现Serializable或者Externalizable接口
class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
}
ObjectInputStream测试代码
package com.pero.demo;
import java.io.*;
/**
* @author Pero
* @version 1.0
*/
public class ObjectInputStream_ {
public static void main(String[] args) throws IOException {
//反序列化文件路径
String path = "d:\\demo\\test.dat";
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(path));
//反序列化顺序必须和序列化顺序一致
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readChar());
System.out.println(objectInputStream.readByte());
System.out.println(objectInputStream.readUTF());
System.out.println(objectInputStream.readDouble());
try {
//dog的编译类型是Object,dog的运行类型是Dog
Object dog = objectInputStream.readObject();
System.out.println(dog.getClass());
System.out.println(dog);
//如果需要调用Dog的方法,需要向下转型,必须能够访问Dog类
//Dog类可以声明为public的
} catch (ClassNotFoundException e) { //类型转换,底层把对象从Object转成Dog
throw new RuntimeException(e);
}
//关闭外层流,底层会关闭节点流
objectInputStream.close();
}
}
注意事项和细节
1)读写顺序一致;
2)实现序列化或反序列化对象,必须实现serializable或者Externalizable接口;
3)序列化的类中建议添加SeriaVersionUID,为了提高版本的兼容性;
4)序列化对象时,默认将所有属性都进行序列化,但除了static或transient修饰的成员;
5)序列化对象时,要求属性类型也要实现序列化接口;
6)序列化具备可继承性,某类实现了序列化,那么它的子类也默认实现了序列化。
标准输入输出流
编译类型 | 运行类型 | 默认设备 | |
System.in标准输入 | InputStream | BufferedInputStream | 键盘 |
System.out标准输出 | PrintStream | PrintStream | 显示器 |
package com.pero.demo;
/**
* @author Pero
* @version 1.0
*/
public class InputAndOutput {
public static void main(String[] args) {
//标准输入流
//public final static InputStream in = null;
//编译类型InputStream,运行类型是BufferedInputStream
System.out.println(System.in.getClass());
//标准输出流
//public final static PrintStream out = null;
//编译类型PrintStream,运行类型是PrintStream
System.out.println(System.out.getClass());
}
}
转换流InputStreamReader和OutputStreamWriter
1)InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成(转换)Reader(字符流);
2)OutputStreamWriter:Writer的子类,可以将OutputStream(字节流)包装成Writer(字符流);
3)当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流;
4)可以在使用时指定编码格式(UTF-8,gnk等等)。
InputStreamReader测试代码
package com.pero.demo;
import java.io.*;
/**
* 默认读取文件时是默认UTF-8的编码
* 如果不指定读取文件的编码模式,当编码模式不相同时则会出现乱码
*
* @author Pero
* @version 1.0
*/
public class Transformation_ {
public static void main(String[] args) throws IOException {
String path = "d:\\demo\\test\\next.txt";
InputStreamReader inputStreamReader = null;
char[] chars = new char[1024];
int length = 0;
// bufferedReader = new BufferedReader(new FileReader(path));
// while ((readLine_ = bufferedReader.readLine()) != null){
// System.out.println(readLine_);
// }
// if (bufferedReader != null){
// bufferedReader.close();
// }
//第一次转换,将FileInputStream包装成InputStreamReader;
//指定编码类型为gbk/utf-8/utf8
inputStreamReader = new InputStreamReader(new FileInputStream(path),"utf8");
//第二次转换,将InputStreamReader包装成BufferedReader;
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
// BufferedReader bufferedReader1 = new BufferedReader(
// new InputStreamReader(
// new FileInputStream(path),"gbk"));
String s = bufferedReader.readLine();
System.out.println(s);
//关闭外层流
bufferedReader.close();
}
}
OutputStreamWriter测试代码
package com.pero.demo;
import java.io.*;
/**
* @author Pero
* @version 1.0
*/
public class OutputStreamWriter_ {
public static void main(String[] args) throws IOException {
String filePath = "d:\\demo\\test\\writer.txt";
String charSet = "utf-8" ;
//转为字符流
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
//字节流
new FileOutputStream(filePath,true),charSet); //要添加转换格式
outputStreamWriter.write("hello,world");
outputStreamWriter.close();
System.out.println("文件按照"+charSet+"保存文件成功");
}
}
打印流PrintStream(字节打印流)和PrintWriter(字符打印流)
PrintStream测试代码
package com.pero.demo;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
/**
* PrintStream字节打印流,输出流
*
* @author Pero
* @version 1.0
*/
public class PrintStream_ {
public static void main(String[] args) throws FileNotFoundException {
PrintStream out = System.out;
//在默认情况下,PrintStream输出数据的位置是标准输出,即显示器
/*
* public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
* */
out.print("hello,world");
//打印也可以用write来运行
try {
out.write("完成打印".getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
out.close();
//修改打印流输出的位置
//setOut方法可以修改printStream的输出路径
//PrintStream的构造器支持传入一个输出地址
//public static void setOut(PrintStream out) {
// checkIO();
// setOut0(out); //native方法,修改了out
// }
System.setOut(new PrintStream("d:\\demo\\test.txt"));
System.out.println("打印完成"); //输出到"d:\\demo\\test.txt"
}
}
PrintWriter测试代码
package com.pero.demo;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author Pero
* @version 1.0
*/
public class PrintWriter_ {
public static void main(String[] args) throws IOException {
//PrintWriter printWriter = new PrintWriter(System.out/*标准输出流*/);
PrintWriter printWriter = new PrintWriter(
new FileWriter("d:\\demo\\test\\look.txt"));
printWriter.print("打印成功");//输出到"d:\\demo\\test\\look.txt"文件
printWriter.close(); //如果没有关闭则不会进行内容输出
}
}
Properties类
properties是Hashtable的子类,读取和写入properties配置文件。
(BufferedReader+FileReader读取properties配置文件)
package com.pero.properties_;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/**
* @author Pero
* @version 1.0
*/
public class Properties01 {
public static void main(String[] args) throws IOException {
//读取mysql.properties文件,并得到ip,user,pwd
//用缓冲流BufferedReader+FileReader
//拿到后要进行拆解(繁琐步骤)
String read = null;
BufferedReader bufferedReader = new BufferedReader(
new FileReader("src\\mysql.properties"));
while ((read = bufferedReader.readLine()) != null) {
String[] split = read.split("="); //把字符串等号两边拆成字符串数组
if ("ip".equals(split[0])) {
System.out.println(split[1]);
}
}
bufferedReader.close(); //关闭流
}
}
1)properties类是专门用于读写配置文件的集合类:
配置文件的格式:
键=值
键=值
2)键值对不需要有空格,值不需要引号引起来。默认类型是String。
3)Properties的常见方法:
①load()方法:加载配置文件的键值对到Properties对象;
②list()方法:将数据显示到指定设备;
③getProperty(key)方法:根据键获取值;
④setProperty(key,value)方法:设置键值对到Properties对象;
⑤store()方法:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文会存储为unicode码。
package com.pero.properties_;
import org.junit.jupiter.api.Test;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
/**
* @author Pero
* @version 1.0
*/
public class Properties02 {
public static void main(String[] args) throws IOException {
//创建Properties对象
Properties properties = new Properties();
//加载指定路径文件键值对到Properties对象
properties.load(new FileReader("src\\mysql.properties")/*Reader or InputStream*/);
//获取值对象
String ip = properties.getProperty("ip");
System.out.println(ip);
//打印所有信息
properties.list(System.out/*PrintStream or PrintWriter*/);
}
@Test
public void test() throws IOException {
//用Properties类创建配置文件,修改配置文件内容
Properties properties = new Properties();
//properties对象中有三个键值对存储在其中(目前键值对在内存中)
properties.setProperty("ip","192.168.1.1");
properties.setProperty("user","杰克"); //保存时是中文unicode码
properties.setProperty("pwd","987654");
properties.setProperty("pwd","654456"); // 如果key值存在,再次创建则是修改
//将键值对数据存储在文件中
properties.store(
new FileWriter("src\\mysql2.properties")/*Writer or OutputStream*/,
null/*comments*/);
System.out.println("成功保存配置文件");
}
}
课后习题
package com.pero;
import org.junit.jupiter.api.Test;
import java.io.*;
/**
* 判断d盘下是否有文件夹mytemp,如果没有就创建mytemp文件夹
* 在mytemp文件夹下创建文件hello.txt
* 如果hello.txt已经存在,则提示文件已经存在不再重复创建
* 在hello.txt文件中写入hello,world
*
* @author Pero
* @version 1.0
*/
public class Homework01 {
public static void main(String[] args) {
}
@Test
public void test() throws IOException {
//创建文件路径
String filePath = "d:\\mytemp";
//创建当前地址的文件对象
File file = new File(filePath);
if(!file.exists()){ //如果文件不存在
if (file.mkdirs()){ //创建多级目录,如果创建成功返回true
System.out.println("文件夹创建成功");
}else {
System.out.println("文件夹创建失败");
}
}else {
System.out.println("文件夹存在");
}
File fileHello = new File("d:\\mytemp\\hello.txt");
if (!fileHello.exists()){
if (fileHello.createNewFile()){ //创建文件
FileWriter fileWriter = new FileWriter(fileHello);
fileWriter.write("hello,world");
fileWriter.close();
System.out.println("文件创建成功");
}else {
System.out.println("文件创建失败");
}
}else {
System.out.println("文件已经存在,不再重复创建");
FileWriter fileWriter = new FileWriter(fileHello,true);
fileWriter.write("hello,world");
fileWriter.close();
}
}
}
package com.pero;
import org.junit.jupiter.api.Test;
import java.io.*;
/**
* 使用BufferedReader读取一个文本文件,
* 为每一行加上行号,连同内容一并输出到屏幕上
*
* @author Pero
* @version 1.0
*/
public class Homework02 {
public static void main(String[] args) throws IOException {
String versePath = "d:\\books\\book\\verse.txt";
String line = null;
int temp = 1;
BufferedReader bufferedReader = new BufferedReader(new FileReader(versePath));
//遇到乱码时(默认处理为utf-8,如果文本文件是gbk将出现乱码),
// 使用转换流将FileInputStream->InputStreamReader[这里可以指定编码]->BufferedReader
PrintStream out = System.out;
while ((line = bufferedReader.readLine()) != null) {
if (temp % 2 != 0) {
out.print(temp + line + "," + '\n');
} else {
out.print(temp + line + "。" + '\n');
}
temp++;
}
temp = 1;
bufferedReader.close();
out.close();
}
@Test
public void test() throws IOException {
//把诗句写入文本文件中
//创建二级文件夹books\\book,将诗词verse.txt放进文件在中
String bookPath = "d:\\books\\book";
File file = new File(bookPath);
//判断这两个文件夹有没有,如果有就不用创建了,如果没有则创建
if (!file.exists()) {
if (file.mkdirs()) { //创建二级目录
System.out.println("文件夹创建成功");
} else {
System.out.println("文件夹创建失败");
}
} else {
System.out.println("文件夹存在");
}
//将诗词文本文件创建在book文件夹中
File fileVerse = new File(bookPath + "\\verse.txt");
if (!fileVerse.exists()) {
if (fileVerse.createNewFile()) {
System.out.println("诗词文本文件创建成功");
BufferedWriter bufferedWriter =
new BufferedWriter(
new FileWriter(bookPath + "\\verse.txt"));
bufferedWriter.write("锄禾日当午" + '\n' +
"汗滴禾下土" + '\n' +
"谁知盘中餐" + '\n' +
"粒粒皆辛苦");
System.out.println("诗词写入成功");
if (bufferedWriter != null) {
bufferedWriter.close();
}
} else {
System.out.println("诗词文本文件创建失败");
}
} else {
System.out.println("诗词文本文件已存在");
}
}
}
package com.pero;
import org.junit.jupiter.api.Test;
import java.io.*;
import java.util.Properties;
/**
* 编写dog.properties
* name=tom
* age=5
* color=red
* 编写Dog类(name,age,color)创建一个dog对象,读取dog.properties
* 用相应的内容完成初始化,并输出
*
* @author Pero
* @version 1.0
*/
public class Homework03 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Properties properties = new Properties();
FileReader fileReader = new FileReader("src\\dog.properties");
properties.load(fileReader);
//properties存储的数据默认为Object类
String name = properties.getProperty("name");
int age = Integer.parseInt(properties.getProperty("age"));
String color = properties.getProperty("color");
Dog dog = new Dog(name, age, color);
System.out.println(dog);
//序列化对象存放地址
String dogPath = "d:\\demo\\dog.dat";
ObjectOutputStream objectOutputStream =
new ObjectOutputStream(new FileOutputStream(dogPath));
objectOutputStream.writeObject(dog); //Dog类必须实现序列化接口
objectOutputStream.close();
System.out.println("dog对象序列化成功");
//反序列化对象打印出对象信息
ObjectInputStream objectInputStream =
new ObjectInputStream(new FileInputStream(dogPath));
Dog dogSee = (Dog)objectInputStream.readObject(); //向下转型
System.out.println(dogSee);
objectInputStream.close();
}
//创建dog.properties
@Test
public void test() throws IOException {
String dogSqlPath = "src\\dog.properties";
Properties properties = new Properties();
properties.setProperty("name","tom");
properties.setProperty("age","5");
properties.setProperty("color","red");
properties.store(new FileWriter(dogSqlPath),null);
System.out.println("dogSql文件保存成功");
}
}
class Dog implements Serializable{
private String name;
private int age;
private String color;
public Dog(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
}