Java IO流 学习笔记
1、IO概述
1.1 什么是IO?
Java中I/O操作主要是指使用java.io
包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做写出数据。
1.2 IO的分类
根据数据的流向分为:输入流和输出流。
- 输入流:把数据从其他设备上读取到内存中的流
- 输出流:把数据从内存中写出到其他设备上的流
根据数据的类型分为:字节流和字符流
- 字节流:以字节为单位,读写数据的流
- 字符流:以字符为单位,读写数据的流
1.3 IO的流向说明
1.4 顶级父类
输入流 | 输出流 | |
---|---|---|
字节流 | 字节输入流 InputStream |
字节输出流 OutputStream |
字符流 | 字符输入流 Reader |
字符输出流 Writer |
2、字节流
2.1 一切皆为字节
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。
2.2 字节输出流[OutputStream]
java.io.OutputStream
抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
public void close()
:关闭此输出流并释放与此流相关联的任何系统资源。public void flush()
:刷新此输出流并强制任何缓冲的输出字节被写出。public void write(byte[] b)
:将 b.length字节从指定的字节数组写入此输出流。public void write(byte[] b, int off, int len)
:从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。public abstract void write(int b)
:将指定的字节输出流。
close方法,当完成流的操作的时候,必须调用此方法,释放系统资源
2.3 FileOutputStream类
OutputStream
有很多子类,如ByteArrayOutputStream
,FileOutputStream
,FilterOutputStream
, ObjectOutputStream
,PipedOutputStream
我们从最简单的一个子类开始。
写入数据的原理(内存--->硬盘)
java程序-->JVM(java虚拟机)-->OS(操作系统)-->OS调用写数据的方法-->把数据写入到文件中
字节输出流的使用步骤
- 创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
- 调用FileOutputStream对象中的方法write,把数据写入到文件中
- 释放资源(流使用会占用一定的内存,使用完毕后要把内存清空,提高程序的效率)
构造方法
public FileOutputStream(String name)
:创建文件输出流以指定的名称写入文件。public FileOutputStream(File file)
:创建文件输出流以写入由指定的 File对象表示的文件。
写出字节数据
文件存储的原理和记事本打开的原理
- 写出字节:
write(int b)
方法,每次可以写出一个字节数据,代码使用演示
public static void main(String[] args) throws IOException {
//1.创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
FileOutputStream fos = new FileOutputStream("G:\\testIO\\t1.txt");
//2.调用FileOutputStream对象中的方法write,把数据写入到文件中
fos.write(97);//文件中写的是 a
//3.释放资源(流使用会占用一定的内存,使用完毕后要把内存清空,提高程序的效率)
fos.close();
}
-
写出字节数组:
write(byte[] b)
,每次可以写出数组中的数据。 -
写出指定长度字节数组:
write(byte[] b, int off, int len)
,每次写出从off索引开始,len个字节。
/*
* `public void write(byte[] b)`:
* 将 b.length字节从指定的字节数组写入此输出流。
* `public void write(byte[] b, int off, int len)` :
* 从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
*/
public class TestIO02 {
public static void main(String[] args) throws IOException {
//1.创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
FileOutputStream fos = new FileOutputStream("G:\\testIO\\t2.txt");
fos.write(49);
fos.write(48);
fos.write(48);
//2.调用FileOutputStream对象中的方法write,把数据写入到文件中
/*
* `public void write(byte[] b)`:
* 将 b.length字节从指定的字节数组写入此输出流。
* 一次写多个字节
* 如果写的第一个字节数正数(0-127) ,那么显示的时候会查询ASCII表
* 如果写的第一个字节是负数,那第一个字节会和第二个字节,两个字节组成一个中文显示,
* 查询系统默认码表(GBK);
*/
byte[] bytes = {65,66,67,68,69};
// byte[] bytes = {-65,-66,-67,68,69};
/*
* `public void write(byte[] b, int off, int len)` :
* 从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
* int off:数组的开始索引
* int len:写几个字符
*/
fos.write(bytes,1,2);//BC
/*
写入字符串的方法:可以使用String类中的方法吧字符串,转换为字节数组
byte[] getBytes() 把字符串转换为字节数组
*/
byte[] bytes1 = "你好".getBytes();
System.out.println(Arrays.toString(bytes1));//[-28, -67, -96, -27, -91, -67] UFT-8三个字节一个中文
fos.write(bytes1);
// fos.write(bytes);
//3.释放资源(流使用会占用一定的内存,使用完毕后要把内存清空,提高程序的效率)
fos.close();
}
数据追加续写
public FileOutputStream(File file, boolean append)
: 创建文件输出流以写入由指定的 File对象表示的文件。public FileOutputStream(String name, boolean append)
: 创建文件输出流以指定的名称写入文件。
这两个构造方法,参数中都需要传入一个boolean类型的值,true
表示追加数据,false
表示清空原有数据。
写换行:写换行符号
- windows:\r\n
- linux:\n
- mac:\r
/*
- `public FileOutputStream(File file, boolean append)`: 创建文件输出流以写入由指定的 File对象表示的文件。
- `public FileOutputStream(String name, boolean append)`: 创建文件输出流以指定的名称写入文件。
参数:
String name,File file:写入数据的目的地
boolean append:追加写开关
true:创建对象不会覆盖源文件,继续在文件末尾追加写数据
false:创建一个新文件
写换行:写换行符号
windows:\r\n
linux:\n
mac:\r
*/
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("a.txt", true);
for (int i =1;i<=10;i++){
fos.write("你好".getBytes());
fos.write("\r\n".getBytes());
}
fos.close();
}
2.4 字节输入流[InputStream]
java.io.InputStream
抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。
public void close()
:关闭此输入流并释放与此流相关联的任何系统资源。public abstract int read()
: 从输入流读取数据的下一个字节。public int read(byte[] b)
: 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
小贴士:
close方法,当完成流的操作时,必须调用此方法,释放系统资源。
2.5 FileInputStream类
java.io.FileInputStream
类是文件输入流,从文件中读取字节。
构造方法:
FileInputStream(String name)
: 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。FileInputStream(File file)
:通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出FileNotFoundException
。
读取数据的原理(硬盘--->内存)
java程序-->JVM(java虚拟机)-->OS(操作系统)-->OS调用读取数据的方法-->读取文件
字节输入流的使用步骤
- 创建一个FileInputStream对象,构造方法中绑定要读取的数据源
- 调用FileInputStream对象中的方法read,读取文件
- 释放资源(流使用会占用一定的内存,使用完毕后要把内存清空,提高程序的效率)
读取字节数据
- 读取字节:
read
方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
。
/*
java.io.InputStream:字节输入流
此抽象类是表示字节输入流的所有类的超类
定义了所有子类共性的方法
int read() 从该输入流读取一个字节的数据。
int read(byte[] b) 从输入流读取一些字节数,并将它们存储到缓冲区 b 。
void close() 关闭此输入流并释放与流相关联的任何系统资源。
java.io.FileInputStream extends InputStream
FileInputStream 文件字节输入流
作用:把硬盘文件中的数据,读取到内存中使用
构造方法:
FileInputStream(String name)
FileInputStream(File file)
参数:读取文件的数据源
String name :文件的路径
File file:文件
构造方法的作用:
1.会创建一个FileInputStream对象
2.会把FileInputStream对象指定构造方法中要读取的文件
**读取数据的原理(硬盘--->内存)**
java程序-->JVM(java虚拟机)-->OS(操作系统)-->OS调用读取数据的方法-->读取文件
**字节输入流的使用步骤**
1. 创建一个FileInputStream对象,构造方法中绑定要读取的数据源
2. 调用FileInputStream对象中的方法read,读取文件
3. 释放资源(流使用会占用一定的内存,使用完毕后要把内存清空,提高程序的效率)
*/
public class TestIO04 {
public static void main(String[] args) throws IOException {
//1. 创建一个FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("G:\\testIO\\t3.txt");
//2. 调用FileInputStream对象中的方法read,读取文件
//int read()读取文件中的一个字节并返回,读取到文件的末尾并返回-1
/*int len = fis.read();
System.out.println(len);
len = fis.read();
System.out.println(len);
len = fis.read();
System.out.println(len);
len = fis.read();
System.out.println(len);
len = fis.read();
System.out.println(len);*/
/*
发现以上读取文件是一个重复的过程,所以可以使用循环优化
不知道文件中有多少个字节,使用while循环
while循环结束条件,读取到-1时结束
布尔表达式:(len=fis.read())!=-1
1.fis.read():读取一个字节
2.len=fis.read():把读取到的字节赋值给变量len
3.(len=fis.read())!=-1:判断变量len是否不等于-1
*/
int len=0;//记录读取的字节
while((len=fis.read())!=-1){
System.out.print((char) len);
}
//3. 释放资源(流使用会占用一定的内存,使用完毕后要把内存清空,提高程序的效率)
fis.close();
}
原理:
- 使用字节数组读取:
read(byte[] b)
,每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回-1
/*
字节输入流一次读取多个字节的方法
int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓存区数组b中。
明确两件事情:
1.方法的参数byte[]的作用?
答:起到缓冲作用,存储每次读取到的多个字节
数组长度一般定义为1024或1024的整数倍
2.方法的返回值是什么?
答:每次读取到的有效字节个数
String类的构造方法
String(byte[] bytes):把字节数组转换为字符串
String(byte[] bytes,int offset,int length) 把字节数组的一部分转换为字符串
offset:数组的开始索引,length:转换的字符个数
*/
public class TestIO05 {
public static void main(String[] args) throws IOException {
//1. 创建一个FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("G:\\testIO\\t3.txt");
//使用FileInputStream对象中的方法read读取文件
//int read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
/* byte[] bytes = new byte[2];
int len = fis.read(bytes);
System.out.println(len);//2
//System.out.println(Arrays.toString(bytes));//[65, 66]
System.out.println(new String(bytes));//AB
len = fis.read(bytes);
System.out.println(len);//2
System.out.println(new String(bytes));//CD
len = fis.read(bytes);
System.out.println(len);//1
System.out.println(new String(bytes));//ED
len = fis.read(bytes);
System.out.println(len);//-1
System.out.println(new String(bytes));//ED*/
/*
发现以上读取时是一个重复的过程,可以使用循环优化
不知道文件中有多少字节,所以使用while循环
while循环结束的条件,读取到-1结束
*/
byte[] buffer = new byte[1024];//存储读取到的多个字节
int len=0;//记录每次读取的有效字节个数
while ((len=fis.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}
//释放资源
fis.close();
}
原理
2.6 图片复制
原理
实现代码:
/*
复制文件:一读一写
明确:
数据源:G:\testIO\p1.jpeg
数据的目的地:当前文件夹
文件复制的步骤:
1.创建一个字节输入流的对象,构造方法中绑定要读取的数据源
2.创建一个字节输出流的对象,构造方法中绑定要写如的目的地
3.使用字节输入流对象中的read方法读取文佳
4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
5.释放资源
*/
public class CopyFile {
public static void main(String[] args) throws Exception {
//1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("G:\\testIO\\p1.jpeg");
//2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
FileOutputStream fos = new FileOutputStream("p1.jpeg");
//一次读取一个字节写入一个字节的方式
//3.使用字节输入流对象中的方法read读取文件
/*int len=0;
while ((len=fis.read())!=-1){
//4.使用字节输出流中的write,把读取到的字节写入到目的地文件中
fos.write(len);
}*/
//优化
//使用数组缓冲读取多个字节,写入多个字节
byte[] buffer = new byte[1024];
int len=0;
//3.使用字节输入流对象中的方法read读取文件
while ((len=fis.read(buffer))!=-1){
//4.使用字节输出流中的write,把读取到的字节写入到目的地文件中
fos.write(buffer,0,len);
}
//5.释放资源(先关闭写的,后关闭读的,如果写完了,肯定读完了)
fos.close();
fis.close();
//
}
3、字符流
当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
/*
使用字节流读取中文文件
1个中文
GBK:占用两个字节
UTF-8:占用三个字节
*/
public class TestIO06 {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("G:\\testIO\\t4.txt");
int len=0;
//不乱码
// byte[] buffer = new byte[3];
// while((len=fis.read(buffer))!=-1){
// System.out.println(new String(buffer,0,len));
// }
//乱码
while ((len=fis.read())!=-1){
System.out.println((char)len);
}
fis.close();
}
}
3.1 字符输入流【Reader】
java.io.Reader
:字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类.
共性的成员方法:
public int read()
:读一个字符public int read(char cbuf[])
:将字符读入数组public abstract void close()
:关闭流并释放与之相关联的任何系统资源。
3.2 FileReader类
java.io.FileReader
类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
小贴士:
-
字符编码:字节与字符的对应规则。Windows系统的中文编码默认是
GBK编码表。
idea中UTF-8
-
字节缓冲区:一个字节数组,用来临时存储字节数据。
构造方法
FileReader(File file)
:创建一个新的FileReader,给定要读取的File对象FileReader(String fileName)
:创建一个新的FileReader,给定要读取的文件到的名称。
读取字符数据
字符输入流的使用步骤
-
创建FileReader对象,构造方法中绑定要读取的数据源
-
使用FileReader对象中的方法read读取文件
-
释放资源
-
读取字符:
read
方法,每次可以读取一个字符的数据,提升为int类型,读取到文件末尾,返回-1
,循环读取 -
使用字符数组读取:
read(char[] cbuf)
,每次读取b的长度个字符到数组中,返回读取到的有效字符个数,读取到末尾时,返回-1
/*
java.io.Reader:字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类
共性的成员方法:
int read() :读一个字符
int read(char[] cbuf) :将字符读入数组。
abstract void close() :关闭流并释放与之相关联的任何系统资源。
java.io.FileReader extends java.io.InputStreamReader extends java.io.Reader
FileReader : 文件字符输入流
作用:把硬盘文件中的数据以字符的方式读取到内存中。
构造方法:
FileReader(File file)
FileReader(String fileName)
参数:读取文件的数据源
String fileName:文件的路径
File File:一个文件
FileReader构造方法的作用:
1.创建一个FileReader对象
2.会把FileReader对象指向我们要读取的文件。
字符输入流的使用步骤
1.创建FileReader对象,构造方法中绑定要读取的数据源
2.使用FileReader对象中的方法read读取文件
3.释放资源
*/
public static void main(String[] args) throws Exception {
//1.创建FileReader对象,构造方法中绑定要读取的数据源
FileReader fr = new FileReader("G:\\testIO\\t4.txt");
//2.使用FileReader对象中的方法read读取文件
//int read():读取单个字符并返回
/*int len=0;
while ((len=fr.read())!=-1){
System.out.print((char)len);
}*/
//int read(char[] cbuf) :将字符读入数组。
char[] cs = new char[1024];//存储读取到的多个字符
int len =0;//记录的是每次读取的有效字符个数
while ((len=fr.read(cs))!=-1){
/*
String 类的构造方法
String(char[] value):把字符数组转换成字符串
String(char[] value, int offset, int count) :把字符数组的一部分转换成字符串
offset:数组的开始索引;count:转换的个数
*/
System.out.println(new String(cs,0,len));
}
// 3.释放资源
fr.close();
}
3.3 字节输出流【Writer】
java.io.Writer
抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。
void write(int c)
写入单个字符。void write(char[] cbuf)
写入字符数组。abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分,off数组的开始索引,len写的字符个数。void write(String str)
写入字符串。void write(String str, int off, int len)
写入字符串的某一部分,off字符串的开始索引,len写的字符个数。void flush()
刷新该流的缓冲。void close()
关闭此流,但要先刷新它。
3.4 FileWriter类
java.io.FileWriter
类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
构造方法
FileWriter(File file)
: 创建一个新的 FileWriter,给定要读取的File对象。FileWriter(String fileName)
: 创建一个新的 FileWriter,给定要读取的文件的名称。
作用
- 会创建一个FileWriter对象
- 会根据构造方法中传递的文件/文件名的路径,创建文件
- 会把FileWriter对象指向创建好的文件
1.写出字符:write(int b)
方法,每次可以写出一个字符数据。
/*
java.io.Writer :字符输出流,是所有字符输出流的最顶层的父类,是一个抽象类
共性的成员方法:
- `void write(int c)` 写入单个字符。
- `void write(char[] cbuf) `写入字符数组。
- `abstract void write(char[] cbuf, int off, int len) `写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
- `void write(String str) `写入字符串。
- `void write(String str, int off, int len)` 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
- `void flush() `刷新该流的缓冲。
- `void close()` 关闭此流,但要先刷新它。
java.io.FileWriter extends OutputStreamWriter extends Writer
FileWriter:文件字符输出流
作用:把内存中的字符数据写入到文件中
构造方法
FileWriter(File file) 给一个File对象构造一个FileWriter对象。
FileWriter(String fileName) 构造一个给定文件名的FileWriter对象。
参数:写入数据的目的地
String fileName:文件路径
File file:是一个文件
构造方法的作用:
1.会创建一个FileWriter对象
2.会根据构造方法中传递的文件/文件名的路径,创建文件
3.会把FileWriter对象指向创建好的文件
字符输出流的使用步骤:
1.创建FileWriter对象。构造方法中绑定要写入数据的目的地
2.使用FileWriter中的方法write,把数据写入到内存缓冲区(字符转换为字节的过程)
3.使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中
4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
*/
public static void main(String[] args) throws IOException {
//1.创建FileWriter对象。构造方法中绑定要写入数据的目的地
FileWriter fw = new FileWriter("G:\\testIO\\t5.txt");
//2.使用FileWriter中的方法write,把数据写入到内存缓冲区(字符转换为字节的过程)
// - `void write(int c)` 写入单个字符
fw.write(97);
//3.使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中
fw.flush();
// 4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
fw.close();
}
2.关闭和刷新
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush
方法了。
flush
:刷新缓冲区,流对象可以继续使用。close
:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了
public static void main(String[] args) throws IOException {
//1.创建FileWriter对象。构造方法中绑定要写入数据的目的地
FileWriter fw = new FileWriter("G:\\testIO\\t5.txt");
//2.使用FileWriter中的方法write,把数据写入到内存缓冲区(字符转换为字节的过程)
// - `void write(int c)` 写入单个字符
fw.write(97);
//3.使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中
fw.flush();
fw.write(98);//刷新后,流可以继续使用
// 4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
fw.close();
fw.write(98);//close方法使用后已经关闭了,已经从内存中消失了,流就不能再使用了
}
3.写出字符数组:write(char[] cbuf)
和 write(char[] cbuf, int off, int len)
,每次可以写出字符数组中的数据,用法类似FileOutputStream。
4.写出字符串:write(String str)
和 write(String str, int off, int len)
,每次可以写出字符串中的数据,更为方便
/*
- `void write(char[] cbuf) `写入字符数组。
- `abstract void write(char[] cbuf, int off, int len) `写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
- `void write(String str) `写入字符串。
- `void write(String str, int off, int len)` 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
*/
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("G:\\testIO\\t6.txt");
char[] cs= {'a','b','c','d','e'};
//`void write(char[] cbuf) `写入字符数组。
fw.write(cs);
//`abstract void write(char[] cbuf, int off, int len) `写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
fw.write(cs,1,3);
//- `void write(String str) `写入字符串。
fw.write("你好世界");
//- `void write(String str, int off, int len)` 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
fw.write("你好世界",2,2);
fw.close();
}
5.续写和换行:操作类似于FileOutputStream
续写和换行
续写,追加写:使用两个参数的构造方法
FileWriter(File file, boolean append) :
FileWriter(String fileName, boolean append)
参数:String fileName、File file:写入数据的目的地
boolean append:续写数据的开关 true:可以续写;false:不可续写
换行:换行符号
windows:\r\n
linux:\n
mac:\r
/*
续写和换行
续写,追加写:使用两个参数的构造方法
FileWriter(File file, boolean append) :
FileWriter(String fileName, boolean append)
参数:String fileName、File file:写入数据的目的地
boolean append:续写数据的开关 true:可以续写;false:不可续写
换行:换行符号
windows:\r\n
linux:\n
mac:\r
*/
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("t1.txt",true);
for (int i = 0; i < 10; i++) {
fw.write("helloworld"+i);
fw.write("\r\n");
}
fw.close();
}
4、IO异常处理
JDK7之前处理
在jdk1.7之前使用try catch finally处理流中的异常
/*
在jdk1.7之前使用try catch finally处理流中的异常
格式:
try{
可能会产生异常的代码
}catch(异常类的变量 变量名){
异常的处理逻辑
}finally{
一定执行的代码
资源释放
}
*/
public static void main(String[] args) {
//提高变量fw的作用域,让finally可以使用
//变量在定义的时候,可以没有值,但是使用的时候必须有值
FileWriter fw=null;
try {
//可能会产生异常的代码
fw = new FileWriter("t1.txt",true);
for (int i = 0; i < 10; i++) {
fw.write("helloworld"+i);
fw.write("\r\n");
}
}catch (IOException e){
//异常的处理逻辑
System.out.println(e);
}finally {
//一定执行的代码
//如果对象创建失败了,fw的默认值就是null,null是不能调用方法的,会抛出NullPointerException
// ,需要增加一个判断,不是null在吧资源释放。
if (fw!=null){
try {
//f.close方法声明抛出来IOException异常对象,
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
JDK7新特性
在try后面可以增加一个(),在括号中可以定义流对象
那么这个流对象的作用域就在try中有效
try中的代码执行完毕后,会自动把流对象释放,不用写finally
格式:
try(定义流对象;定义流对象){
可能会产生异常的代码
}catch(异常类的变量 变量名){
异常的处理逻辑
}
/*
JDK7新特性
在try后面可以增加一个(),在括号中可以定义流对象
那么这个流对象的作用域就在try中有效
try中的代码执行完毕后,会自动把流对象释放,不用写finally
格式:
try(定义流对象;定义流对象){
可能会产生异常的代码
}catch(异常类的变量 变量名){
异常的处理逻辑
}
*/
public class TestIO13 {
public static void main(String[] args) {
try(
FileInputStream fis = new FileInputStream("GS:\\testIO\\p1.jpeg");
FileOutputStream fos = new FileOutputStream("p1.jpeg");
) {
byte[] buffer = new byte[1024];
int len=0;
while ((len=fis.read(buffer))!=-1){
fos.write(buffer,0,len);
}
}catch (IOException e){
System.out.println(e);
}
}
}
JDK9新特性
try的前面可以定义流对象
在try后面的()中可以直接引入流对象的名称(变量名)
在try代码执行完毕之后,流对象也可以释放掉,不用写finally
格式:
A a = new A();
B b = new B();
try(a;b){
}catch{
}
/*
JDK9新特性
try的前面可以定义流对象
在try后面的()中可以直接引入流对象的名称(变量名)
在try代码执行完毕之后,流对象也可以释放掉,不用写finally
格式:
A a = new A();
B b = new B();
try(a;b){
}catch{
}
*/
public class TestIO14 {
public static void main(String[] args) throws FileNotFoundException {
FileInputStream fis = new FileInputStream("G:\\testIO\\p1.jpeg");
FileOutputStream fos = new FileOutputStream("p1.jpeg");
try(fis;fos) {
byte[] buffer = new byte[1024];
int len=0;
while ((len=fis.read(buffer))!=-1){
fos.write(buffer,0,len);
}
}catch (IOException e){
System.out.println(e);
}
}
}
5、属性集
5.1概述
java.util.Properties
继承于 Hashtable
,来表示一个持久的属性集。它使用键值结构存储数据,每个键及其对应值都是一个字符串。该类也被许多Java类使用,比如获取系统属性时,System.getProperties
方法就是返回一个Properties
对象。
Properties
类表示一组持久的属性。 Properties
可以保存到流中或从流中加载。 属性列表中的每个键及其对应的值都是一个字符串。
5.2 Properties类
构造方法
public Properties()
:创建一个空的属性列表。
基本的存储方法
- Object setProperty(String key, String value) 调用 Hashtable方法 put 。
- String getProperty(String key) 通过key找到value值,此方法相当于Map集合中的get(key)方法
- Set
stringPropertyNames() 返回此属性列表中的键集,其中该键及其对应值是字符串,此方法相当于Map集合中的keySet方法
/*
java.util.Properties结合 extends Hashtable<k,v> implements Map<k,v>
Properties类表示一组持久的属性。 Properties可以保存到流中或从流中加载。
Properties集合是一个唯一和IO流相结合的集合
可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
可以使用Properties集合中的方法load,吧硬盘中保存的文件(键值对),读取到集合中使用
属性列表中的每个键及其对应的值都是一个字符串。
Properties集合是一个双列集合,key和value默认都是字符串
*/
public class Test01 {
public static void main(String[] args) {
show01();
}
/*
使用Properties集合存储数据,遍历取出Properties集合中的数据
Properties集合是一个双列集合,key和value默认都是字符串
Properties集合有一些操作字符串的特有方法:
Object setProperty(String key, String value) 调用 Hashtable方法 put 。
String getProperty(String key) 通过key找到value值,此方法相当于Map集合中的get(key)方法
Set<String> stringPropertyNames() 返回此属性列表中的键集,其中该键及其对应值是字符串,此方法相当于Map集合中的keySet方法
*/
private static void show01() {
//创建Properties集合对象
Properties prop = new Properties();
//使用setProperty往集合中添加数据
prop.setProperty("数学","100");
prop.setProperty("语文","100");
prop.setProperty("英语","100");
//使用stringPropertyNames吧Properties集合中的键取出,存储到一个set集合中
Set<String> set = prop.stringPropertyNames();
//遍历set集合,取出 Properties集合的每一个键
for (String key : set) {
//s使用getProperty通过key获取value
String value = prop.getProperty(key);
System.out.println(key+"="+value);
}
}
}
store方法
可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储。
void store(OutputStream out, String comments)
void store(Writer writer, String comments)
参数:
OutputStream out:字节输出流,不能写中文
Writer writer:字符输出流,可以写中文
String comments:注释,用来解释说明保存的文件 是做什么用的
不能使用中文,会产生乱码。默认是Unicode编码
一般使用空字符串
使用步骤
1.创建Properties集合对象,添加数据 2.创建字节输出流/字符输出流,构造方法中绑定要输出的目的地 3.使用Properties集合中的方法store,吧集合中的临时数据,持久化写入到硬盘中存储 4.释放资源
/*
可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
void store(OutputStream out, String comments)
void store(Writer writer, String comments)
参数:
OutputStream out:字节输出流,不能写中文
Writer writer:字符输出流,可以写中文
String comments:注释,用来解释说明保存的文件 是做什么用的
不能使用中文,会产生乱码。默认是Unicode编码
一般使用空字符串
使用步骤:
1.创建Properties集合对象,添加数据
2.创建字节输出流/字符输出流,构造方法中绑定要输出的目的地
3.使用Properties集合中的方法store,吧集合中的临时数据,持久化写入到硬盘中存储
4.释放资源
*/
private static void show02() throws IOException {
//1.创建Properties集合对象,添加数据
Properties prop = new Properties();
//使用setProperty往集合中添加数据
prop.setProperty("数学","100");
prop.setProperty("语文","100");
prop.setProperty("英语","100");
// 2.创建字节输出流/字符输出流,构造方法中绑定要输出的目的地
FileWriter fw = new FileWriter("prop.txt");
//3.使用Properties集合中的方法store,吧集合中的临时数据,持久化写入到硬盘中存储
prop.store(fw,"save data");
// 4.释放资源
fw.close();
//prop.store(new FileOutputStream("prop.txt"),"");//会乱码
}
load方法
可以使用Properties集合中的方法load,吧硬盘中保存的文件(键值对),读取到集合中使用。
void load(InputStream inStream)
void load(Reader reader)
参数
InputStream inStream:字节输入流,不能读取含有中文的键值对
Reader reader:字符输入流,能读取含有中文的键值对
使用步骤:
1.创建Properties集合对象
2.使用Properties集合对象中的方法load读取保存键值对的文件
3.遍历Properties集合
注意
1.存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)
2.存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取
3.存储键值对的文件中,键与值默认都是字符串,不用再加引号
/*
可以使用Properties集合中的方法load,吧硬盘中保存的文件(键值对),读取到集合中使用
void load(InputStream inStream)
void load(Reader reader)
参数:
InputStream inStream:字节输入流,不能读取含有中文的键值对
Reader reader:字符输入流,能读取含有中文的键值对
使用步骤:
1.创建Properties集合对象
2.使用Properties集合对象中的方法load读取保存键值对的文件
3.遍历Properties集合
注意:
1.存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)
2.存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取
3.存储键值对的文件中,键与值默认都是字符串,不用再加引号
*/
private static void show03() throws Exception {
//1.创建Properties集合对象
Properties prop = new Properties();
//2.使用Properties集合对象中的方法load读取保存键值对的文件
prop.load(new FileReader("prop.txt"));
//乱码
//prop.load(new FileInputStream("prop.txt"));
//3.遍历Properties集合
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
String value = prop.getProperty(key);
System.out.println(key+"="+value);
}
}
学习完基本的一些流,我们要见识一些更强大的流。比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化流等等。这些功能更为强大的流,都是在基本的流对象基础之上创建而来的,就像穿上铠甲的武士一样,相当于是对基本流对象的一种增强。
6、缓冲流
6.1 概述
缓冲流,也叫高效流,是对4个基本的FileXxx
流的增强,所以也是4个流,按照数据类型分类:
- 字节缓冲流:
BufferedInputStream
,BufferedOutputStream
- 字符缓冲流:
BufferedReader
,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
6.2 字节缓冲流
构造方法
public BufferedInputStream(InputStream in)
:创建一个 新的缓冲输入流。public BufferedOutputStream(OutputStream out)
: 创建一个新的缓冲输出流。
字节缓冲输出流
构造方法
BufferedOutputStream(OutputStream out)
:创建一个新的缓冲输出流,以将数据写入指定的底层输出流。BufferedOutputStream(OutputStream out, int size)
:创建一个新的缓冲输出流,以便以指定的缓冲区大小将数据写入指定的底层输出流。
参数:
OutputStream out:字节输出流
我们可以传递FileOutStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream的写入效率
int size:指定缓冲流内部缓冲区的大小,不指定默认
使用步骤
1.创建一个FileOutStream,构造方法中绑定要输出的目的地
2.创建 BufferedOutputStream对象,构造方法中传递FileOutStream对象,提高FileOutStream对象效率
3.使用BufferedOutputStream对象中的方法write,把数据写入到内部的缓冲区中
4.使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
5.释放资源(会先调用flush方法刷新数据,第四步可以省略)
/*
java.io.BufferedOutputStream extends OutputStream
BufferedOutputStream:字节缓冲输出流
继承自父类的共性成员方法:
* `public void close()` :关闭此输出流并释放与此流相关联的任何系统资源。
* `public void flush() ` :刷新此输出流并强制任何缓冲的输出字节被写出。
* `public void write(byte[] b)`:将 b.length字节从指定的字节数组写入此输出流。
* `public void write(byte[] b, int off, int len)` :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
* `public abstract void write(int b)` :将指定的字节输出流。
构造方法:
BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out, int size) 创建一个新的缓冲输出流,以便以指定的缓冲区大小将数据写入指定的底层输出流。
参数:
OutputStream out:字节输出流
我们可以传递FileOutStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream的写入效率
int size:指定缓冲流内部缓冲区的大小,不指定默认
使用步骤:
1.创建一个FileOutStream,构造方法中绑定要输出的目的地
2.创建 BufferedOutputStream对象,构造方法中传递FileOutStream对象,提高FileOutStream对象效率
3.使用BufferedOutputStream对象中的方法write,把数据写入到内部的缓冲区中
4.使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
5.释放资源(会先调用flush方法刷新数据,第四步可以省略)
*/
public class Demo01 {
public static void main(String[] args) throws Exception {
// 1.创建一个FileOutStream,构造方法中绑定要输出的目的地
FileOutputStream fos = new FileOutputStream("a.txt");
//2.创建 BufferedOutputStream对象,构造方法中传递FileOutStream对象,提高FileOutStream对象效率
BufferedOutputStream bos = new BufferedOutputStream(fos);
//3.使用BufferedOutputStream对象中的方法write,把数据写入到内部的缓冲区中
bos.write("数据写入到内部缓冲区中".getBytes());
//4.使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
bos.flush();
//5.释放资源(会先调用flush方法刷新数据,第四步可以省略)
bos.close();
}
}
字节缓冲输入流
构造方法
BufferedInputStream(InputStream in)
:创建一个 BufferedInputStream并保存其参数,输入流 in ,供以后使用。BufferedInputStream(InputStream in, int size)
:创建 BufferedInputStream具有指定缓冲区大小,并保存其参数,输入流 in ,供以后使用。
参数:
InputStream in:字节输入流
我们可以传递FileInputStream,缓冲流会给FileInputStream增加一个缓冲区,提高FileInputStream的读取效率
int size:指定缓冲流内部缓冲区的大小,不指定默认
使用步骤
1.创建FileInputStream对象,构造方法中绑定要读取的数据源
2.创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
3.使用BufferedInputStream对象中的方法read,读取数据
4.释放资源
/*
java.io.BufferedInputStream extends InputStream
BufferedInputStream:字节缓冲输入流
继承自父类的成员方法:
int read() 从该输入流读取一个字节的数据。
int read(byte[] b) 从输入流读取一些字节数,并将它们存储到缓冲区 b 。
void close() 关闭此输入流并释放与流相关联的任何系统资源。
构造方法:
BufferedInputStream(InputStream in):创建一个 BufferedInputStream并保存其参数,输入流 in ,供以后使用。
BufferedInputStream(InputStream in, int size) :创建 BufferedInputStream具有指定缓冲区大小,并保存其参数,输入流 in ,供以后使用。
参数:
InputStream in:字节输入流
我们可以传递FileInputStream,缓冲流会给FileInputStream增加一个缓冲区,提高FileInputStream的读取效率
int size:指定缓冲流内部缓冲区的大小,不指定默认
使用步骤:
1.创建FileInputStream对象,构造方法中绑定要读取的数据源
2.创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
3.使用BufferedInputStream对象中的方法read,读取数据
4.释放资源
*/
public class Demo02 {
public static void main(String[] args) throws Exception {
//1.创建FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("a.txt");
//2.创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
BufferedInputStream bis = new BufferedInputStream(fis);
//3.使用BufferedInputStream对象中的方法read,读取数据
//int read()从输入流中读取数据的下一个字节
/*int len=0;//记录每次读到的字节
while((len=bis.read())!=-1){
System.out.println(len);
}*/
//int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
byte[] buffer = new byte[1024];
int len=0;
while((len=bis.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}
//4.释放资源
bis.close();
}
}
6.3 缓冲流的效率测试
文件复制
不使用缓冲流技术
文件的大小:54,007字节
一次读写一个字节:894毫秒
使用数组缓冲读取多个字节,写入多个字节:4毫秒
/*
复制文件:一读一写
明确:
数据源:G:\testIO\p1.jpeg
数据的目的地:当前文件夹
文件复制的步骤:
1.创建一个字节输入流的对象,构造方法中绑定要读取的数据源
2.创建一个字节输出流的对象,构造方法中绑定要写如的目的地
3.使用字节输入流对象中的read方法读取文佳
4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
5.释放资源
文件的大小:54,007字节
一次读写一个字节:894毫秒
使用数组缓冲读取多个字节,写入多个字节:4毫秒
*/
public class CopyFile {
public static void main(String[] args) throws Exception {
long s = System.currentTimeMillis();
//1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("G:\\testIO\\p1.jpeg");
//2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
FileOutputStream fos = new FileOutputStream("p1.jpeg");
//一次读取一个字节写入一个字节的方式
//3.使用字节输入流对象中的方法read读取文件
int len=0;
while ((len=fis.read())!=-1){
//4.使用字节输出流中的write,把读取到的字节写入到目的地文件中
fos.write(len);
}
//优化
//使用数组缓冲读取多个字节,写入多个字节
/*byte[] buffer = new byte[1024];
int len=0;
//3.使用字节输入流对象中的方法read读取文件
while ((len=fis.read(buffer))!=-1){
//4.使用字节输出流中的write,把读取到的字节写入到目的地文件中
fos.write(buffer,0,len);
}*/
//5.释放资源(先关闭写的,后关闭读的,如果写完了,肯定读完了)
fos.close();
fis.close();
long e = System.currentTimeMillis();
System.out.println("复制文件共耗时"+(e-s)+"毫秒");
}
}
使用缓冲流技术
文件的大小:54,007字节
一次读写一个字节:4毫秒
使用数组缓冲读取多个字节,写入多个字节:1毫秒
/*
文件复制的步骤
1.创建字节缓冲输入流对象,构造方法中传递字节输入流
2.创建字节缓冲输出流对象,构造方法中传递字节输出流
3.使用字节缓冲输入流对象中的方法read,读取文件
4.使用字节缓冲输出流中的方法write,把读取的数据写入到内部缓冲区中
5.释放资源(会先把缓冲区数据,刷新到文件中)
文件的大小:54,007字节
一次读写一个字节:4毫秒
使用数组缓冲读取多个字节,写入多个字节:1毫秒
*/
public class BufferedCopyFile {
public static void main(String[] args) throws Exception {
long s = System.currentTimeMillis();
//1.创建字节缓冲输入流对象,构造方法中传递字节输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("G:\\testIO\\p1.jpeg"));
//2.创建字节缓冲输出流对象,构造方法中传递字节输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("p3.jpeg"));
//3.使用字节缓冲输入流对象中的方法read,读取文件
//一次读取一个字节写入一个字节的方式
/*int len = 0;
while ((len=bis.read())!=0){
bos.write(len);
}*/
//使用数组缓冲读取多个字节,写入多个字节
byte[] buffer = new byte[1024];
int len=0;
while ((len=bis.read(buffer))!=-1){
bos.write(buffer,0,len);
}
bos.close();
bis.close();
long e = System.currentTimeMillis();
System.out.println("复制文件共耗时"+(e-s)+"毫秒");
}
}
6.3 字符缓冲流
字节缓冲输出流
构造方法
BufferedWriter(Writer out)
:创建使用默认大小的输出缓冲区的缓冲字符输出流。BufferedWriter(Writer out, int sz)
:创建一个新的缓冲字符输出流,使用给定大小的输出缓冲区。
参数
Writer out:字符输出流
我们可以传递FileWriter,缓冲流会给FileWriter增加一个缓冲区,提高FileWriter的写入效率
int sz:指定缓冲区的大小,不写默认大小
特有方法
void newLine()
:写一行行分隔符。会根据不同的操作系统,获取不同的行分隔符
换行:换行符号:
windows:\r\n
linux:/n
mac:/r
使用步骤:
1.创建字符缓冲输出流对象,构造方法中传递字符输出流
2.调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区中
3.调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据,刷新到文件中
4.释放资源
/*
java.io.BufferedWriter extends Writer
BufferedWriter:字符缓冲输出流
继承自父类的共性成员方法:
- `void write(int c)` 写入单个字符。
- `void write(char[] cbuf) `写入字符数组。
- `abstract void write(char[] cbuf, int off, int len) `写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
- `void write(String str) `写入字符串。
- `void write(String str, int off, int len)` 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
- `void flush() `刷新该流的缓冲。
- `void close()` 关闭此流,但要先刷新它。
构造方法:
BufferedWriter(Writer out) 创建使用默认大小的输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out, int sz) 创建一个新的缓冲字符输出流,使用给定大小的输出缓冲区。
参数: Writer out:字符输出流
我们可以传递FileWriter,缓冲流会给FileWriter增加一个缓冲区,提高FileWriter的写入效率
int sz:指定缓冲区的大小,不写默认大小
特有的成员方法:
void newLine():写一行行分隔符。会根据不同的操作系统,获取不同的行分隔符
换行:换行符号:
windows:\r\n
linux:/n
mac:/r
使用步骤:
1.创建字符缓冲输出流对象,构造方法中传递字符输出流
2.调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区中
3.调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据,刷新到文件中
4.释放资源
*/
public class Demo03 {
public static void main(String[] args) throws IOException {
//1.创建字符缓冲输出流对象,构造方法中传递字符输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
// 2.调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区中
for (int i = 0; i < 10; i++) {
bw.write("City");
bw.newLine();
}
// 3.调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据,刷新到文件中
bw.flush();
//4.释放资源
bw.close();
}
}
字节缓冲输入流
构造方法
BufferedReader(Reader in)
:创建使用默认大小的输入缓冲区的缓冲字符输入流。BufferedReader(Reader in, int sz)
:创建使用指定大小的输入缓冲区的缓冲字符输入流。
参数
Reader in:字节输入流
我们可以传递FileReader,缓冲流会给FileReader增加一个缓冲区,提高FileReader的读取效率
特有的成员方法
String readLine()
:读取一个文本行,读取一行数据。
行的终止符号:通过下列字符之一即可认为某行已终止:换行('\n'),回车('\r')或者回车后直接跟着换行(\r\n)。
返回值:包含行的内容的字符串,不包括任何行终止字符,如果已达到流的末尾,则为null
使用步骤
1.创建字符缓冲输入流对象,构造方法中传递字符输入流
2.使用字符缓冲输入流对象中的方法read/readLine读取文本
3.释放资源
/*
java.io.BufferedReader extends Reader
继承自父类的共性成员方法
int read() :读一个字符
int read(char[] cbuf) :将字符读入数组。
abstract void close() :关闭流并释放与之相关联的任何系统资源。
构造方法:
BufferedReader(Reader in) 创建使用默认大小的输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz) 创建使用指定大小的输入缓冲区的缓冲字符输入流。
参数:
Reader in:字节输入流
我们可以传递FileReader,缓冲流会给FileReader增加一个缓冲区,提高FileReader的读取效率
特有的成员方法:
String readLine() :读取一个文本行,读取一行数据。
行的终止符号:通过下列字符之一即可认为某行已终止:换行('\n'),回车('\r')或者回车后直接跟着换行(\r\n)。
返回值:包含行的内容的字符串,不包括任何行终止字符,如果已达到流的末尾,则为null
使用步骤;
1.创建字符缓冲输入流对象,构造方法中传递字符输入流
2.使用字符缓冲输入流对象中的方法read/readLine读取文本
3.释放资源
*/
public class Demo04 {
public static void main(String[] args) throws IOException {
//1.创建字符缓冲输入流对象,构造方法中传递字符输入流
BufferedReader br = new BufferedReader(new FileReader("b.txt"));
// 2.使用字符缓冲输入流对象中的方法read/readLine读取文本
/*String line = br.readLine();
System.out.println(line);
line = br.readLine();
System.out.println(line);
line = br.readLine();
System.out.println(line);
line = br.readLine();
System.out.println(line);*/
/*
使用循环优化
*/
/*String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}*/
char[] cs = new char[5];
int len=0;
while ((len=br.read(cs))!=-1){
System.out.print(new String(cs,0,len));
}
//3.释放资源
br.close();
}
}
6.4 练习对文本内容进行排序
分析
1.创建一个HashMap集合对象,可以:存储每行文本的序号(1,2,3,....);value;存储每行的文本
2.创建字符缓冲输入流对象,构造方法中绑定字符输入流
3.创建字符缓冲输出流对象,构造方法中绑定字符输出流
4.使用字符缓冲输入流的方法readLine,逐行读取文本
5.对读取到的文本进行切割,获取行中的序号和文本内容
6.把切割好的序号和文本的内容存储到HashMap集合中
7.遍历HashMap结合,获取每一个键值对
8.把每一个键值对,拼接为一个文本行
9.把拼接好的文本,使用字符缓冲输出流的方法writr,写入到文件中
10.释放资源
*
练习:对文本内容进行排序
分析:
1.创建一个HashMap集合对象,可以:存储每行文本的序号(1,2,3,....);value;存储每行的文本
2.创建字符缓冲输入流对象,构造方法中绑定字符输入流
3.创建字符缓冲输出流对象,构造方法中绑定字符输出流
4.使用字符缓冲输入流的方法readLine,逐行读取文本
5.对读取到的文本进行切割,获取行中的序号和文本内容
6.把切割好的序号和文本的内容存储到HashMap集合中
7.遍历HashMap结合,获取每一个键值对
8.把每一个键值对,拼接为一个文本行
9.把拼接好的文本,使用字符缓冲输出流的方法writr,写入到文件中
10.释放资源
*/
public class Demo05 {
public static void main(String[] args) throws IOException {
// 1.创建一个HashMap集合对象,可以:存储每行文本的序号(1,2,3,....);value;存储每行的文本
HashMap<String, String> map = new HashMap<>();
//2.创建字符缓冲输入流对象,构造方法中绑定字符输入流
BufferedReader br = new BufferedReader(new FileReader("G:\\testIO\\in.txt"));
//3.创建字符缓冲输出流对象,构造方法中绑定字符输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("G:\\testIO\\out.txt"));
//4.使用字符缓冲输入流的方法readLine,逐行读取文本
String line;
while ((line=br.readLine())!=null){
//5.对读取到的文本进行切割,获取行中的序号和文本内容
String[] arr = line.split("\\.");
//6.把切割好的序号和文本的内容存储到HashMap集合中
map.put(arr[0],arr[1]);
}
// 7.遍历HashMap结合,获取每一个键值对
for (String key : map.keySet()) {
String value=map.get(key);
//8.把每一个键值对,拼接为一个文本行
line = key+"."+value;
//9.把拼接好的文本,使用字符缓冲输出流的方法writr,写入到文件中
bw.write(line);
bw.newLine();
}
//10.释放资源
bw.close();
br.close();
}
}
7、 转换流
7.1 字符编码和字符集
字符编码
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。
编码:字符(能看懂的)--字节(看不懂的)
解码:字节(看不懂的)-->字符(能看懂的)
-
字符编码
Character Encoding
: 就是一套自然语言的字符与二进制数之间的对应规则。编码表:生活中文字和计算机中二进制的对应规则
字符集
- 字符集
Charset
:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。
计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。
可见,当指定了编码,它所对应的字符集自然就指定了,所以编码才是我们最终要关心的。
- ASCII字符集 :
- ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。
- 基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符。ASCII的扩展字符集使用8位(bits)表示一个字符,共256字符,方便支持欧洲常用字符。
- ISO-8859-1字符集:
- 拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等。
- ISO-8859-1使用单字节编码,兼容ASCII编码。
- GBxxx字符集:
- GB就是国标的意思,是为了显示中文而设计的一套字符集。
- GB2312:简体中文码表。一个小于127的字符的意义与原来相同。但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。
- GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。
- GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。
- Unicode字符集 :
- Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。
- 它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案,UTF-8、UTF-16和UTF-32。最为常用的UTF-8编码。
- UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码,编码规则:
- 128个US-ASCII字符,只需一个字节编码。
- 拉丁文等字符,需要二个字节编码。
- 大部分常用字(含中文),使用三个字节编码。
- 其他极少使用的Unicode辅助字符,使用四字节编码。
7.2 编码引出的问题
在IDEA中,使用FileReader
读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8
编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码。
/*
FileReader可以读取IDE默认编码格式(UTF-8)的文件
FileReader读取系统默认编码(中文GBK)会产生乱码
*/
public class Demo06 {
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("G:\\testIO\\GBK.txt");
int len=0;
while ((len=fr.read())!=-1){
System.out.print((char) len);
}
fr.close();
//�������
}
}
那么如何读取GBK编码的文件呢? ? ?
转换流的原理
转换流是字节与字符间的桥梁!
7.3 OutputStreamWriter类
转换流java.io.OutputStreamWriter
,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。
构造方法
OutputStreamWriter(OutputStream out)
:创建一个使用默认字符编码的OutputStreamWriter。OutputStreamWriter(OutputStream out, String charsetName)
:创建一个使用指定字符集的OutputStreamWriter。
参数
OutputStream out:字节输出流,可以用来写转换之后的字节到文件中
String charsetName:指定的编码表名称,不区分大小写,可以是utf-8,gbk....,不指定使用UTF-8
使用步骤
1.创建OutputStreamWriter对象,构造方法中传递字节输出流和制定的编码表名称
2.使用OutputStreamWriter对象中的方法write,吧字符转换为字节存储到缓冲区中(编码)
3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
4.释放资源
/*
java.io.OutputStreamWriter extends Writer
OutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的charset将要写入流中的字符编码成字节.(编码:把能看懂的变成看不懂的)
继承自父类的共性成员方法:
- `void write(int c)` 写入单个字符。
- `void write(char[] cbuf) `写入字符数组。
- `abstract void write(char[] cbuf, int off, int len) `写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
- `void write(String str) `写入字符串。
- `void write(String str, int off, int len)` 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
- `void flush() `刷新该流的缓冲。
- `void close()` 关闭此流,但要先刷新它。
构造方法:
OutputStreamWriter(OutputStream out)创建一个使用默认字符编码的OutputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName) :创建一个使用指定字符集的OutputStreamWriter。
参数:
OutputStream out:字节输出流,可以用来写转换之后的字节到文件中
String charsetName:指定的编码表名称,不区分大小写,可以是utf-8,gbk....,不指定使用UTF-8
使用步骤
1.创建OutputStreamWriter对象,构造方法中传递字节输出流和制定的编码表名称
2.使用OutputStreamWriter对象中的方法write,吧字符转换为字节存储到缓冲区中(编码)
3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
4.释放资源
*/
public class Demo01 {
public static void main(String[] args) throws IOException {
//write_utf_8();
write_GBK();
}
/*
使用转换流写GBK格式的文件
*/
private static void write_GBK() throws IOException {
// 1.创建OutputStreamWriter对象,构造方法中传递字节输出流和制定的编码表名称
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("GBK.txt"),"GBK");
//2.使用OutputStreamWriter对象中的方法write,吧字符转换为字节存储到缓冲区中(编码)
osw.write("你好");
//3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
osw.flush();
// 4.释放资源
osw.close();
}
/*
使用转换流写UTF-8格式的文件
*/
private static void write_utf_8() throws IOException {
// 1.创建OutputStreamWriter对象,构造方法中传递字节输出流和制定的编码表名称
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("UTF-8.txt"));
//2.使用OutputStreamWriter对象中的方法write,吧字符转换为字节存储到缓冲区中(编码)
osw.write("你好");
//3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
osw.flush();
// 4.释放资源
osw.close();
}
}
7.3 InputStreamReader类
InputStreamReader
:是从字节流到字符流的桥:它读取字节,并使用指定的charset将其解码为字符 。(解码:吧看不懂的变成看的懂的).
构造方法
InputStreamReader(InputStream in)
:创建一个使用默认字符集的InputStreamReader。InputStreamReader(InputStream in, String charsetName)
:创建一个使用命名字符集的InputStreamReader。
参数:
InputStream in:字节输入流,用来读取文件中保存的字节
String charsetName:指定的编码表名称,不区分大小写,可以是utf-8,gbk....,不指定使用UTF-8
使用步骤
1.创建InputStreamReader对象,构造方法中传递字节输入流和制定的编码表名称
2.使用InputStreamReader对象中的方法read读取文件
3.释放资源
注意事项
构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码
/*
java.io.InputStreamReader extends Reader
InputStreamReader:是从字节流到字符流的桥:它读取字节,并使用指定的charset将其解码为字符 。(解码:吧看不懂的变成看的懂的)
继承父类的共性成员方法:
int read() :读一个字符
int read(char[] cbuf) :将字符读入数组。
abstract void close() :关闭流并释放与之相关联的任何系统资源。
构造方法:
InputStreamReader(InputStream in) :创建一个使用默认字符集的InputStreamReader。
InputStreamReader(InputStream in, String charsetName) :创建一个使用命名字符集的InputStreamReader。
参数:
InputStream in:字节输入流,用来读取文件中保存的字节
String charsetName:指定的编码表名称,不区分大小写,可以是utf-8,gbk....,不指定使用UTF-8
使用步骤:
1.创建InputStreamReader对象,构造方法中传递字节输入流和制定的编码表名称
2.使用InputStreamReader对象中的方法read读取文件
3.释放资源
注意事项
构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码
*/
public class Demo02 {
public static void main(String[] args) throws IOException {
// read_utf_8();
read_GBK();
}
/*
使用InputStreamReader读取GBK格式的文件
*/
private static void read_GBK() throws IOException {
// 1.创建InputStreamReader对象,构造方法中传递字节输入流和制定的编码表名称
InputStreamReader isr = new InputStreamReader(new FileInputStream("GBK.txt"), "GBK");
//2.使用InputStreamReader对象中的方法read读取文件
int len=0;
while((len=isr.read())!=-1){
System.out.print((char)len);
}
//3.释放资源
isr.close();
}
/*
使用InputStreamReader读取UTF-8格式的文件
*/
private static void read_utf_8() throws IOException {
// 1.创建InputStreamReader对象,构造方法中传递字节输入流和制定的编码表名称
InputStreamReader isr = new InputStreamReader(new FileInputStream("UTF-8.txt"), "UTF-8");
//2.使用InputStreamReader对象中的方法read读取文件
int len=0;
while((len=isr.read())!=-1){
System.out.print((char)len);
}
//3.释放资源
isr.close();
}
}
7.4 联系:转换文件编码
将GBK编码的文本文件,转换为UTF-8编码的文本文件。
分析
- 指定GBK编码的转换流,读取文本文件。
- 使用UTF-8编码的转换流,写出文本文件
/*
将GBK编码的文件转换为UTF-8编码的文本文件
分析:
1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表示名称GBK
2.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称UTF-8
3.使用InputStreamReader对象中的方法read读取文件
4.使用OutputStreamWriter对象中的方法Write,吧读取的数据写入到文件中。
5.释放资源。
*/
public class ReverseStream {
public static void main(String[] args) throws IOException {
//1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表示名称GBK
InputStreamReader isr = new InputStreamReader(new FileInputStream("G:\\testIO\\GBK.txt"), "GBK");
// 2.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称UTF-8
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("G:\\testIO\\UTF-8.txt"));
//3.使用InputStreamReader对象中的方法read读取文件
int len=0;
while((len=isr.read())!=-1){
//4.使用OutputStreamWriter对象中的方法Write,吧读取的数据写入到文件中。
osw.write(len);
}
// 5.释放资源。
osw.close();
isr.close();
}
}
8、 序列化
8.1 概述
Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据
、对象的类型
和对象中存储的属性
等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据
、对象的类型
和对象中存储的数据
信息,都可以用来在内存中创建对象。看图理解序列化:
原理图:
8.2 ObjectOutputStream类
java.io.ObjectOutputStream
类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
构造方法
ObjectOutputStream(OutputStream out)
:创建一个指定OutputStream的ObjectOutputStream。
序列化操作
- 一个对象要想序列化,必须满足两个条件:
- 该类必须实现
java.io.Serializable
接口,Serializable
是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException
。 - 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用
transient
关键字修饰。
序列和反序列化的时候会抛出java.io.NotSerializableException没有序列化异常
类通过java.io.Serializable接口以启用其序列化功能,未实现此接口的类将无法使其任何状态序列化或反序列化
Serializable接口也叫标记性接口
要进行序列化和反序列化的时候,就会检测类上是否有这个标记
有:就可以序列化和反序列化
没有:就会抛出NotSerializableException异常
Person类
/*
序列和反序列化的时候会抛出java.io.NotSerializableException没有序列化异常
类通过java.io.Serializable接口以启用其序列化功能,未实现此接口的类将无法使其任何状态序列化或反序列化
Serializable接口也叫标记性接口
要进行序列化和反序列化的时候,就会检测类上是否有这个标记
有:就可以序列化和反序列化
没有:就会抛出NotSerializableException异常
*/
public class Person implements Serializable {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.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;
}
}
主方法
/*
java.io.ObjectOutputStream extends OutputStream
ObjectOutputStream:对象的序列化流
作用:把对象以流的方式写入到文件中
构造方法:
ObjectOutputStream(OutputStream out) 创建一个写入指定的OutputStream的ObjectOutputStream。
OutputStream out:字节输出流
特有的成员方法:
void writeObject(Object obj) :将指定的对象写入ObjectOutputStream。
使用步骤:
1.创建ObjectOutputStream对象,构造方法中传递字节输出流。
2.使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中
3.释放资源
*/
public class Demo01 {
public static void main(String[] args) throws IOException {
//1.创建ObjectOutputStream对象,构造方法中传递字节输出流。
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
//2.使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中
oos.writeObject(new Person("CityD",21));
//3.释放资源
oos.close();
}
}
8.3 ObjectInputStream类
ObjectInputStream
:对象的反序列化流
作用:把文件中保存的对象,以流的方式读取出来使用
构造方法
ObjectInputStream(InputStream in)
:创建从指定的InputStream读取的ObjectInputStream。
参数:
InputStream in:字节输入流
特有的成员方法
Object readObject()
:从ObjectInputStream读取一个对象。
使用步骤
1.创建ObjectInputStream对象,构造方法中传递字节输入流
2.使用ObjectInputStream对象中的方法readObject读取保存对象的文件。
3.释放资源
4.使用读取出来的对象(d打印)
反序列化操作:
ClassNotFoundException异常
readObject() 方法声明抛出了ClassNotFoundException(class文件找不到)
当不存在对象的class文件时抛出此异常
反序列化前提:
1.类必须实现Serializable
2.必须存在类对应的class文件
/*
java.io.ObjectInputStream extends InputStream
ObjectInputStream:对象的反序列化流
作用:把文件中保存的对象,以流的方式读取出来使用
构造方法:
ObjectInputStream(InputStream in) :创建从指定的InputStream读取的ObjectInputStream。
参数:
InputStream in:字节输入流
特有的成员方法:
Object readObject() :从ObjectInputStream读取一个对象。
使用步骤:
1.创建ObjectInputStream对象,构造方法中传递字节输入流
2.使用ObjectInputStream对象中的方法readObject读取保存对象的文件。
3.释放资源
4.使用读取出来的对象(d打印)
readObject() 方法声明抛出了ClassNotFoundException(class文件找不到)
当不存在对象的class文件时抛出此异常
反序列化前提:
1.类必须实现Serializable
2.必须存在类对应的class文件
*/
public class Demo02 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1.创建ObjectInputStream对象,构造方法中传递字节输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"));
//2.使用ObjectInputStream对象中的方法readObject读取保存对象的文件。
Person person = (Person) ois.readObject();
//3.释放资源
ois.close();
//4.使用读取出来的对象(d打印)
System.out.println(person);
}
}
InvalidClassException异常
另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException
异常。发生这个异
常的原因如下:
- 该类的序列版本号与从流中读取的类描述符的版本号不匹配
- 该类包含未知数据类型
- 该类没有可访问的无参数构造方法
Serializable
接口给需要序列化的类,提供了一个序列版本号。serialVersionUID
该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
8.4 transient 关键字
- static关键字:静态关键字
静态优先于非静态加载到内存中(静态优先于对象进入到内存中)
被static修饰的成员变量不能被序列化,序列化的都是对象private static int age;
oos.writeObject(new Person("CityD",21));
Person person = (Person) ois.readObject();
Person
- transient 关键字:瞬态关键字
被transient修饰的成员变量,不能被序列化
private transient int age;
oos.writeObject(new Person("CityD",21));
Person person = (Person) ois.readObject();
Person
8.5 练习:序列化集合
- 把若干学生对象 ,保存到集合中。
- 把集合序列化。
- 反序列化读取时,只需要读取一次,转换为集合类型。
- 遍历集合,可以打印所有的学生信息
分析:
- 定义一个存储Person对象的的ArrayList集合
- 往ArrayList集合中存储Person对象
- 创建一个序列化流ObjectOutputStream对象
- 使用ObjectOutputStream对象中的方法writeObject对集合进行序列化
- 创建一个序列化流ObjectInputStream对象
- 使用ObjectInputStream对象中的方法readObject读取文件中保存的集合
- 把Object类型的集合转换为ArrayList的类型
- 遍历ArrayList集合
- 释放资源
/*
联系:序列化集合
当我们想在文件中保存多个对象的时候
可以把多个对象存储到一个集合中
对集合进行序列化和反序列化
分析:
1.定义一个存储Person对象的的ArrayList集合
2.往ArrayList集合中存储Person对象
3.创建一个序列化流ObjectOutputStream对象
4.使用ObjectOutputStream对象中的方法writeObject对集合进行序列化
5.创建一个序列化流ObjectInputStream对象
6.使用ObjectInputStream对象中的方法readObject读取文件中保存的集合
7.把Object类型的集合转换为ArrayList的类型
8.遍历ArrayList集合
9.释放资源
*/
public class Demo03 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1.定义一个存储Person对象的的ArrayList集合
ArrayList<Person> list = new ArrayList<>();
//2.往ArrayList集合中存储Person对象
list.add(new Person("张三",15));
list.add(new Person("李四",16));
list.add(new Person("王五",45));
//3.创建一个序列化流ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt"));
// 4.使用ObjectOutputStream对象中的方法writeObject对集合进行序列化
oos.writeObject(list);
//5.创建一个序列化流ObjectInputStream对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("list.txt"));
//6.使用ObjectInputStream对象中的方法readObject读取文件中保存的集合
Object o = ois.readObject();
//7.把Object类型的集合转换为ArrayList的类型
ArrayList<Person> list2 = (ArrayList<Person>) o;
//8.遍历ArrayList集合
for (Person person : list2) {
System.out.println(person);
}
// 9.释放资源
ois.close();
oos.close();
}
}
9、打印流
9.1 概述
平时我们在控制台打印输出,是调用print
方法和println
方法完成的,这两个方法都来自于java.io.PrintStream
类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。
PrintStream特点
1.只负责数据的输出,不负责数据的读取
2.与其他输出流不同,PrintStream永远不会抛出IOException
3.有特有的方法,print,println
void print(任意类型的值)
void println(任意类型的值并换行)
构造方法
PrintStream(File file)
:输出的目的地是一个文件PrintStream(OutputStream out)
:输出的目的地是一个字节输出流PrintStream(String fileName)
:输出的目的地是一个文件路径
注意:如果使用集成父类的write方法写数据,那么查看数据的时候会查询编码表 97->a
如果使用自己特有的方法print/println方法写数据,写的数据原样输出 97->97
/*
java.io.PrintStream :打印流
PrintStream:为其他输出流添加了功能,使他们能够方便的打印出各种数据值表示形式
PrintStream特点:
1.只负责数据的输出,不负责数据的读取
2.与其他输出流不同,PrintStream永远不会抛出IOException
3.有特有的方法,print,println
void print(任意类型的值)
void println(任意类型的值并换行)
构造方法:
1.PrintStream(File file):输出的目的地是一个文件
2.PrintStream(OutputStream out):输出的目的地是一个字节输出流
3.PrintStream(String fileName) :输出的目的地是一个文件路径
java.io.PrintStream extends OutputStream
继承自父类的成员方法
* `public void close()` :关闭此输出流并释放与此流相关联的任何系统资源。
* `public void flush() ` :刷新此输出流并强制任何缓冲的输出字节被写出。
* `public void write(byte[] b)`:将 b.length字节从指定的字节数组写入此输出流。
* `public void write(byte[] b, int off, int len)` :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
* `public abstract void write(int b)` :将指定的字节输出流。
注意:如果使用集成父类的write方法写数据,那么查看数据的时候会查询编码表 97->a
如果使用自己特有的方法print/println方法写数据,写的数据原样输出 97->97
*/
public class Demo01 {
public static void main(String[] args) throws FileNotFoundException {
//创建打印流PrintStream对象,构造方法中绑定要输出的目的地
PrintStream ps = new PrintStream("print.txt");
//如果使用集成父类的write方法写数据,那么查看数据的时候会查询编码表 97->a
ps.write(97);
// 如果使用自己特有的方法print/println方法写数据,写的数据原样输出 97->97
ps.println(97);
ps.println(8.8);
ps.println('a');
ps.println("hello world");
//释放资源
ps.close();
}
}
可以改变输出语句的目的地(打印流的流向)
输出语句,默认在控制台输出
使用System.setOut()方法改变输出语句的目的地改为参数中传递的打印流的目的地
static void setOut(PrintStream out)
重新分配"标准"输出流
/*
可以改变输出语句的目的地(打印流的流向)
输出语句,默认在控制台输出
使用System.setOut()方法改变输出语句的目的地改为参数中传递的打印流的目的地
static void setOut(PrintStream out)
重新分配"标准"输出流
*/
public static void main(String[] args) throws FileNotFoundException {
System.out.println("我在控制台输出");
PrintStream ps = new PrintStream("i.txt");
System.setOut(ps);
System.out.println("我在i.txt中输出");
ps.close();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY