本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1、四个基本的抽象基类
InputStream 字节输入流
OutputStream 字节输出流
Reader 字符输入流
Writer 字符输出流
读写文件的步骤:
(1)打开流,如果是读文本文件,用FileReader,写文本文件,用FileWriter,读二进制文件,用FileInputStream,写二进制文件,用FileOutputStream
(2)通过流处理数据
(3)关闭流
2、字符输入流 Reader 和字节输入流 inputStream
FileReader读取文件过程
简略版本:
@Test
public void test1() throws IOException{
FileReader fileReader = new FileReader("一个文本文件");
int ch = fileReader.read();
while(ch != -1){
System.out.print((char)ch);
ch = fileReader.read();
}
fileReader.close();
}
标准版本:
@Test
public void test(){
//1)声明引用,初始化为null
FileReader fileReader = null;
//2)try catch finally
try{
//5)创建流对象,建立通道
fileReader = new FileReader("一个文本文件"); //在当前目录读取此文件,项目目录是当前目录
//6)处理数据
int ch = fileReader.read(); //读到的是字符的码值
while(ch != -1){
System.out.print((char)ch); //将码值强转成字符
ch = fileReader.read();
}
} catch (IOException e){
//4)处理异常
e.printStackTrace();
}finally { //一定可以关闭流
//3)关闭流
if(fileReader != null){
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
问题: 一个一个读,效率太低!
使用缓冲区读取文本文件
@Test
public void test3(){
FileReader fileReader = null;
try{
fileReader = new FileReader("一个文本文件");
char[] buff = new char[100];
int realCount = fileReader.read(buff);
while(realCount != -1){
//处理已经读到的数据
for(int i = 0; i < realCount; i++){ //处理实际读到的字符数
System.out.print(buff[i]);
}
//继续读后面的数据
realCount = fileReader.read(buff);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(fileReader != null){
try {
fileReader.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
练习: 使用缓冲区读文件,并且加上每行的行号
@Test
public void test4(){
FileReader fileReader= null;
int line = 1;
System.out.print(line + " ");
try {
fileReader = new FileReader("CollectionTest.java");
char[] buff = new char[100];
int realCount = fileReader.read(buff);
while(realCount != -1){
for(int i = 0; i < realCount; i++){
System.out.print(buff[i]);
if(buff[i] == '\n') {
System.out.print(++line + " ");
}
}
realCount = fileReader.read(buff);
}
} catch (Exception e){
e.printStackTrace();
} finally {
if(fileReader != null){
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
缓冲区大小为8192时,读取文件的效率最好。
3、字符输出流 Writer 和字节输出流 OutputStream
FileWriter写文本文件操作
@Test
public void test2(){
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter("写一个文本文件");
fileWriter.write('a');
fileWriter.write('b');
fileWriter.write('c');
fileWriter.write('\r');
fileWriter.write('\n');
fileWriter.write('1');
fileWriter.write('2');
fileWriter.write('3');
fileWriter.write(13);
fileWriter.write(10);
fileWriter.write('我');
fileWriter.write('是');
fileWriter.write('汉');
fileWriter.write(13);
fileWriter.write(10);
}catch (Exception e){
e.printStackTrace();
}finally {
if(fileWriter != null){
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用缓冲区批量写入文本数据
@Test
public void test5(){
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter("写一个文本文件");
String[] contents = {"随便写上一些内容1",
"随便写上一些内容2",
"随便写上一些内容3",
"jfkdsdlnmnc",
"积分卡死了讲课费街坊邻居斯柯达",
"随便写上一些内容1",
"随便写上一些内容1",};
for(int i = 0; i < contents.length; i++){
char[] charArray = contents[i].toCharArray();
//fileWriter.write(charArray); //直接把一个数组的内容写入到输出流中
//fileWriter.write(charArray,4,5); //第二个参数是offset偏移量,第三个参数是lenth长度,表示从下标4开始,每次写5个字符
fileWriter.write(charArray,4,charArray.length - 4);
fileWriter.write(13); //写回车
fileWriter.write(10); //写换行
}
} catch (Exception e){
e.printStackTrace();
} finally {
if(fileWriter != null){
try {
fileWriter.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
练习: 编写程序FileCopy.java,在测试方法中,将FileCopy.java复制为FileCopy.java.bak文件。
@Test
public void test(){
FileReader fileReader = null;
FileWriter fileWriter = null;
try {
fileReader = new FileReader("FileCopy.java");
fileWriter = new FileWriter("FileCopy.java.bak");
char[] buff = new char[100];
//以读为主导
int realCount = fileReader.read(buff);
while(realCount != -1){
//处理已经读到的数据
//在处理已经读到的数据时,写文件
fileWriter.write(buff,0,realCount);
//继续读
realCount = fileReader.read(buff);
}
} catch(Exception e){
e.printStackTrace();
} finally {
if(fileReader != null){
try {
fileReader.close();
}catch (Exception e){
e.printStackTrace();
}
}
if(fileWriter != null){
try {
fileWriter.close();
}catch (Exception e1){
e1.printStackTrace();
}
}
}
}
}
缓冲流 FileInputStream FileOutputStream
使用缓冲流复制二进制文件,非文本文件。缓冲流可以处理任意文件。
@Test
public void test1(){
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
fileInputStream = new FileInputStream("1.mp3");
fileOutputStream = new FileOutputStream("2.mp3");
byte[] buff = new byte[8192];
int realCount = fileInputStream.read(buff);
while(realCount != -1){
fileOutputStream.write(buff,0,realCount);
realCount = fileInputStream.read(buff);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(fileInputStream != null){
try {
fileInputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
if(fileOutputStream != null){
try {
fileOutputStream.close();
}catch (Exception e1){
e1.printStackTrace();
}
}
}
}
4、缓冲流BufferedReader和BufferedWriter(处理流)
使用包装流BufferedReader读取文件内容
@Test
public void test6(){
FileReader fileReader = null;
BufferedReader bufferedReader = null;
try {
fileReader = new FileReader("FileCopy.java");
bufferedReader = new BufferedReader(fileReader);
//最有价值的方法
String line = bufferedReader.readLine();
int count = 1;
System.out.print(count + " ");
while(line != null){
System.out.println(line);
line = bufferedReader.readLine();
System.out.print(++count + " ");
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(bufferedReader != null){
try {
//只需要关闭高级流
bufferedReader.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
使用包装流BufferedWriter写文件
@Test
public void test7(){
FileWriter fileWriter = null;
BufferedWriter bufferedWriter = null;
try {
fileWriter = new FileWriter("使用缓冲流写文本");
bufferedWriter = new BufferedWriter(fileWriter);
String[] contents = {"随便写上一些内容1",
"随便写上一些内容2",
"随便写上一些内容3",
"jfkdsdlnmnc",
"积分卡死了讲课费街坊邻居斯柯达",
"随便写上一些内容1",
"随便写上一些内容1",};
for(String string : contents){
bufferedWriter.write(string);
//最有价值的方法,可以写入跨平台的换行
bufferedWriter.newLine();
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(bufferedWriter != null){
try {
bufferedWriter.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
5、终极处理流:对象流
ObjectInputStream和ObjectOutputStream字节流
使用对象输出流ObjectOutputStream写二进制文件
@Test
public void test8(){
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
fileOutputStream = new FileOutputStream("对象输出流二进制文件");
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
objectOutputStream = new ObjectOutputStream(bufferedOutputStream);
objectOutputStream.writeInt(10); //数据在内存中如何保存,它就如何写入文件
objectOutputStream.writeBoolean(false);
objectOutputStream.writeDouble(3.33);
}catch (Exception e){
e.printStackTrace();
}finally {
if(objectOutputStream != null){
try {
objectOutputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
使用对象输入流ObjectInputStream读二进制文件
@Test
public void test9(){
FileInputStream fileInputStream = null;
BufferedInputStream bufferedInputStream = null;
ObjectInputStream objectInputStream = null;
try {
fileInputStream = new FileInputStream("对象输出流二进制文件");
bufferedInputStream = new BufferedInputStream(fileInputStream);
objectInputStream = new ObjectInputStream(bufferedInputStream);
int readInt = objectInputStream.readInt();
boolean readBoolean = objectInputStream.readBoolean();
double readDouble = objectInputStream.readDouble();
System.out.println(readInt + " " + readBoolean + " " + readDouble);
}catch (Exception e){
e.printStackTrace();
}finally {
if(objectInputStream != null){
try {
objectInputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
练习:使用对象流写入50个100以内的随机整数,并使用对象输入流读取出来
@Test
public void test10(){
FileInputStream fileInputStream = null;
BufferedInputStream bufferedInputStream = null;
ObjectInputStream objectInputStream = null;
try {
fileInputStream = new FileInputStream("写入50个100以内随机整数");
bufferedInputStream = new BufferedInputStream(fileInputStream);
objectInputStream = new ObjectInputStream(bufferedInputStream);
for(int i = 0; i < 50; i++){
System.out.println(objectInputStream.readInt());
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(objectInputStream != null){
try {
objectInputStream.close();
}catch (Exception e1){
e1.printStackTrace();
}
}
}
}
@Test
public void exer(){
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedoutputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
fileOutputStream = new FileOutputStream("写入50个100以内随机整数");
bufferedoutputStream = new BufferedOutputStream(fileOutputStream);
objectOutputStream = new ObjectOutputStream(bufferedoutputStream);
for(int i = 0; i < 50; i++){
objectOutputStream.writeInt((int)(Math.random() * 100));
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (objectOutputStream != null){
try {
objectOutputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
使用ObjectOutputStream序列化java对象
序列化:将java对象输出到流中,以便方法的远程调用(网络调用)
class Student implements Serializable{
private int id;
private String name;
private int age;
private int grade;
public Student() {
}
public Student(int id, String name, int age, int grade) {
this.id = id;
this.name = name;
this.age = age;
this.grade = grade;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", grade=" + grade +
'}';
}
}
@Test
public void serialize() throws IOException {
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedoutputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
fileOutputStream = new FileOutputStream("对象序列化");
bufferedoutputStream = new BufferedOutputStream(fileOutputStream);
objectOutputStream = new ObjectOutputStream(bufferedoutputStream);
Student s1 = new Student(1, "张三", 14, 2);
Student s2 = new Student(1, "张三1", 14, 2);
Student s3 = new Student(1, "张三2", 14, 2);
objectOutputStream.writeObject(s1);
objectOutputStream.writeObject(s2);
objectOutputStream.writeObject(s3);
}catch (Exception e){
e.printStackTrace();
}finally {
if (objectOutputStream != null){
try {
objectOutputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
注意: 静态属性不可以被序列化,只序列化对象在GC区中的数据,被transient修饰的属性不能被序列化(private transient int age)
使用ObjectInputStream实现对象的反序列化
@Test
public void unserialize(){
FileInputStream fileInputStream = null;
BufferedInputStream bufferedInputStream = null;
ObjectInputStream objectInputStream = null;
try {
fileInputStream = new FileInputStream("对象序列化");
bufferedInputStream = new BufferedInputStream(fileInputStream);
objectInputStream = new ObjectInputStream(bufferedInputStream);
Object object1 = objectInputStream.readObject();
Object object2 = objectInputStream.readObject();
Object object3 = objectInputStream.readObject();
System.out.println(object1);
System.out.println(object2);
System.out.println(object3);
}catch (Exception e){
e.printStackTrace();
}finally {
if(objectInputStream != null){
try {
objectInputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
练习:写一个person类,包含属性name,age,gender,要求性别不序列化,创建两个对象,序列化到文件中,查看文件,并反序列化,拿到对象。
class Person implements Serializable{
private String name;
private int age;
private transient String gender;
public Person() {
}
public Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
@Test
public void exer2(){
FileInputStream fileInputStream = null;
BufferedInputStream bufferedInputStream = null;
ObjectInputStream objectInputStream = null;
try {
fileInputStream = new FileInputStream("序列化对象练习");
bufferedInputStream = new BufferedInputStream(fileInputStream);
objectInputStream = new ObjectInputStream(bufferedInputStream);
System.out.println(objectInputStream.readObject());
System.out.println(objectInputStream.readObject());
}catch (Exception e){
e.printStackTrace();
}finally {
if(objectInputStream != null){
try {
objectInputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
@Test
public void exer1(){
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
fileOutputStream = new FileOutputStream("序列化对象练习");
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
objectOutputStream = new ObjectOutputStream(bufferedOutputStream);
Person p1 = new Person("张三", 45, "男");
Person p2 = new Person("小红", 16, "女");
objectOutputStream.writeObject(p1);
objectOutputStream.writeObject(p2);
}catch (Exception e){
e.printStackTrace();
}finally {
if(objectOutputStream != null){
try {
objectOutputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
一个一个对象序列化太麻烦,可以使用对象数组批量进行对象的序列化
@Test
public void exer2(){
FileInputStream fileInputStream = null;
BufferedInputStream bufferedInputStream = null;
ObjectInputStream objectInputStream = null;
try {
fileInputStream = new FileInputStream("序列化对象练习");
bufferedInputStream = new BufferedInputStream(fileInputStream);
objectInputStream = new ObjectInputStream(bufferedInputStream);
/*
System.out.println(objectInputStream.readObject());
System.out.println(objectInputStream.readObject());
*/
Person[] arr = (Person[]) objectInputStream.readObject();
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(objectInputStream != null){
try {
objectInputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
@Test
public void exer1(){
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
fileOutputStream = new FileOutputStream("序列化对象练习");
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
objectOutputStream = new ObjectOutputStream(bufferedOutputStream);
Person p1 = new Person("张三", 45, "男");
Person p2 = new Person("小红", 16, "女");
/*
objectOutputStream.writeObject(p1);
objectOutputStream.writeObject(p2);
*/
Person[] arr = {p1,p2};
objectOutputStream.writeObject(arr);
}catch (Exception e){
e.printStackTrace();
}finally {
if(objectOutputStream != null){
try {
objectOutputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
数组没有集合方便,使用集合序列化对象
@Test
public void exer2(){
FileInputStream fileInputStream = null;
BufferedInputStream bufferedInputStream = null;
ObjectInputStream objectInputStream = null;
try {
fileInputStream = new FileInputStream("序列化对象练习");
bufferedInputStream = new BufferedInputStream(fileInputStream);
objectInputStream = new ObjectInputStream(bufferedInputStream);
/*
System.out.println(objectInputStream.readObject());
System.out.println(objectInputStream.readObject());
Person[] arr = (Person[]) objectInputStream.readObject();
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}*/
List<Person> list= (List<Person>)objectInputStream.readObject();
Iterator<Person> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(objectInputStream != null){
try {
objectInputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
@Test
public void exer1(){
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
fileOutputStream = new FileOutputStream("序列化对象练习");
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
objectOutputStream = new ObjectOutputStream(bufferedOutputStream);
Person p1 = new Person("张三", 45, "男");
Person p2 = new Person("小红", 16, "女");
/*
objectOutputStream.writeObject(p1);
objectOutputStream.writeObject(p2);
Person[] arr = {p1,p2};
objectOutputStream.writeObject(arr);
*/
List<Person> list = new ArrayList<>();
list.add(p1);
list.add(p2);
objectOutputStream.writeObject(list);
}catch (Exception e){
e.printStackTrace();
}finally {
if(objectOutputStream != null){
try {
objectOutputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
6、转换流 InputStreamReader 和 OutputStreamReader
在处理字符文件时,比较麻烦,因为在Unicode和GBK编码下,一个汉字所占的字节数不同,所以转换流的作用是将难处理的字节文本文件转换成字符流。
FileReader只能处理和项目一致的编码的文本文件。
使用InputStreamReader读文件(标准做法)
@Test
public void test11(){
//FileReader fileReader = null; 不好用
FileInputStream fileInputStream = null;
InputStreamReader inputStreamReader = null; //转换流
BufferedReader bufferedReader = null;
try {
//fileReader = new FileReader("FileCopy.java"); //只能处理和项目一致的编码的文本文件
fileInputStream = new FileInputStream("FileCopy.java");
//inputStreamReader = new InputStreamReader(fileInputStream); //使用的是默认的编码方式
inputStreamReader = new InputStreamReader(fileInputStream,"GBK"); //指明转换流在处理字节数据时按照某种编码方式处理字符串
bufferedReader = new BufferedReader(inputStreamReader);
String line = bufferedReader.readLine();
int count = 1;
System.out.print(count + " ");
while(line != null){
System.out.println(line);
line = bufferedReader.readLine();
System.out.print(++count + " ");
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(bufferedReader != null){
try {
//只需要关闭高级流
bufferedReader.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
使用OutputStreamReader写文件(标准做法)
@Test
public void test12(){
FileOutputStream fileOutputStream = null;
OutputStreamWriter outputStreamWriter =null;
BufferedWriter bufferedWriter = null;
try {
fileOutputStream = new FileOutputStream("写一个文本文件");
outputStreamWriter = new OutputStreamWriter(fileOutputStream,"utf8"); //写文件时,把字符串用某种编码方式写入
bufferedWriter = new BufferedWriter(outputStreamWriter);
bufferedWriter.write("abc我和你");
}catch (Exception e){
e.printStackTrace();
}finally {
if(bufferedWriter != null){
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
7、IO流体系总览