1、文件/目录 File
文件就是保存数据的地方
比如:word文档,txt文件,excel文件…
文件内容可以是图片、视频、声音…
1)文件流
文件在程序中是以流的形式来操作的

- 流:数据在数据源(文件)和程序(内存)之间经历的路径
- 输入流:数据从数据源(文件)到程序(内存)的路径
- 输出流:数据从程序(内存)到数据源(文件)的路径
2)创建文件File
步骤:
1、定义File对象(多种方式)
- 只相当于在内存中创建了File对象
2、调用File对象的createNewFile()
- 真正把内存中的File对象写入文件
// File实现两个接口:序列化、比较
public class File
implements Serializable, Comparable<File>

(1)路径名
File(String pathname)
public void create01(){
String filePath = "d:\\a.txt";
File file = new File(filePath);
try {
file.createNewFile();
System.out.println("文件创建成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
(2)父目录文件 + 子路径名
File(File parent, String child)
public void create02(){
File parent = new File("d:");
String child = "b.txt";
File file = new File(parent, child);
try {
file.createNewFile();
System.out.println("文件创建成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
(3)父目录名 + 子路径名
File(String parent, String child)
public void create03(){
String parent = "d:";
String child = "c.txt";
File file = new File(parent, child);
try {
file.createNewFile();
System.out.println("文件创建成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
(4)URI
File(URI uri)
- file,uri,path相互转化
file (File)
uri (URI)
path (String)
| 转化 | 方式 |
|---|---|
| uri 转 file | new File(uri) |
| uri 转 path | uri.getPath() |
| file 转 uri | file.toURI() |
| file 转 path | file.getPath() |
| path 转 uri | new URI(path) |
| path 转 file | new File(path) |
3)获取文件信息

4)目录操作


2、IO流分类及体系图
1)概念
- I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理数据传输。如读/写文件,网络通讯
- Java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行
- java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据

2)分类
- 按数据单位分:
- 字节流 (二进制文件;如声音、视频)
- 字符流 (文本文件;1Byte = 8 bit)
- 按数据流向分:
- 输入流
- 输出流
- 按流的角色分:
- 节点流
- 处理流/包装流
| (抽象基类) | 字节流 | 字符流 |
|---|---|---|
| 输入流 | InputStream | Reader |
| 输出流 | OutputStream | Writer |
上面4个类都是抽象类(abstract),Java的IO流有40多个类,都是由这4个基类派生出来的
这些子类名都是以父类名作为后缀的




3)体系图


4)流与文件的关系
网购商品时,商品相当于文件,商品从卖家到用户手中的过程是物流,相当于流


3、文件流
1)文件字节流
(1)FileInputStream


实例
- 源文件a.txt
hello,world!
abc
测试
- read():返回读取的字节ASC码(int)
public void readFile01(){
String filePath = "d:\\a.txt";
// 读取到的字节的ASC码
int readData = 0;
FileInputStream fi = null;
try {
fi = new FileInputStream(filePath);
while((readData = fi.read()) > -1){
// 把ASC码转为char输出
System.out.print((char)readData);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭流
fi.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

- read(byte[] b):返回实际读到的字节数量(int)
public void readFile02(){
String filePath = "d:\\a.txt";
// 字节数组:一次读取5个字节
byte[] buf = new byte[5];
// 一次实际读到的字节数
int readLen = 0;
//FileInputStream fi = null;
InputStream fi = null;
try {
fi = new FileInputStream(filePath);
while((readLen = fi.read(buf)) > -1){
// 把一次读到的数据(从0到readLen)构造成字符串,输出
System.out.print(new String(buf,0,readLen));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭流
fi.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

中文不适合字节流
(2)FileOutPutStream
对于FileOutputStream,如果文件不存在,会创建文件(前提是目录已经存在)


public void writeFile01(){
String filePath = "d:\\b.txt";
OutputStream fo = null;
try {
// 新写入的数据覆盖原来数据
//fo = new FileOutputStream(filePath);
// 新写入的数据不覆盖原来数据,在结尾添加
fo = new FileOutputStream(filePath,true);
// 写入单个字符;用单引号
//fo.write('a');
// 写入多个字符;用String,getBytes()转化
String str = "Hello world!";
fo.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭流
fo.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
aHello world!
(3)文件拷贝
思路分析
- 创建文件输入流,将文件读入到程序
- 创建文件的输出流,将读取到的文件数据写入到指定位置
【边读边写】读取部分数据就写入到指定文件

public void copy(){
// 源文件
//String filePath1 = ".\\file\\IMG_20150503_094805_2.jpg";
String filePath1 = ".\\file\\l.wav";
// 拷贝文件
//String filePath2 = ".\\file\\_2.jpg";
String filePath2 = ".\\file\\_3.wav";
// 输入流
InputStream ips = null;
// 输出流
OutputStream ops = null;
try {
ips = new FileInputStream(filePath1);
ops = new FileOutputStream(filePath2);
// 读取的字节数
int readLen = 0;
// 字节数组
byte[] buf = new byte[1024];
// 循环读取
while((readLen = ips.read(buf)) > -1){
// 写入输出流
ops.write(buf,0,readLen);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try{
if(ips != null){
ips.close();
}
if(ops != null){
ops.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
在流未关闭之前,都是以追加的方式输出

2)文件字符流
(1)FileReader



getEncoding() 是InputStreamReader的方法,可以InputStreamReader、FileReader的对象调用,不用能Reader的对象调用
- read() 读取单个字符,返回字符编码值(int)
public void readFile01(){
// 源文件:项目根目录下的file文件夹中
String filePath = ".\\file\\a.txt";
FileReader reader = null;
// 读取到的字符编码值(int)
int readData = 0;
try {
reader = new FileReader(filePath);
// 循环读取
while ((readData = reader.read()) > -1){
System.out.print((char)readData);
}
// 输出流字符编码
System.out.println("\n字符编码:"+reader.getEncoding());
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
// 关闭流
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- read(char[] buf) 读取多个字符到缓冲数组(char数组),返回读取到的字符数
public void readFile02(){
// 源文件:项目根目录下的file文件夹中
String filePath = ".\\file\\a.txt";
FileReader reader = null;
// 一次实际读取到的字符数量
int readLen = 0;
// 缓冲数组(字符数组)
char[] buf = new char[1024];
try {
// 建立流
reader = new FileReader(filePath);
// 循环读取
while ((readLen = reader.read(buf)) > -1){
// 通过String构造器输出
System.out.print(new String(buf,0,readLen));
}
// 得到字符编码
System.out.println("\n字符编码:"+reader.getEncoding());
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
// 关闭流
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

(2)FileWriter



五种写入方法
写入后要调用flush(),才能真正写入文件
==关闭流close()==时,会自动flush()
- write(int c) 写入单个字符
- write(char[] buf) 写入多个字符(字符数组)
- write(char[] buf,int off,int len) 写入多个字符(字符数组),从off开始,共len个
- write(String str) 写入字符串
- write(String str,int off,int len) 写字符串,从off开始,共len个
public void writeFile01(){
// 目标文件:项目根目录下的file文件夹中
String filePath = ".\\file\\b.txt";
Writer writer = null;
try {
// 输出流
writer = new FileWriter(filePath);
// 写入单个字符
//writer.write('A');
//writer.flush();
// 写入多个字符
//char[] buf = {'测','试','B'};
//writer.write(buf);
// 写入多个字符中的部分
//char[] buf = {'测','试','B'};
//writer.write(buf,0,2);
// 写入字符串
//String str = "abc测试";
//writer.write(str);
// 写入字符串中的部分
String str = "abc测试";
writer.write(str,0,4);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
// 关闭流;自动刷新flush
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4、节点流
节点流可以从一个特定的数据源(节点)读写数据
文件流就是一种节点流
如:FileReader、FileWriter等

5、处理流
1)概念
处理流(也叫包装流)是“附着”于已存在的流(节点流或其它处理流)之上,为原来的流提供附加的功能
如:FilterInputStream和FilterOutputStream及其子类、BufferedReader、BufferedWriter、FilterReader、FilterWriter等

2)装饰者模式
处理流属于设计模式中的装饰者模式(也叫包装器模式)


- BufferedReader内部有一个Reader,它就是附着于Reader之上(对Reader进行装饰/包装),提供附加功能,之后可以转化为Reader的任意子类,这就是装饰器模式
- BufferedWriter类似
3)缓冲流
(1)BufferedReader




public void read(){
// 目标文件路径:相对路径
String filePath = ".\\file\\c.txt";
BufferedReader bufferedReader = null;
try {
// 创建缓冲流
bufferedReader = new BufferedReader(new FileReader(filePath));
// 接收读取的行数据
String strLine;
// 如果读取的行不为null,就循环读取
while((strLine = bufferedReader.readLine()) != null){
// 输出
System.out.println(strLine);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流;只需关闭外层流,底层节点流会自动关闭
try {
if(bufferedReader != null){
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
关闭流时,只需要关闭外层流即可,底层流会自动关闭

(2)BufferedWriter



public void write(){
// 目标文件
String filePath = ".\\file\\d.txt";
BufferedWriter writer = null;
try {
// 缓冲输出流
writer = new BufferedWriter(new FileWriter(filePath));
// 写字符串
writer.write("测试abc1");
// 换行
writer.newLine();
writer.write("测试abc2");
writer.newLine();
writer.write("测试abc3");
writer.newLine();
writer.write("测试abc4");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try {
if(writer != null){
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
(3)Buffered字符拷贝
BufferedReader和BufferedWriter是字符缓冲流;只适合字符数据(如文本文件)
对于声音、视频等二进制文件应选用字节缓冲流,BufferedInputStream和BufferedOutputStream
用字符流,选用ISO8859-1编码,也可以处理声音、视频等二进制文件,需结合转换流(InputStreamReader、OutputStreamWriter)
public void copy01(){
// 目标文件
String filePath1 = ".\\file\\a.txt";
// 拷贝文件
String filePath2 = ".\\file\\a_.txt";
// 输入缓冲流
BufferedReader reader = null;
// 输出缓冲流
BufferedWriter writer = null;
try {
// 创建缓冲流
reader = new BufferedReader(new FileReader(filePath1));
writer = new BufferedWriter(new FileWriter(filePath2));
// 接收读取到的行数据
String strLine;
// 如果读取到的行数据不为null,就循环读取
while ((strLine = reader.readLine()) != null){
// 写【边读边写】
writer.write(strLine);
// 换行
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(reader != null){
reader.close();
}
if(writer != null){
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
(4)Buffered字节拷贝
既可以拷贝字节数据(二进制数据),也可以拷贝字符数据(文件数据)
public void copy02() {
// 目标文件
String filePath1 = ".\\file\\1.wav";
// 拷贝文件
String filePath2 = ".\\file\\1_.wav";
// 输入缓冲流
// FilterInputStream reader = null;
BufferedInputStream reader = null;
// 输出缓冲流
// FilterOutputStream writer = null;
BufferedOutputStream writer = null;
try {
// 创建缓冲流
reader = new BufferedInputStream(new FileInputStream(filePath1));
writer = new BufferedOutputStream(new FileOutputStream(filePath2));
// 接收读取到的数据
byte[] buf = new byte[8192];
// 单次读取到的字节数量
int readLen = 0;
// 如果读取到的字节数量不为-1,就循环读取
while ((readLen = reader.read(buf)) > -1) {
// 写【边读边写】
writer.write(buf, 0, readLen);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try {
if (reader != null) {
reader.close();
}
if (writer != null) {
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4)对象流
(1)概述
-
对象流包括 ObjectInputStream 和 ObjectOutputStream,专门用来处理对象的
-
作用:可以将 基本数据类型 或者 对象 进行序列化 和 反序列化
如:int num = 100,可以把值100和类型int保存到文件,并且恢复
Dog dog = new Dog(“小黄”,3),可以把对象dog以及属性值:“小黄”和3保存到文件,并且恢复
-
序列化 与 反序列化
- 就是在保存 或者 恢复时,即包含数据的值,也包含数据类型(或者是对象及对象属性值)
- 对象要支持序列化,必须实现接口(下面两个接口之一)
- Serializable:这是一个标记接口,仅仅是序列化的标记,没有方法和属性
- Externalizable:这是自定义接口,有两个方法需要实现。(一般不用)
-
装饰者模式
- ObjectInputStream 和 ObjectOutputStream都有一个可以接受其它流(一般为节点流)的构造器,在这个流的基础上进行处理,所以也是一种装饰者模式


-
重要使用场景
在原型设计模式中,进行深拷贝时,把对象先序列化,再反序列化,就实现了深拷贝
(2)ObjectOutputStream
序列化
保存的文件类型为 .dat
public class ObjectOutputStreamDemo {
@Test
public void write() {
String filePath = ".\\file\\e.dat";
ObjectOutputStream oos = null;
try {
// 创建对象处理流
oos = new ObjectOutputStream(new FileOutputStream(filePath));
// int
oos.writeInt(50);
// 单字节
oos.writeByte('A');
// 单字符
oos.writeChar(520);
// 布尔值
oos.writeBoolean(false);
// Double
oos.writeDouble(3.8);
// 字符串
oos.writeUTF("测试");
// 对象
oos.writeObject(new Dog("小黄",3));
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try {
if (oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class Dog implements Serializable {
String name;
int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

(3)ObjectInputStream
反序列化
反序列化顺序要和序列化时的顺序一致
@Test
public void read() {
String filePath = ".\\file\\e.dat";
ObjectInputStream ois = null;
try {
// 创建对象处理流
ois = new ObjectInputStream(new FileInputStream(filePath));
// int
//oos.writeInt(50);
System.out.println(ois.readInt());
// 单字节
//oos.writeByte('A');
System.out.println((char) ois.readByte());
// 单字符
//oos.writeChar(520);
System.out.println((int)ois.readChar());
// 布尔值
//oos.writeBoolean(false);
System.out.println(ois.readBoolean());
// Double
//oos.writeDouble(3.8);
System.out.println(ois.readDouble());
// 字符串
//oos.writeUTF("测试");
System.out.println(ois.readUTF());
// 对象
//oos.writeObject(new Dog("小黄",3));
try {
Object dog = ois.readObject();
System.out.println("dog类型:" + dog.getClass());
System.out.println(dog);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try {
if (ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

(4)对象处理流使用细节
- 读写顺序要一致
- 要求实现序列化/反序列化的对象,要实现Serializable接口
- 序列化的类中建议添加SerialVersionUID,提高版本的兼容性
- static 或 transient 修饰的属性不序列化
- 需要序列化的属性类型,也需要实现Serializable接口
- 序列化具备可继承性;如果某类实现了序列化,子类也可以序列化
5)标准输入输出流
(1)System.in
- 编译类型:InputStream
- 运行类型:BufferedInputStream
- 对应设备:键盘
(2)System.out
- 编译类型:PrintStream
- 运行类型:PrintStream
- 对应设备:显示器



(3)Scanner 扫描类
public static void main(String[] args) {
System.out.println("in类型:"+System.in.getClass());
System.out.println("out类型:"+System.out.getClass());
// 创建扫描器:扫描键盘输入(System.in)
Scanner scanner = new Scanner(System.in);
System.out.println("请输入...");
// next() 查找并返回来自此扫描器的下一个完整标记
// 在一行中输入“abc lmn xyz”时,只返回“abc”
//String next = scanner.next();
// nextLine() 查找并返回当前行
String next = scanner.nextLine();
System.out.println(next);
// 关闭扫描器
scanner.close();
}
in类型:class java.io.BufferedInputStream
out类型:class java.io.PrintStream
请输入...
abc lmn xyz
// next()
abc
// nextLine()
abc lmn xyz
关闭扫描器时,会自动关闭System.in

6)转换流
转换流包含:InputStreamReader 和 OutputStreamWriter
(1)乱码问题
public static void main(String[] args) throws IOException {
String filePath = ".\\file\\a.txt";
// 默认情况下,读取文件是按照 utf-8 编码
BufferedReader br = new BufferedReader(new FileReader(filePath));
String line = br.readLine();
System.out.println(line);
br.close();
}


ANSI码是国标码,对应系统就是GBK码,国标码是一个统称,每个国家都有自己的国标码,国标码是根据系统来确定的
- 出现乱码是因为文件的编码方式与读取时的编码方式不一致
- 转换流可以把字节流转换成字符流,字节流是可以指定编码方式
(2)InputStreamReader
InputStreamReader 是 Reader 的子类,有可以接受 InputStream 字节流 以及 编码格式的构造器,属于装饰者设计模式;可以将字节流(InputStream)包装成字符流(Reader)

public static void main(String[] args) throws IOException {
String filePath = ".\\file\\a.txt";
// 文件编码格式GBK,指定读取时所用编码格式也为GBK,就不会出现乱码了
// 包装缓冲流(转换流(节点流))
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath),"GBK"));
// ======= 代码分解 ======
// 字节 节点流
// InputStream inputStream = new FileInputStream(filePath);
// 转换流:把字节流转为字符流;用GBK编码
// Reader reader = new InputStreamReader(inputStream, "GBK");
// 包装缓冲处理流:提高读取效率
// BufferedReader br = new BufferedReader(reader);
// =======================
String line = br.readLine();
System.out.println(line);
br.close();
}

(3)OutputStreamWriter
OutputStreamWriter 是 Writer 的子类,有可以接受 OutputStream 字节流 以及 编码格式的构造器,属于装饰者设计模式;可以将字节流(OutputStream)包装成字符流(Writer)

以指定编码(GBK)保存文件
public static void main(String[] args) throws IOException {
// 文件保存路径
String filePath = ".\\file\\e.txt";
// 字符编码:GBK/UTF-8/UTF8/utf-8/utf8
String charSet = "GBK";
// 输出字节流
OutputStream os = new FileOutputStream(filePath);
// 转换处理流
Writer osw = new OutputStreamWriter(os, charSet);
// 缓冲处理流
BufferedWriter bw = new BufferedWriter(osw);
bw.write("ABxmy!测试数据");
bw.close();
}

7)打印输出流
(1)PrintStream(字节)
PrintStream 是 FilterOutputStream 的子类,有可以接受 OutputStream 字节流 的构造器,属于装饰者设计模式;也有可以接受文件(File/String)及字符编码 的构造器,可以把输出保存到文件

- 标准输出:显示器
public static void main(String[] args) throws IOException {
// 标准输出:显示器
t1();
// 指定输出:文件
//t2();
}
public static void t1() throws IOException {
// System.out底层类型就是PrintStream
PrintStream out = System.out;
// 默认情况下,PrintStream是标准输出,输出位置是:显示器
out.println("Hello!你好!");
// print内部调用的是write(),可以直接用write()输出
// 由于PrintStream是字节流,所以参数是字节或字节数组
out.write("Abc,北京".getBytes());
// 关闭输出流
out.close();
}

- 输出至文件
public static void t2() throws IOException {
// 改变输出位置:输出到文件
String filePath = ".\\file\\f.txt";
// 字符编码:GBK/UTF-8/UTF8/utf-8/utf8
String charSet = "utf8";
// 改变输出位置:保存到文件
// 通过System.setOut()方法
System.setOut(new PrintStream(filePath,charSet));
// System.out底层类型就是PrintStream
PrintStream out = System.out;
// PrintStream out = new PrintStream(filePath,charSet);
// 输出至文件
out.println("Hello!你好!");
// print内部调用的是write(),可以直接用write()输出
out.write("Abc,北京".getBytes());
out.println("测试!Xyz");
// 关闭输出流
out.close();
}

(2)PrintWriter(字符)
PrintWriter 是 Writer 的子类,有可以接受 OutputStream 字节流 的构造器,属于装饰者设计模式;也有可以接受文件(File/String)及字符编码 的构造器,可以把输出保存到文件

-
标准输出:显示器
关闭流(自动调用flush())后,才会真正输出
public class PrintWriterDemo {
public static void main(String[] args) throws IOException {
// 标准输出:显示器
t1();
// 指定输出:文件
//t2();
}
public static void t1() throws IOException {
// System.out底层类型就是PrintStream:字节流
PrintWriter out = new PrintWriter(System.out);
// 默认情况下,PrintWriter是标准输出,输出位置是:显示器
out.println("Hello!你好!");
// print内部调用的是write(),可以直接用write()输出
// 由于PrintWriter是字符流,所以参数直接用字符串就可以
out.write("Abc,北京");
// 关闭输出流
out.close();
}
}


- 输出至文件
public static void t2() throws IOException {
// 改变输出位置:输出到文件
String filePath = ".\\file\\f1.txt";
// 字符编码:GBK/UTF-8/UTF8/utf-8/utf8
String charSet = "utf8";
// 改变输出位置:保存到文件
PrintWriter out = new PrintWriter(filePath,charSet);
// 输出至文件
out.println("Hello!你好!");
// print内部调用的是write(),可以直接用write()输出
out.write("Abc,北京");
out.println("测试!Xyz");
// 关闭输出流
out.close();
}

(3)刷新问题
只有在使用缓冲时才会有刷新的问题
-
PrintStream是字节流,在不使用缓冲流(BufferedOutputStream)写入文件时,不论关不关流close(),都会写入文件;在使用缓冲流(BufferedOutputStream)写入文件时,只有自动刷新autoFlush是true时,才会刷新;为false时(默认),写入文件后,要调用flush()或close(),数据才会真正写入文件
简要:PrintStream 使用缓冲时,在刷新问题上和 PrintWriter 一致
刷新autoFlush 使用缓冲BufferedOutputStream 不用缓冲BufferedOutputStream true 可以写入文件 可以写入文件 false 只有flush()或close()后才写入 可以写入文件

- PrintWriter是字符流,天生使用了缓冲,所以有刷新的问题;在autoFlush是true时,才会刷新;为false时(默认),写入文件后,要调用flush()或close(),数据才会真正写入文件
6、操作Properties
Properties配置文件

1)传统方法
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
read01();
}
/**
* 传统方法读取
* @throws IOException
*/
public static void read01() throws IOException {
// 文件路径:两种方式都可以
String filePath = ".\\src\\main\\resources\\db.properties";
//String filePath = "src\\main\\resources\\db.properties";
// 缓冲字符读取流
BufferedReader br = new BufferedReader(new FileReader(filePath));
String line = "";
// 循环读取
while((line = br.readLine()) != null){
// 对读取的行数据进行拆分
String[] split = line.split("=");
System.out.println(split[0] + "值为:"+split[1]);
}
// 关闭流
br.close();
}
}
2)类Properties介绍
(1)概述
-
Properties是专门用于处理配置文件的集合类
-
文件的格式:键-值对;不需要空格,也不需要引号
如:
ip=192.168.100.100 user=abc ps=123456

(2)常用方法


3)用Properties类操作配置文件
(1)读取
/**
* 用Properties读取
*/
public static void read02() throws IOException {
// 创建Properties类
Properties properties = new Properties();
// 文件路径:两种方式都可以
String filePath = ".\\src\\main\\resources\\db.properties";
//String filePath = "src\\main\\resources\\db.properties";
// 字节流
//properties.load(new FileInputStream(filePath));
// 字符流
properties.load(new FileReader(filePath));
String ip = properties.getProperty("ip");
String user = properties.getProperty("user");
String ps = properties.getProperty("ps");
System.out.println("ip = " + ip);
System.out.println("user = " + user);
System.out.println("ps = " + ps);
}
ip = 192.168.100.100
user = tuwer
ps = 123456
(2)存储
/**
* 用Properties存储
*/
public static void write01() throws IOException {
// 创建Properties类
Properties properties = new Properties();
// 配置键值对
// 如果文件中某个键存在,setProterty()就是修改,不存在时是新建
properties.setProperty("charSet","uft-8");
properties.setProperty("user","汤姆");
properties.setProperty("ps","123456");
// 文件路径
String filePath = ".\\src\\main\\resources\\db1.properties";
// 存储:中文以Unicode码存储
properties.store(new FileOutputStream(filePath),"注释");
}

7、练习作业
1)文件创建及写入数据
判断文件夹(file/mytemp)是否存在,如果不存在就创建
判断文件夹下hello.txt文件是否存在,如果不存在就创建,如果存在就不创建,并给出相应提示
向文件hello.txt中写入数据
public class HomeWork {
public static void main(String[] args) {
work01();
}
public static void work01() {
// 文件夹路径
String dirStr = ".\\file\\a\\mytemp";
// 文件夹对象
File dir = new File(dirStr);
// 如果文件夹不存在,就创建
if (!dir.exists()) {
// 创建文件夹:可以创建多级目录
dir.mkdirs();
}
// 文件路径
String fileStr = "hello.txt";
// 文件对象
File file = new File(dir, fileStr);
// 如果文件不存在就创建,然后提示
if (!file.exists()) {
try {
// 创建文件
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("文件" + fileStr + "不存在,已创建成功!");
}
// 如果文件存在,给出提示
else {
System.out.println("文件" + fileStr + "已经存在!");
}
// 写入数据
FileWriter fw = null;
try {
// 文件字符输出流
fw = new FileWriter(file);
fw.write("Hello world!测试!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
if(fw != null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("数据写入成功!");
}
}

2)读取文件并添加行号输出
用BufferedReader
/**
* 使用BufferedReader读取文件,并加上行号,输出到屏幕
*/
public static void work02() {
// 目标文件路径
String filePath = ".\\file\\a\\mytemp\\hello.txt";
// 创建文件
File file = new File(filePath);
// 判断文件是否存在
if (!file.exists()) {
System.out.println("文件不存在!");
return;
}
BufferedReader br = null;
try {
// 创建读取缓冲流
br = new BufferedReader(new FileReader(file));
String lineStr = "";
int lineNumber = 0;
// 循环读取并添加行号输出
while ((lineStr = br.readLine()) != null) {
System.out.println(++lineNumber + "、 " + lineStr);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

3)获取文件数据创建对象
- 用properties的值作为属性值创建对象;然后对象序列化输出
/**
* 用properties的值作为属性值创建对象
*/
public static void work03() {
// =====读取配置文件数据=====
// 配置文件路径
String filePath = ".\\src\\main\\resources\\dog.properties";
File file = new File(filePath);
if (!file.exists()) {
System.out.println("文件不存在!");
return;
}
String name = "";
int age = -1;
String color = "";
// 创建Properties类
Properties properties = new Properties();
try {
// 加载配置文件
properties.load(new BufferedReader(new FileReader(file)));
name = properties.getProperty("name");
age = Integer.parseInt(properties.getProperty("age"));
color = properties.getProperty("color");
} catch (IOException e) {
e.printStackTrace();
}
// =====创建对象=====
// 检查是否读取到数据
if (name == null || name.length() < 1 || age < 0 || color == null || color.length() < 1) {
System.out.println("属性值读取失败!");
return;
}
Dog dog = new Dog(name, age, color);
System.out.println(dog);
// =====序列化对象到文件=====
String objectFilePath = ".\\src\\main\\resources\\dog.dat";
ObjectOutputStream oos = null;
try {
// 创建对象处理流
oos = new ObjectOutputStream(new FileOutputStream(objectFilePath));
// 写入对象
oos.writeObject(dog);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("对象" + dog + "已输出到文件!");
}
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 + '\'' +
'}';
}
}

- 反序列化创建对象
/**
* 反序列化
* 从文件中读取对象
*/
public static void readObject(){
// 对象文件路径
String filePath = ".\\src\\main\\resources\\dog.dat";
File file = new File(filePath);
if(!file.exists()){
System.out.println("文件不存在!");
return;
}
ObjectInputStream ois = null;
try {
// 创建对象处理流
ois = new ObjectInputStream(new FileInputStream(file));
try {
// 读对象
Object dog = ois.readObject();
// 对象类型
System.out.println(dog.getClass());
// 输出Object
System.out.println(dog);
// 强转
Dog d = (Dog)dog;
// 输出Dog
System.out.println(d);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(ois!=null){
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

本文详细介绍了Java中的IO流,包括文件的创建与读写,IO流的分类(字节流、字符流、输入流、输出流),节点流与处理流的概念,以及装饰者模式在IO流中的应用。同时讲解了缓冲流的使用,如BufferedReader和BufferedWriter,以及对象流(ObjectInputStream和ObjectOutputStream)的序列化与反序列化。此外,还涉及了标准输入输出流、转换流、Properties配置文件的操作,以及在实际编程中的应用示例。
1796

被折叠的 条评论
为什么被折叠?



