一、文件
1.1 什么是文件
文件是保存数据的地方,最常见比如 word 文档,,txt 文件,excel文件,mp4文件等。它既可以保存一张图片、也可以保存视频、声音……
1.2 文件流
文件在程序中是以流的形式来操作的
流:数据在数据源(文件)和程序(内存)之间经历的路径
输入流:数据从数据源(文件)到程序(内存)的路径
输出流:数据从程序(内存)到数据源(文件)的路径
二、常用的文件操作
2.1 创建文件对象相关构造器和方法
相关方法
new File(String pathname) //根据路径构建一个 File对象
new File(File parent, String child) //根据父目录文件 + 子路径构建
new File(String parent, String child) //根据父目录 + 子路径构建
createNewFile() 创建新文件
应用案例演示
package com.hspedu.file;import org.junit.jupiter.api.Test;import java.io.File;import java.io.IOException;/*** @author HarborGao* @version 1.0*/public class FileCreate {public static void main(String[] args) {}//方式一@Testpublic void create01() {String filePath = "E:\\news1.txt";File file = new File(filePath);try {file.createNewFile();System.out.println("文件创建成功");} catch (IOException e) {e.printStackTrace();}}//方式二@Testpublic void create02() {File parentFilePath = new File("e:\\");String fileName = "news2.txt";File file = new File(parentFilePath, fileName);try {file.createNewFile();System.out.println("文件创建成功");} catch (IOException e) {e.printStackTrace();}}//方式三@Testpublic void create03() {String parentPath = "E:/";String filePath = "news3.txt";File file = new File(parentPath,filePath);try {file.createNewFile();System.out.println("文件创建成功");} catch (IOException e) {e.printStackTrace();}}}
2.2 获取文件的相关信息
| getName | 获取文件名 |
|---|---|
| getAbsolutePath | 获取文件绝对路径 |
| getParent | 获取父级目录 |
| length | 文件大小(字节) |
| exists | 文件是否存在 |
| isFile | 是否是一个文件 |
| isDirectory | 是否是一个目录 |
案例演示
package com.hspedu.file;import org.junit.jupiter.api.Test;import java.io.File;/*** @author HarborGao* @version 1.0*/public class FileInformation {public static void main(String[] args) {}@Testpublic void info() {File file = new File("e:\\news1.txt");System.out.println("文件名=" + file.getName());System.out.println("文件绝对路径=" + file.getAbsolutePath());System.out.println("文件父级目录=" + file.getParent());System.out.println("是否是一个文件=" + file.isFile());System.out.println("是否是一个目录=" + file.isDirectory());System.out.println("文件是否存在=" + file.exists());System.out.println("文件大小(字节)=" + file.length());}}
2.3 目录的操作和文件删除
| mkdir | 创建一级目录 |
|---|---|
| mkdirs | 创建多级目录 |
| delete | 删除空目录或文件 |
案例演示
package com.hspedu.file;import org.junit.jupiter.api.Test;import java.io.File;import java.io.IOException;/*** @author HarborGao* @version 1.0*/public class Directory {public static void main(String[] args) {}@Testpublic void m1() {String filePath = "e:\\news1.txt";File file = new File(filePath);if (file.exists()) {if (file.delete()) {System.out.println(filePath + "删除成功");} else {System.out.println(filePath + "删除失败");}} else {System.out.println("该文件不存在...");}}@Testpublic void m2() {String filePath = "e:\\demo02";File file = new File(filePath);if (file.exists()) {if (file.delete()) {System.out.println(filePath + "删除成功");} else {System.out.println(filePath + "删除失败");}} else {System.out.println("该目录不存在...");}}@Testpublic void m3() {String directoryPath = "e:\\demo\\a\\b\\c";File file = new File(directoryPath);if (file.exists()) {System.out.println("该目录已存在");} else {if (file.mkdirs()) {System.out.println(directoryPath + "目录创建成功");} else {System.out.println(directoryPath + "目录创建失败");}}}}
三、IO 流原理及流的分类
3.1 Java IO 流原理
- I / O是Input / Output 的缩写,I / O技术是非常实用的技术,用于处理数据传输。如读/写文件,网络通讯等
- Java程序中,对于数据的输入、输出操作以“流(Stream)”的方式进行
- java.io 包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据
- 输入 input:读取外部数据(如磁盘、光盘等存储设备中的数据)到程序(内存)中
- 输出 output:将程序(内存)数据输出到磁盘、光盘等存储设备中
3.2 流的分类
按操作数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符)文本文件
按数据流的流向不同分为:输入流、输出流
按流的角色的不同分为:节点流,处理流/包装流
| (抽象基类) | 字节流 | 字符流 |
|---|---|---|
| 输入流 | InputStream | Reader |
| 输出流 | OutputStream | Writer |
- Java的 IO流共涉及40多个类,实际上非常规则,都是从如上4个抽象基类派生的
- 由这4个类派生出来的子类名称都是以其父类名作为子类名后缀
四、IO 流体系图 - 常用的类
4.1 IO 流体系图

4.2 文件 VS 流
文件是存储在磁盘等媒介上的
而 流 是用来传输文件的
可以将文件看成商品,磁盘看成物流中心,流看成快递员,内存看成买家
4.3 FileInputStream 介绍
FileInputStream:文件字节输入流 用于读取磁盘上的文件到内存,按字节读取
应用案例:使用 FileInputStream 读取 hello.txt文件,并将文件内容显示到控制台
package com.hspedu.file;import org.junit.jupiter.api.Test;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;/*** @author HarborGao* @version 1.0* 演示 FileInputStream 的使用(字节输入流 文件 -> 程序)*/public class FileInputStream_ {public static void main(String[] args) {}/*** 演示读取文件* 单个字节读取,效率比较低* -> 使用 read(byte[] b)*/@Testpublic void readFile01() {String filePath = "e:\\hello.txt";int readDate = 0;FileInputStream fileInputStream = null;try {//创建 FileInputStream 对象,用于读取 文件fileInputStream = new FileInputStream(filePath);//从该输入流读取一个字节的数据。如果没有输入可用,此方法将阻止。//如果返回-1,表示读取完毕while ((readDate = fileInputStream.read()) != -1) {System.out.print((char) readDate); //转成char显示}} catch (IOException e) {e.printStackTrace();} finally {//关闭文件流,释放资源try {fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}}/*** 演示读取文件* -> 使用 read(byte[] b) 读取文件,提高效率*/@Testpublic void readFile02() {String filePath = "e:\\hello.txt";//字节数组byte[] buf = new byte[8]; //一次读取8个字节int readLen = 0;FileInputStream fileInputStream = null;try {//创建 FileInputStream 对象,用于读取 文件fileInputStream = new FileInputStream(filePath);//从该输入流最多读取8个字节的数据到字节数组。此方法将阻塞,直到某些输入可用//如果返回-1,表示读取完毕//如果读取正常,返回实际读取的字节数while ((readLen = fileInputStream.read(buf)) != -1) {System.out.print(new String(buf,0,readLen)); //转成char显示}} catch (IOException e) {e.printStackTrace();} finally {//关闭文件流,释放资源try {fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}}}
4.4 FileOutputStream 介绍
FileInputStream:文件字节输出流 用于将程序(内存)中的数据写入到磁盘上的文件中,按字节写入
应用案例:使用 FileOutputStream 在 a.txt 文件中写入 “hello,world”,如果文件不存在,会创建文件
package com.hspedu.outputstream_;import org.junit.jupiter.api.Test;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.nio.charset.StandardCharsets;/*** @author HarborGao* @version 1.0*/public class FileOutputStream_ {public static void main(String[] args) {}/*** 演示 FileOutputStream 将数据写入文件中* 如果该文件不存在,则创建该文件* 说明:* 1. new FileOutputStream(filePath) 创建方式,当写入内容时,会覆盖原来的内容* 2. new FileOutputStream(filePath,true) 创建方式,当写入内容时,是在文件末尾追加内容*/@Testpublic void writeFile() {//创建FileOutputStream对象String filePath = "e:\\a.txt";FileOutputStream fileOutputStream = null;try {fileOutputStream = new FileOutputStream(filePath);//写入一个字节//fileOutputStream.write('a');//写入字符串String str = "hello,world!";//getBytes() 可以把字符串转成字节数组//fileOutputStream.write(str.getBytes());//写入字符串,从指定索引写入指定长度的字节fileOutputStream.write(str.getBytes(),2,6);} catch (IOException e) {e.printStackTrace();} finally {try {fileOutputStream.close();} catch (IOException e) {e.printStackTrace();}}}}
4.5 编程练习:拷贝
按照前面学习的内容,完成图片/音乐的拷贝。
package com.hspedu.outputstream_;import org.junit.jupiter.api.Test;import java.io.*;/*** @author HarborGao* @version 1.0*/public class FileCopy {public static void main(String[] args) {}@Testpublic void copy() {String filePath = "e:\\546.jpg";String newFilePath = "d:\\tom.jpg";FileInputStream fileInputStream = null;FileOutputStream fileOutputStream = null;byte[] bc = new byte[1024];int readLen = 0;try {fileInputStream = new FileInputStream(filePath);fileOutputStream = new FileOutputStream(newFilePath);while ((readLen = fileInputStream.read(bc)) != -1) {fileOutputStream.write(bc,0,readLen);}System.out.println("拷贝成功~");} catch (IOException e) {e.printStackTrace();} finally {try {if (fileInputStream != null) {fileInputStream.close();}if (fileOutputStream != null) {fileOutputStream.close();}} catch (IOException e) {e.printStackTrace();}}}}
4.6 FileReader 介绍
FileReader:文件字符输入流 用于读取磁盘上的文件到内存,按字符读取
FileReader 相关方法:
- new FileReader(File/String)
- read:每次读取单个字符,返回该字符,如果到文件末尾返回 -1
- read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1
FileReader 相关API:
- new String(char[]):将 char[] 转换成 String
- new String(char[],off,len):将 char[] 的指定部分转换成 String
应用案例:使用 FileReader 从 story.txt 读取内容,并显示
package com.hspedu.reader_;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;/*** @author HarborGao* @version 1.0*/public class FileReader_ {public static void main(String[] args) {String filePath = "e:\\story.txt";FileReader fileReader = null;int Date = 0;char[] chars = new char[10];int readLen = 0;try {fileReader = new FileReader(filePath);//单个字符读取// while ((Date = fileReader.read()) != -1) {// System.out.print((char) Date);// }//多个字符读取while ((readLen = fileReader.read(chars)) != -1) {System.out.print(new String(chars,0,readLen));}} catch (IOException e) {e.printStackTrace();} finally {try {if (fileReader != null) {fileReader.close();}} catch (IOException e) {e.printStackTrace();}}}}
4.7 FileWriter 介绍
FileWriter:文件字符输出流 用于将程序(内存)中的数据写入到磁盘上的文件中,按字符写入
FileWriter 常用方法:
- new FileWriter(File/String):覆盖模式,相当于流的指针在首端
- new FileWriter(File/String, true):追加模式,相当于流的指针在尾端
- write(int):写入单个字符
- write(char[]):写入指定字符数组
- write(char[], off, len):写入指定数组的指定部分
- write(String):写入整个字符串
- write(string, off, len):写入字符串的指定部分
FileWriter 相关API:
String类: toCharArray:将String转换成char[]
注意:
FileWriter 使用后,必须要关闭(close)或者刷新(flush),否则写入不到指定的文件!
应用案例:使用 FileWriter 将”风雨过后,定见彩虹”写入到 note.txt 文件中,注意细节。
package com.hspedu.writer_;import java.io.FileWriter;import java.io.IOException;/*** @author HarborGao* @version 1.0*/public class FileWriter_ {public static void main(String[] args) {String filePath = "e:\\note.txt";FileWriter fileWriter = null;String content = "风雨过后,定见彩虹";try {//fileWriter = new FileWriter(filePath);fileWriter = new FileWriter(filePath,true);// write(int):写入单个字符fileWriter.write('H');// write(char[]):写入指定字符数组fileWriter.write(content.toCharArray());// write(char[], off, len):写入指定数组的指定部分fileWriter.write(content.toCharArray(),2,5);// write(String):写入整个字符串fileWriter.write(content);// write(string, off, len):写入字符串的指定部分fileWriter.write(content,2,5);} catch (IOException e) {e.printStackTrace();} finally {try {if (fileWriter != null) {//fileWriter.flush();//.close() 关闭文件流,等价于 flush + 关闭fileWriter.close();}} catch (IOException e) {e.printStackTrace();}}}}
五、节点流和处理流
5.1 基本介绍
- 节点流可以从一个特定的数据源读取数据,如 FileReader、FileWriter

- 处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如 BufferedReader、BufferWriter

5.2 节点流和处理流一览图

5.3 节点流和处理流的区别和联系
- 节点流是底层流/低级流,直接跟数据打交道。
- 处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。
- 处理流对节点流进行包装,使用了修饰器设计模式,不会直接与数据源打交道
模拟修饰器设计模式
package com.hspedu;/*** @author HarborGao* @version 1.0* 模拟Reader*/public abstract class Reader_ {public void readFile() {}public void readString() {}}
package com.hspedu;/*** @author HarborGao* @version 1.0* 模拟Reader的子类 FileReader 节点流*/public class FileReader_ extends Reader_{public void readFile() {System.out.println("对文件进行读取...");}}
package com.hspedu;/*** @author HarborGao* @version 1.0* 模拟Reader的子类 StringReader 节点流*/public class StringReader_ extends Reader_{public void readString() {System.out.println("读取字符串...");}}
package com.hspedu;/*** @author HarborGao* @version 1.0* 模拟 BufferedReader 处理流(包装流) 修饰器设计模式*/public class BufferedReader_ extends Reader_{private Reader_ reader_; //属性,Reader_类public BufferedReader_(Reader_ reader_) {this.reader_ = reader_;}public void readFile() { //读取一次reader_.readFile();}//让方法更加灵活: 多次读取文件,或者加缓冲 char[]...public void readFiles(int num) {for (int i = 0; i < num; i++) {reader_.readFile();}}//扩展: 批量处理字符串数据public void readStrings(int num) {for (int i = 0; i < num; i++) {reader_.readString();}}}
package com.hspedu;/*** @author HarborGao* @version 1.0*/public class Test_ {public static void main(String[] args) {BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_());bufferedReader_.readFiles(10);BufferedReader_ bufferedReader_1 = new BufferedReader_(new StringReader_());bufferedReader_1.readStrings(5);}}
5.4 处理流的功能主要体现
- 性能的提高:主要以增加缓冲的方式来提高输入输出的效率
- 操作的便捷:处理流 提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加方便灵活
5.5 处理流 - BufferedReader 和 BufferedWriter
- BufferedReader 和 BufferedWriter 数据字符流,是按照字符来读取和写入数据的
注意:处理字节流文件(图片、音频等二进制文件)可能会造成数据损失 - 关闭时,只需要关闭外层流(处理流)即可,内层的节点流或者处理流会随着外层的关闭而关闭
应用案例1:使用BufferredReader 读取文本文件,并显示在控制台
package com.hspedu.reader_;import java.io.BufferedReader;import java.io.FileNotFoundException;import java.io.FileReader;/*** @author HarborGao* @version 1.0* 演示 BufferedReader 使用*/public class BufferedReader_ {public static void main(String[] args) throws Exception {String filePath = "e:\\story.txt";//创建BufferedReaderBufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));//读取String line;//说明://1. readLine() 方法是按行读取,效率高//2. 当返回 null 时,表示文件读取完毕while ((line = bufferedReader.readLine()) != null) {System.out.println(line);}//关闭流,这里注意,只需要关闭 bufferedReader,因为底层会自动关闭节点流FileReaderbufferedReader.close();}}
应用案例2:使用 BufferedWriter 将”hello,世界!”,写入到文件中
package com.hspedu.reader_;import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;/*** @author HarborGao* @version 1.0* 演示 BufferedWriter 使用*/public class BufferedWriter_ {public static void main(String[] args) throws IOException {String filePath = "e:\\ok.txt";//创建 BufferedWriter 对象BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));bufferedWriter.write("hello,世界!");bufferedWriter.newLine();//插入一个和系统相关的换行bufferedWriter.write("hello2,世界!");bufferedWriter.newLine();bufferedWriter.write("hello3,世界!");bufferedWriter.newLine();//说明: 关闭外层流 bufferedReader 即可,因为底层会自动关闭节点流FileWriterbufferedWriter.close();}}
应用案例3:使用 BufferedReader 和 BufferedWriter 完成文本文件拷贝,注意文件编码
package com.hspedu.writer_;import java.io.*;/*** @author HarborGao* @version 1.0*/public class BufferedCopy_ {public static void main(String[] args) {String srcFilePath = "e:\\story.txt";String destFilePath = "e:\\demo\\storyCopy.txt";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();}}}}
5.6 处理流 - BufferedInputStream 和 BufferedOutputStream
- BufferedInputStream 是字节流,在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。
- BufferedInputStream 是字节流,实现缓冲的输出流,可以将多个字节写入底层输出流中,而不必对每次字节写入调用底层系统。


应用案例:编程完成图片/音乐 的拷贝(要求使用 Buffered…流)
package com.hspedu.outputstream_;import java.io.*;/*** @author HarborGao* @version 1.0* 演示 BufferedInputStream 和 BufferedOutputStream 使用* 可以实现 二进制文件的拷贝* 思考: 字节流可以操作二进制文件,可以操作文本文件吗? 可以。文本文件底层也是二进制文件,编码不同而已,读取时注意*/public class BufferedIOStreamCopy_ {public static void main(String[] args) {String srcFilePath = "e:\\546.jpg";String destFilePath = "e:\\123.jpg";BufferedInputStream bis = null;BufferedOutputStream bos = null;try {bis = new BufferedInputStream(new FileInputStream(srcFilePath));bos = new BufferedOutputStream(new FileOutputStream(destFilePath));//循环的读取文件并写入到新文件byte[] buff = new byte[1024];int readLen;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();}}}}
5.7 对象流 - ObjectInputStream 和 ObjectOutputStream
看一个需求:
- 将 int num = 100 这个 int 数据保存到文件中,注意不是 100 数字,而是 int 100,并且,能够从文件中直接恢复 int 100
- 将 Dog dog = new Dog(“小黄”, 3)这个dog对象 保存到文件中,并且能够从文件恢复
- 上面的要求,就是 能够将 基本数据类型 或者 对象 进行序列化 和 反序列化操作
序列化和反序列化:
- 序列化就是在保存数据时,保存数据的值和数据类型
- 反序列化就是在恢复数据时,恢复数据的值和数据类型
- 需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
- Serializable //这是一个标记接口,没有方法,一般情况下推荐使用
- Externalizable //需实现其方法
ObjectInputStream 和 ObjectOutputStream 基本介绍

功能:提供了对基本类型或对象类型的序列化和反序列化的方法
ObjectOutputStream: 提供序列化功能
ObjectInputStream: 提供反序列化功能

应用案例1:使用 ObjectOutputStream 序列化 基本数据类型和一个 Dog对象(name,age),并保存到
data.dat 文件中
package com.hspedu.outputstream_;import java.io.FileOutputStream;import java.io.ObjectOutputStream;/*** @author HarborGao* @version 1.0* 演示 ObjectOutputStream 使用,完成数据的序列化*/public class ObjectOutputStream_ {public static void main(String[] args) throws Exception{//序列化后,保存的文件格式,不是存文本,而是指定的数据保存格式 .datString filePath = "e:\\data.dat";ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));//序列化数据到 e:\data.datoos.writeInt(100); //自动装箱oos.writeBoolean(true);oos.writeChar('a');oos.writeDouble(9.5);oos.writeUTF("韩顺平教育");//保存一个 Dog对象Dog dog = new Dog("大黄", 5);oos.writeObject(dog);oos.close();System.out.println("数据保存完毕(序列化形式)");}}
package com.hspedu.outputstream_;import java.io.Serializable;/*** @author HarborGao* @version 1.0*///如果想让类是可序列化的,必须实现 Serializable 或 Externalizable 接口public class Dog implements Serializable {private String name;private int age;public Dog(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Dog{" +"name='" + name + '\'' +", age=" + age +'}';}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;}}
应用案例2:使用 ObjectInputStream 读取 data.dat 并反序列化恢复数据
package com.hspedu.inputstream_;import com.hspedu.outputstream_.Dog; //引入Dog类import java.io.FileInputStream;import java.io.ObjectInputStream;/*** @author HarborGao* @version 1.0*/public class ObjectInputStream_ {public static void main(String[] args) throws Exception {//指定反序列化的文件String filePath = "e:\\data.dat";ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));//读取//解读://1. 读取(反序列化)的顺序需要和保存数据(序列化)的顺序一致//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());Object dog = ois.readObject();System.out.println("运行类型=" + dog.getClass());System.out.println("dog信息=" + dog);//细节说明://1. 如果我们希望调用 Dog方法,需要向下转型//2. 并且需要将 Dog类的定义,拷贝到可以引用的位置Dog dog2 = (Dog)dog;System.out.println(dog2.getName());//关闭流,关闭外层即可ois.close();}}
5.8 对象处理流的注意事项和细节说明
- 读写顺序要一致
- 要求实现序列化或反序列化对象,需要实现 Serializable
- 序列化的类中建议添加 SerialVersionUID,为了提高版本的兼容性
- 序列化对象时,默认将里面所有的属性都进行序列化,但除了 static 或 transient 修饰的成员
- 序列化对象时,要求里面属性的类型也需要实现序列化接口
- 序列化具备可继承性,也就是如果某类已经实现了序列化,则它所有子类也已经默认实现了序列化
5.9 标准输入输出流
| 名称 | 编译类型 | 默认设备 | 运行类型 | |
|---|---|---|---|---|
| System.in | 标准输入 | InputStream | 键盘 | BufferedInputStream |
| System.out | 标准输出 | PrintStream | 显示器 | PrintStream |
5.10 转换流 - InputStreamReader 和 OutputStreamWriter
package com.hspedu.transformation_;import java.io.BufferedReader;import java.io.FileReader;import java.io.IOException;/*** @author HarborGao* @version 1.0*/public class CodeQuestion_ {public static void main(String[] args) throws IOException {//读取 e:\\a.txt 文件到程序//思路://1. 创建字符输入流 BufferedReader [处理流]//2. 使用 BufferedReader 对象读取 a.txt//3. 默认情况下,读取文件是按照 utf-8 编码String filePath = "e:\\a.txt"; //假设源文件是 gbk编码的,含有中文BufferedReader br = new BufferedReader(new FileReader(filePath));String s = br.readLine();System.out.println("读取的内容:" + s); //会发现出现乱码br.close();}}
InputStreamReader 和 OutputStreamWriter 介绍
- InputStreamReader:Reader 的子类,可以将 InputStream(字节流)包装成(转换) Reader(字符流)
- OutputStreamWriter:Writer的子类,实现将 OutputStream(字节流)包装成 Writer(字符流)
- 当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流
- 可以在使用时指定编码格式(比如 utf-8, gbk, gb2312, ISO8859-1 等)
应用案例1:编程将 字节流 FileInputStream 包装成(转换成)字符流 InputStreamReader 对文件进行读取
按照 utf-8/gbk 格式,进而再包装成 BufferedReader
package com.hspedu.transformation_;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;/*** @author HarborGao* @version 1.0* 演示使用 InputStreamReader 转换流解决中文乱码问题* 将字节流 FileInputStream 转换成 字符流 InputStreamReader,指定编码 utf-8 / gbk*/public class InputStreamReader_ {public static void main(String[] args) throws IOException {String filePath = "e:\\a.txt";//解读://1. 将FileInputStream 转成 InputStreamReader//2. 制定了编码 "gbk"InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath),"gbk");//3. 把 InputStreamReader 传入 BufferedReaderBufferedReader br = new BufferedReader(isr);//将 2 和 3 合并成一步BufferedReader br2 = new BufferedReader(new InputStreamReader(new FileInputStream(filePath),"gbk"));//4. 读取System.out.println( br.readLine());//5. 关闭外层br.close();}}
应用案例2:编程将 字节流 FileOutputStream 包装成(转换成)字符流 OutputStreamWriter 对文件进行写入
按照 utf-8/gbk 格式
package com.hspedu.transformation_;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStreamWriter;/*** @author HarborGao* @version 1.0* 演示 OutputStreamWriter 使用* 将 字节流FileOutputStream 转换成 字符流OutputStreamWriter* 指定处理的编码 gnk/utf-8/utf8*/public class OutputStreamWriter_ {public static void main(String[] args) throws IOException {String filePath = "E:\\b.txt";String charSet = "utf8";OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), charSet);osw.write("hi,世界");osw.close();System.out.println("保存成功");}}
六、打印流 - PrintStream 和 PrintWriter
6.1 PrintStream 字节打印输出流
package com.hspedu.printstream_;import java.io.IOException;import java.io.PrintStream;/*** @author HarborGao* @version 1.0* 演示 PrintStream 字节打印输出流 使用*/public class PrintStream_ {public static void main(String[] args) throws IOException {PrintStream out = System.out;//在默认情况下, PrintStream 打印的位置是标准输出 即显示器/*public void print(String s) {if (s == null) {s = "null";}write(s);}*/out.println("hello,java");//因为 print 底层使用的是 write(),所以我们也可以直接调用其完成打印输出out.write("java,你好".getBytes());out.close();//我们可以修改打印流输出的位置/设备System.setOut(new PrintStream("e:\\f1.txt"));System.out.println("hello,韩顺平教育~");}}
6.2 PrintWriter 字符打印输出流
package com.hspedu.printwriter_;import java.io.FileWriter;import java.io.IOException;import java.io.PrintWriter;/*** @author HarborGao* @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("e:\\f2.txt"));printWriter.print("hi,北京~");printWriter.close();}}
七、Properties 类
7.1 看一个需求
有如下一个配置文件 mysql.properties
ip=192.168.0.13
user=root
pwd=12345
请 编程读取 ip、user、pwd 的值
传统方法:
package com.hspedu.properties_;import java.io.BufferedReader;import java.io.FileReader;import java.io.IOException;/*** @author HarborGao* @version 1.0*/public class Properties01 {public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new FileReader("src\\mysql.properties"));String s;while ((s = br.readLine()) != null) {String[] split = s.split("=");System.out.println(split[0] + "的值是 " + split[1]);}br.close();}}
问题:
- 读取数据麻烦,需要自己定义读取方法
- 数据修改比较麻烦
7.2 基本介绍
Properties 类 是专门用于读写配置文件的集合类 ,其父类是Hashtable
配置文件的格式:
键=值
键=值注意:键值对不需要有空格,值不需要用引号包起来,默认类型是String
7.3 Properties 类的常见方法
| 方法 | 功能 |
|---|---|
| load | 加载配置文件的键值对到 Properties 对象 |
| list | 将数据显示到指定设备 |
| getProperty(key) | 根据键获取值 |
| setProperty(key, value) | 设置键值对到 Properties 对象 |
| store | 将 Properties 中的键值对储存到配置文件。在IDEA中,保存信息到配置文件,如果含有中文,会储存为 Unicode码 |
7.4 应用案例
- 使用 Properties 类完成对 mysql.properties 的读取
- 使用 Properties 类添加 key-value 到新文件 mysql2.properties 中
- 使用 Properties 类完成对 mysql.properties 的读取,并修改某个 key-value ```java package com.hspedu.properties_;
import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.Properties;
/**
- @author HarborGao
- @version 1.0
*/
public class Properties02 {
public static void main(String[] args) throws IOException {
} }//1. 使用 Properties 类完成对 mysql.properties 的读取Properties properties = new Properties();//加载指定配置文件properties.load(new FileReader("src\\mysql.properties"));//把key-value 显示到控制台properties.list(System.out);//根据 key 获取对应的 valueString ip = properties.getProperty("ip");System.out.println("ip是 " + ip);
java package com.hspedu.properties_;
import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties;
/**
- @author HarborGao
@version 1.0 */ public class Properties03 { public static void main(String[] args) throws IOException {
//使用 Properties 类添加 key-value 到新文件 mysql2.properties 中Properties properties = new Properties();//创建properties.setProperty("ip","192.168.100.100");properties.setProperty("user","汤姆");properties.setProperty("pwd","666666");properties.setProperty("charset","utf8");//修改 k-vproperties.setProperty("charset","gbk");//将 k-v 存储到文件中properties.store(new FileOutputStream("src\\mysql2.properties"),null);System.out.println("保存配置文件成功");
} } ```
八、本章作业
- 编程题
- 在判断e盘下是否有文件夹mytemp,如果没有就创建mytemp
- 在e:\mytemp目录下,创建文件hello.txt
- 如果hello.txt已经存在,提示该文件已经存在,就不要再重复创建了
- 并且在hello.txt文件中,写入hello,world~ ```java package com.hspedu.homework.homework01;
import java.io.File; import java.io.FileOutputStream; import java.io.IOException;
/**
- @author HarborGao
@version 1.0 */ public class Homework01 { public static void main(String[] args) throws IOException {
String filePath = "e:\\mytemp";File file = new File(filePath);if (file.exists()) {System.out.println("目录已经存在");} else {if (file.mkdir()) {System.out.println("目录创建成功");} else {System.out.println("目录创建失败");}}File file1 = new File(file, "hello.txt");if (file1.exists()) {System.out.println("该文件已存在");} else {if (file1.createNewFile()) {System.out.println("文件创建成功");} else {System.out.println("文件创建失败");}}FileOutputStream fos = new FileOutputStream(file1);fos.write("hello,world~".getBytes());fos.close();
} } ```
- 编程题
要求:使用BufferedReader读取一 个文本文件,为每行加上行号,再连同内容一并输出到屏幕上。
//如果把文件的编码改成了gbk,出现中文乱码,大家思考如何解决
//1.默认是按照utf-8处理开始没有乱码
//2.提示:使用我们的转换流,将FileInputStream -> InputStreamReader[可以指定编码] -> BufferedReader ..
package com.hspedu.homework_.homework02_;import java.io.*;/*** @author HarborGao* @version 1.0*/public class Homework02 {public static void main(String[] args) throws IOException {BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("e:\\code.txt"), "gbk"));//BufferedReader reader = new BufferedReader(new FileReader("e:\\code.txt"));int i = 0;String s;while ((s = reader.readLine()) != null) {System.out.println(++i + " " + s);}reader.close();}}
- 编程题
- 要编写一个dog.properties
name=tom
age=5
color=red
- 编写Dog类(name,age,color)创建一个dog对象,读取dog.properties 用相应的内容完成属性初始化,并输出
- 将创建的Dog对象,序列化到文件dog.dat文件 ```java package com.hspedu.homework.homework03;
import java.io.*; import java.util.Properties;
/**
- @author HarborGao
@version 1.0 */ public class Homework03 { public static void main(String[] args) throws IOException {
//编写一个dog.propertiesString filePath = "src\\dog.properties";Properties properties = new Properties();properties.setProperty("name","tom");properties.setProperty("age","5");properties.setProperty("color","red");properties.store(new FileOutputStream(filePath),"Class Dog");//编写Dog类(name,age,color)创建一个dog对象,读取dog.properties 用相应的内容完成属性初始化,并输出Properties properties1 = new Properties();properties1.load(new FileInputStream(filePath));String age = properties1.getProperty("age");Dog dog = new Dog(properties1.getProperty("name"),Integer.parseInt(age),properties1.getProperty("color"));System.out.println(dog);//将创建的Dog对象,序列化到文件dog.dat文件ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("e:\\dog.dat"));objectOutputStream.writeObject(dog);objectOutputStream.close();
} }
```javapackage com.hspedu.homework_.homework03_;import java.io.Serializable;/*** @author HarborGao* @version 1.0*/public 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;}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 getColor() {return color;} public void setColor(String color) {this.color = color;}@Overridepublic String toString() {return "Dog{" +"name='" + name + '\'' +", age=" + age +", color='" + color + '\'' +'}';}}
学习参考(致谢):
- B站 @程序员鱼皮 Java学习一条龙
- B站 @韩顺平 零基础30天学会Java
