文章目录
1. IO 流原理及流的分类
1.1 Java IO 流原理
1.2 流的分类
1.3 IO流体系图-常用的类
- IO流体系图
- 文件 VS 流
package com.xjz.file.inputstream_;
import org.junit.jupiter.api.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @author xjz_2002
* @version 1.0
* 演示 FileInputStream 的使用(字节输入流 文件 --> 程序)
*/
public class FileInputStream_ {
public static void main(String[] args) {
}
/**
* 演示读取文件..
* 单个字符的读取,效率比较低
* 使用 read()
*/
@Test
public void readFile01() {
String filePath = "d:\\hello.txt";
int readData = 0;
FileInputStream fileInputStream = null;
try {
//创建 FileInputStream 对象,用于读取 文件
fileInputStream = new FileInputStream(filePath);
//从该输入流读取一个字节的数据。如果没有输入可用,此方法将阻止
//如果返回 -1,表示读取完毕
while ((readData = fileInputStream.read()) != -1) {
System.out.println((char) readData); //转成 char 显示
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭文件流,释放资源
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 使用 read(byte[] b) 读取文件,提高效率
*/
@Test
public void readFile02() {
String filePath = "d:\\hello.txt";
//字节数组
byte[] buf = new byte[8];
int readLen = 0;
FileInputStream fileInputStream = null;
try {
//创建 FileInputStream 对象,用于读取 文件
fileInputStream = new FileInputStream(filePath);
//从该输入流读取一个字节的数据。如果没有输入可用,此方法将阻止
//如果返回 -1,表示读取完毕
//如果读取正常, 返回实际读取的字节数
while ((readLen = fileInputStream.read(buf)) != -1) {
// bytes - 要解码为字符的字节
// offset - 要解码的首字节的索引
// length - 要解码的字节数
System.out.print(new String(buf,0,readLen)); //显示
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭文件流,释放资源
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package com.xjz.file.inputstream_;
import org.junit.jupiter.api.Test;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author xjz_2002
* @version 1.0
*/
public class FileOutputStream01 {
public static void main(String[] args) {
}
/**
* 演示使用 FileOutputStream 将数据写到文件中,
* 如果该文件不存在,则创建该文件
*/
@Test
public void writeFile() {
//创建 FileOutputStream
String filePath = "d:\\a.txt";
FileOutputStream fileOutputStream = null;
try {
//得到 FileOutputStream 对象
//代码说明
//1. new FileOutputStream(filePath)创建方式,当写入内容时,会覆盖原来的内容
//2. new FileOutputStream(filePath,true)创建方式,当写入内容时,是追加到原来的内容的后面
fileOutputStream = new FileOutputStream(filePath,true);
//写入一个字节 write(int b);
//fileOutputStream.write('X');
//写入字符串 (byte[] b)
String str = "xjz,world";
//str.getBytes() 可以把 字符串 -》 字节数组
//fileOutputStream.write(str.getBytes());
/*
write(byte[] b, int off, int len) 将 len 字节从位于偏移量 off 的指定字节数组写入此文件输出流
*/
fileOutputStream.write(str.getBytes(),0,3);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 文件拷贝
package com.xjz.file.inputstream_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author xjz_2002
* @version 1.0
* 文件拷贝
*/
public class FileCopy {
public static void main(String[] args) {
//完成 文件拷贝,将 d:\\hnt.png 拷贝到d:\\hnt2.png
//思路分析
//1. 创建文件的输入流,将文件读入到程序
//2. 创建文件的输出流,将读取到的文件数据,写入到指定的文件
String srcFilePath = "d:\\hnt.png";
String destFilePath = "d:\\hnt2.png";
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream= null;
try {
fileInputStream = new FileInputStream(srcFilePath);
fileOutputStream = new FileOutputStream(destFilePath);
//定义一个字节数组,提高读取效率
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = fileInputStream.read(buf)) != -1){
//读取到后,就写入到文件 通过 fileOutputStream
//即 一边读,一边写
fileOutputStream.write(buf,0,readLen);//一定要使用这个方法
}
System.out.println("拷贝ok~");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭输入流和输出流,释放资源
try {
if (fileInputStream != null){
fileInputStream.close();
}
if (fileOutputStream != null){
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2. FileReader 和 FileWriter 介绍
2.1 FileReader 相关方法
package com.xjz.reader_;
import org.junit.jupiter.api.Test;
import java.io.FileReader;
import java.io.IOException;
/**
* @author xjz_2002
* @version 1.0
*/
public class FileReader_ {
public static void main(String[] args) {
}
/**
* 单个字符读取文件
*/
@Test
public void readFile01() {
String filePath = "d:\\important.txt";
FileReader fileReader = null;
int data = 0;
//1. 创建 FileReader对象
try {
fileReader = new FileReader(filePath);
//循环读取 使用read,单个字符读取
while ((data = fileReader.read())!= -1){
System.out.print((char)data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileReader != null){
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 字符数组读取文件
*/
@Test
public void readFile02() {
String filePath = "d:\\important.txt";
FileReader fileReader = null;
int readLen = 0;
char[] buf = new char[8];
//1. 创建 FileReader对象
try {
fileReader = new FileReader(filePath);
//循环读取 使用read(buf),返回的是实际读取到的字符数
//如果返回 -1,说明到文件结束
while ((readLen = fileReader.read(buf))!= -1){
System.out.print(new String(buf,0,readLen));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileReader != null){
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.2 FileWriter 常用方法
package com.xjz.write_;
import java.io.FileWriter;
import java.io.IOException;
/**
* @author xjz_2002
* @version 1.0
*/
public class FileWriter_ {
public static void main(String[] args) {
String filePath = "d:\\note.txt";
//创建 FileWriter 对象
FileWriter fileWriter = null;
char[] chars = {'a','b','c'};
try {
fileWriter = new FileWriter(filePath);//默认就是覆盖写入
//3) write(int):写入单个字符
fileWriter.write('X');
//4) write(char[]):写入指定数组
fileWriter.write(chars);
//5) write(char[],off,len):写入指定数组的指定部分
fileWriter.write("徐金卓".toCharArray(),0,3);
//6) write(string):写入整个字符串
fileWriter.write("你好,北京");
fileWriter.write("风雨之后,定见彩虹");
//7) write(string,off.len):写入字符串的指定部分
fileWriter.write("上海天津",0,2);
//在数据量大的情况下,可以使用循环操作
} catch (IOException e) {
e.printStackTrace();
} finally {
//对应 FileWriter , 一定要关闭流,或者 flush 才能真正的把数据写入到文件
//看源码就知道原因.
if (fileWriter != null){
try {
//关闭文件流,等价 flush() + 关闭
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("程序结束");
}
}
}
3. 节点流 和 处理流(BufferedReader、BufferedWriter)
- 节点流和处理流一览图
3.1 节点流和处理流的区别和联系
- 处理流的功能主要体现在一下两个方面:
package com.xjz.reader_;
import java.io.BufferedReader;
import java.io.FileReader;
/**
* @author xjz_2002
* @version 1.0
* 演示 bufferedReader 使用
*/
public class BufferedReader_ {
public static void main(String[] args) throws Exception {
String filePath = "d:\\a.java";
//创建 bufferedReader 对象
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
//读取
String line;//按行读取,效率高
//说明
//1. bufferedReader.readLine() 是按行读取文件
//2. 当返回 null 时,表示文件读取完毕
while ((line = bufferedReader.readLine()) != null){
System.out.println(line);
}
//关闭流,这里注意,只需要关闭 bufferedReader,因为底层会自动的去关闭 节点流
//FileReader
/*
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();//in 就是我们传入的 new FileReader(filePath), 关闭了.
} finally {
in = null;
cb = null;
}
}
}
*/
bufferedReader.close();
}
}
package com.xjz.write_;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
/**
* @author xjz_2002
* @version 1.0
* 演示 BufferedWriter 的使用
*/
public class BufferedWriter_ {
public static void main(String[] args) throws IOException {
String filePath = "d:\\ok.txt";
//创建 BufferedWriter
//说明
//1. new FileWriter(filePath,true) 表示以追加的方式写入
//1. new FileWriter(filePath) 表示以覆盖的方式写入
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));
bufferedWriter.write("徐金卓1-Java开发工程师");
bufferedWriter.newLine();//插入一个和系统相关的换行
bufferedWriter.write("徐金卓2-Java开发工程师");
bufferedWriter.newLine();//插入一个和系统相关的换行
bufferedWriter.write("徐金卓3-Java开发工程师");
bufferedWriter.newLine();//插入一个和系统相关的换行
//说明:关闭外层流即可,传入的 new FileWriter(filePath),会在底层关闭
bufferedWriter.close();
}
}
package com.xjz.write_;
import java.io.*;
/**
* @author xjz_2002
* @version 1.0
*/
public class BufferedCopy_ {
public static void main(String[] args) {
//说明
//1. BufferedReader 和 BufferedWriter 是安装字符操作
//2. 不要去操作 二进制文件[声音,视频,doc,pdf],可能造成文件损坏
//BufferedInputStream
//BufferedOutputStream
String srcFilePath = "d:\\a.java";
String destFilePath = "d:\\a4.java";
BufferedReader br = null;
BufferedWriter bw = null;
String line;
try {
br = new BufferedReader(new FileReader(srcFilePath));
bw = new BufferedWriter(new FileWriter(destFilePath));
//说明:readLine 读取一行内容,但是没有换行
while ((line = br.readLine())!=null){
//每读取一行,就写入
bw.write(line);
//插入一个换行
bw.newLine();
}
System.out.println("拷贝完毕~");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
try {
if (br != null){
br.close();
}
if (bw != null){
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.2 处理流-BufferedInputStream 和 BufferedOutputStream
3.3 介绍 BufferedOutputStream
package com.xjz.outputstream_;
import java.io.*;
/**
* @author xjz_2002
* @version 1.0
* 演示使用 BufferedOutputStream 和 BufferedInputStream 使用
* 使用他们,可以完成二进制文件拷贝
* 思考:字节流可以操作二进制文件,可以操作文本文件吗? 当然可以
*/
public class BufferedCopy02 {
public static void main(String[] args) {
// String srcFilePath = "d:\\hnt.png";
// String destFilePath = "d:\\hnt3.png";
String srcFilePath = "d:\\a.java"; //字节流也可以处理文本文件
String destFilePath = "d:\\a5.java";
//创建 BufferedInputStream 和 BufferedOutputStream 对象
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//因为 FileInputStream 是 InputStream 子类
bis = new BufferedInputStream(new FileInputStream(srcFilePath));
bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
//循环的读取文件,并写入到 destFilePath
byte[] buff = new byte[1024];
int readLen = 0;
//当返回 -1 时,就表示文件读取完毕
while ((readLen = bis.read(buff)) != -1 ){
bos.write(buff,0,readLen);
}
System.out.println("文件拷贝完毕");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流 , 关闭外层的处理流即可,底层会去关闭节点流
try {
if (bis != null){
bis.close();
}
if (bos != null){
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.4 对象流-ObjectInputStream 和 ObjectOutputStream
3.5 对象流介绍
功能:提供了对基本类型或对象类型的序列化和反序列化的方法
ObjectOutputStream 提供 序列化功能
ObjectInputStream 提供 反序列化功能
package com.xjz.outputstream_;
import java.io.*;
/**
* @author xjz_2002
* @version 1.0
* 演示 ObjectOutputStream 的使用,完成数据的序列化
*/
public class ObjectOutStream_ {
public static void main(String[] args) throws IOException {
//序列化后,保存的文件形式,不是存文本,而是按照他的格式来保存
String filePath = "d:\\data.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化数据到 d:\\data.dat
oos.writeInt(100); //int -> Integer(实现类 Serializable)
oos.writeBoolean(true); //boolean -> Boolean(实现类 Serializable)
oos.writeChar('a'); //char -> Character(实现类 Serializable)
oos.writeDouble(9.5); //double -> Double(实现类 Serializable)
oos.writeUTF("赵雷的朵");//String
//保存一个 person 对象
oos.writeObject(new Person("xjz",20));
//关闭流
oos.close();
System.out.println("数据保存完毕(序列化形式)");
}
}
//保存一个类,必须要实现它的序列化接口 Serializable
class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
package com.xjz.outputstream_;
import com.sun.corba.se.impl.encoding.CDROutputObject;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
/**
* @author xjz_2002
* @version 1.0
* 演示 ObjectInputStream 的使用,完成数据的 反 序列化
*/
public class ObjectInputStream_ {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1. 创建流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:\\data.dat"));
//2. 读取 注意顺序(必须和反序列化顺序一致,否则读取乱码)
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readDouble());
System.out.println(ois.readUTF());
//person 的编译类型是 object, person 的运行类型是 Person
Object person = ois.readObject();
System.out.println("运行类型="+person.getClass());
System.out.println("person信息=" + person);//底层 Object -> Person
//这里特别重要的细节:
//1. 如果我们希望调用 Person的方法,需要向下转型
//2. 需要我们将 Person类的定义,拷贝到可以引用的卑职
Person person2 = (Person) person;
System.out.println(person2.getName()); //xjz
//关闭流,关闭外层流即可,底层会关闭 FileInputStream 流
ois.close();
}
}
3.6 标准输入输出流
3.7 转换流-InputStreamReader 和 OutputStreamWriter
package com.xjz.transformation;
import java.io.*;
/**
* @author xjz_2002
* @version 1.0
* 演示使用 InputStreamReader 转换流解决中文乱码问题
* 将字节流 FileInputStream 转成字符流 InputStreamReader,指定编码 gbk/utf-8
*/
public class InputStreamReader_ {
public static void main(String[] args) throws IOException {
String filePath = "d:\\a.txt";
//解读
//1. 把 FileInputStream 转成 InputStreamReader
// //2. 指定编码 gbk
// InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
// //3. 把 InputStreamReader 传入 BufferedReader
// BufferedReader br = new BufferedReader(isr);
//将 2 和 3 合在一起
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath),"gbk"));
//4. 读取
String s = br.readLine();
System.out.println("读取内容=" + s);
//5. 关闭外层流
br.close();
}
}
package com.xjz.transformation;
import java.io.*;
/**
* @author xjz_2002
* @version 1.0
* 演示 OutputStreamWriter 使用
* 把 FileOutputStream 字节流,转成字符流 OutputStreamWriter
* 指定处理的编码 gbk/utf-8/utf8
*/
public class OutputStreamWriter_ {
public static void main(String[] args) throws IOException {
String filePath = "d:\\xjz.txt";
String charSet = "utf-8";
//把 FileOutputStream 字节流,转成字符流 OutputStreamWriter
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath), charSet));
bw.write("hello,周星驰");
bw.close();
System.out.println("按照" + charSet + " 保存文件成功~");
}
}
4. 打印流-PrintStream 和 PrintWriter
5. Properties 类
- 应用案例