第十章、IO流
10.1、File 类的使用
1)概念
在java中,在日常生活中,经常会对电脑上的文件进行操作,比如:把程序中的内容, 写入 到电脑上文件中;或者是把电脑中的文
件的内容,读取到 程序 中;这种过程,就叫做流( 数据 ),这种文件的操作,java中使用File类来解决。
Java中把文件或者目录(文件夹)都封装成File对象。也就是说如果我们要去操作硬盘上的文件,或者文件夹只要找到File这个类即可。
2)相对路径和绝对路径
相对路径:从项目的根目录开始,一直找到文件,那么这个寻找路径,叫做相对路径
绝对路径 :windows: 从磁盘的根目录(文件夹) 一直找到文件,那么这个寻找的路径,就叫做绝对路径
3)持久化的概念
把java程序中的数据,存储到硬盘的文件中,永久保存,那么这个过程就叫做持久化。
4)File 类的常用 API:
1、创建对象,借助构造方法
File(File parent, String child)
//根据父文件对象和子文件路径来创建File对象
File(String pathName)
//通过文件路径来创建File对象
File(String parent, String child)
//通过父路径和子路径来创建File对象
2、路径符号的说明:
1)windows平台可以同时使用””和”/”作为分隔符,如果””分隔符,那么java程序必须要转义成”/”
2)在Linux和Unix平台上只能使用”/”来作为分隔符
3)所以一般我们使用”/”来作为分隔符。
4)在java中,”/”也可以写成”//”
3、创建文件和文件夹
1)创建单文件
boolean createNewFile()
//在本地路径创建新文件,会抛出异常
//如果文件存在,就不会再创建,返回,false
2)创建单文件夹
boolean mkdir()
创建此抽象路径名指定的目录。
3)创建多级文件夹
boolean mkdirs()
创建此抽象路径名指定的目录,包括所有必需但不存在的父目录
案例:
public class Test {
public static void main(String[] args) throws IOException {
//java 不会默认创建文件夹,只能自己创建文件夹,然后在已有文件夹下创建文件
File file = new File("D://植物大战僵尸//aa.txt");
boolean newFile1 = file.createNewFile(); //创建文件
System.out.println("newFile1 = " + newFile1);
File file1 = new File("D://ff");
file1.mkdir(); //创建目录
File file2 = new File(file1, "ff.txt");
boolean newFile2 = file2.createNewFile();
System.out.println("newFile2 = " + newFile2);
File file3 = new File("D://gg//kk");
file3.mkdirs(); //创建多级目录
File file4 = new File(file3, "tt.txt");
boolean newFile3 = file4.createNewFile();
System.out.println("newFile3 = " + newFile3);
}
}
4、如何删除
删除文件或者文件夹
如果删除的是文件,那么该文件必须存在,如果不存在,返回 false
如果删除的是目录,那么该目录必须是空,才能删除。(所以删除不为空的目录,要从目录中的最小单位开始删除)
boolean delete()
删除此抽象路径名表示的文件或目录。
5、如何移动
IO 流的操作,复制文件
6、如何查看文件或文件夹基本路径
String getAbsolutePath()
//获取文件的绝对路径
String getName()
//获取文件或者文件夹的名称
String getPath()
//获取相对路径(构造方法传入路径)
long length()
//获取文件的长度(单位 byte)
long lastModified()
//文件的最后修改时间
File[] listFiles()
//返回一个目录下面所有的文件和文件夹,形成文件对象数组
案例:
@Test
public void test07() throws IOException {
File file = new File("E://aa.txt");
System.out.println(file.getAbsolutePath());
System.out.println(file.getName());
System.out.println(file.getPath());
System.out.println(file.length());
//把最后修改时间打印为字符串形式
System.out.println(new Date(file.lastModified()).toLocaleString());
}
7、判断性方法
1、判断文件或者文件夹是否存在,如果存在,返回 true
boolean exists()
//测试此路径名表示的文件或者目录是否存在
2、判断文件对象是否是一个文件夹(目录),如果是,返回 true
boolean isDirectory()
//测试此抽象路径名表示的文件是否是一个目录
3、判断文件对象是否是一个文件,如果是,返回 true
boolean isFile()
//测试此抽象路径名表示的文件是否是一个标准文件
案例:
@Test
public void test06() throws IOException {
//判断一个file是否是目录/文件夹?
//isDirectory(): 判断file是否是一个文件夹
File file = new File("E://mm//dd");
System.out.println("该file是否是一个文件夹?:"+file.isDirectory());
//isFile():判断file是否是一个文件
File file1 = new File("E://mm//dd//dd.txt");
System.out.println("该file是否是一个文件?"+file1.isFile());
//删除文件:
boolean delete = file1.delete();
System.out.println("delete = " + delete);
boolean delete1 = file.delete();
System.out.println("文件夹是否删除成功? = " + delete1);
}
10.2、递归算法
概念:表示在一个java程序中,在方法中调用自己的方法。可以解决某些复杂的问题。
语法:
例如:
public void show(){
//在递归算法中,必须要有结束条件。
show();//在方法调用自己的方法。
}
特点:
1)方法自己调用自己
2)在递归调用中,必须要有结束递归的条件,返回结果。
缺点:
1)如果没有结束条件,会造成内存溢出错误:
java.lang.StackOverflowError: 栈内存溢出
案例:
实现1+2+3+4+…+n的功能,要求不能使用for、while、乘
法等 。
分析:求1~100的和。
class Test01{
public static void main(String[] args) {
System.out.println(add(100));
}
public static int add(int num){
if (num == 1){
return num;
}
return num + add(num-1);
}
}
作业:使用递归的方式输出某个文件夹下面的所有的子文件夹和文件。
输出:子文件夹和文件的路径,名称
1)获取 获取目录下所有的文件 目录下所有的文件和文件夹
2)判断是否是文件或者文件夹
3)如果是文件夹,就继续递归调用。
public class OutFiles {
public static void main(String[] args) {
File file = new File("D://获取目录下所有的文件");
outFiles(file);
}
public static void outFiles(File file){
if (file.isDirectory()){
System.out.println(file.getName() + " :");
File[] files = file.listFiles();
for (File file1 : files) {
outFiles(file1);
}
} else {
System.out.println(file.getName());
}
}
}
10.3、Idea 如何创建代码模板
10.4、IO 流概念
1)什么是流?
硬件设备和程序之间进行数据交互;数据在硬件和程序之间流动;类似于水流;叫做I(input) , O(output) 流
2)IO 流作用
保存/读取文件、文件上传和下载、网络通信/socket
3)流的分类
根据传输时方向划分:
输出流,输出流
说明:
1)源:需要传输的数据本身
2)目标对象:把数据传输到哪里
3)如果复制文件:输出流和输入流是成对出现的
根据传输数据格式划分:
字节流:byte 字节
字符流:char 字符
说明:
1)字节流:一般用在传输非文本文件的数据, 二进制数据 ,比如:图片,视频,word.excel,ppt… 就是说它们不能使用记事本打开,打开了是乱码。
2)字符流:一般用来处理文本数据,比如:txt文本等。可以使用记事本打开的数据;不乱码。
3)字节流:byte字节 1byte=8位 ,最小的单位,什么都能处理。
4)字符流:1字符=2字节,只能处理 文本文件 。
IO 流总结图:
总结:
1)stream 的都是字节流,除转换流之外
2)Writer 和 Reader 的都是字符流,除转换流之外
3)缓存流都有 Buffered
4)文件的问题说明
a)哪些文件是文本文件?哪些文件是非文本文件?如果判断?
后缀
b)文本文件和非文本文件用什么流操作?
文本文件用字符流
非文本文件用字节流
c)字节流(InputStream和OutputStream)能否读取文本文件?
能
10.5、字符流(FileReader 和 FileWriter)
抽象类:Reader 和 Writer
FileReader 和 FileWriter 使用的是抽象类中的方法。
1、字符输出流:FileWriter
a、构造方法创建对象
1)如果构造方法,只有一个参数。那么默认是覆盖模式,后面的内容覆盖掉之前的内容。
2)如果构造方法,有两个参数,并且第二个参数是 true,那么就是追加模式,后面的内容直接追加到文件的结尾。如果第2个参数是 false ,也是覆盖模式。
FileWriter 构造方法
FileWriter(File file)
根据给定的 File 对象构造一个 FileWriter 对象
FileWriter(File file, boolean append)
根据给定的 File 对象构造一个 FileWriter 对象
FileWriter(String Name)
根据给定的文件名构造一个 FileWriter 对象
FileWriter(String fileName, boolean append)
根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象
b、Writer 常见方法介绍
返回值类型 方法说明
abstract void close () 关闭此流,但要先刷新它。
abstract void flush () 刷新该流的缓冲。
void write (char[] cbuf) 写入字符数组。
abstract void write (char[] cbuf, int off, int len) 写入字符数组的某一部分。参数:
cbuf - 字符数组
off - 开始写入字符处的偏移量
len - 要写入的字符数
void write (int c) 写入单个字符。
void write ( String str) 写入字符串。
void write ( String str, int off, int len) 写入字符串的某一部分。str字符串,off: 开始字符位置,len:写入字符的长度
c、输出流使用步骤:
1)创建输出流对象
2)调用 write() 方法
3)调用 flush() 方法
4)关闭流
d、flush() 和 close() 的区别?
1)flush() 可以把数据写入到硬盘中,刷新缓冲区,可以随时调用,随时刷新。
2)close() 关闭流,释放资源;操作2步:1.刷新缓冲区 2.关闭流
如果关闭流之后,再次调用 write() 方法,会报错:java.io.IOException: Stream closed
e、案例:
需求:演示使用字符输出流把程序中的文本写入到本地文件中。
@Test
public void test01() throws IOException {
//创建字符输出流对象
//true: 表示追加模式,否则就是覆盖模式
//如果aa.txt文件不存在,默认会自动创建
FileWriter fileWriter = new FileWriter("D://xf2007//U1//dd.txt",true); //接着续写
//FileWriter fileWriter = new FileWriter("aa.txt"); //覆盖输出
//向文件中写入数据 - 暂时放在缓存区
fileWriter.write("今天天气非常好!");
//刷新缓存区,把数据真正写入到文件中
//fileWriter.flush();
fileWriter.append('A');
// fileWriter.flush();
//操作完成之后,关闭流
fileWriter.write("郭德纲");
fileWriter.close();
//流关闭之后,不能再写任何内容
// fileWriter.write("柳岩");
}
2、字符输入流:FileReader
a、使用构造方法创建对象
FileReader(File file)
在给定从中读取数据的 File 的情况下创建一个新 FilReader。
FileReader(String fileName)
在给定从中读取数据的文件名的情况下创建一个新 FileReader。
b、Reader 常用的方法介绍
abstract void close () 关闭该流并释放与之关联的所有资源。
int read () 读取单个字符。用的少 返回字符的int形式,需要强转,如果已到达流的末尾,则返回 -1
int read (char[] cbuf) 将字符读入数组。用这个,读取的字符数,如果已到达流的末尾,则返回 -1
abstract int read (char[] cbuf, int off, int len) 将字符读入数组的某一部分。不用
c、输入流使用步骤
1)创建输入流对象
2)调用读的方法,有2种方式:
- 调用 read() 方法,一次读取一个字符。
- 调用 read(char[] char) 方法:读取的效率更高,使用字符数组缓存区来读取字符,实现步骤:
- 创建字符数组缓冲分区,大小1024的N倍数
- 创建循环遍历 int len ;
- 循环遍历,读取字符数组
- 把字符数组转换成字符串对象
3)关闭流
d、案例
需求:演示把本地文本文件中的数据读入到程序中。
@Test
public void eee() throws IOException {
FileReader reader = new FileReader("D://xf2007//U1//dd.txt");
//读取数据 - 字符
int ch = 0;
// 使用循环读取 //read()每次读取一个字符
while ((ch = reader.read()) != -1){
System.out.println((char) ch);
}
// 读取完成之后,关闭流
reader.close();
}
//或者如下方法
@Test
public void test03() throws IOException {
FileReader reader = new FileReader("D://xf2007//U1//dd.txt");
char[] chars = new char[2];
int len = 0;
while ((len = reader.read(chars)) != -1){
String s = new String(chars,0,len);
System.out.print(s);
}
}
e、使用字符流实现文本文件的复制操作
复制文件
需求:将一个文本文件的内容复制到项目中的文件new.txt 。
@Test
public void test01(){
//1.创建输入流和输出流对象
FileReader reader = null;
FileWriter writer = null;
try {
reader = new FileReader("D://xf2007//U1//dd.txt");
writer = new FileWriter("new.txt",true);
//2.把E://dd.txt的内容读取到程序中
char [] chars = new char[1024];
int len = 0; //读取字符次数
while ((len = reader.read(chars)) != -1){
//3.把读取的内容,直接写入到new.txt中
writer.write(chars,0,len);
//4.把内容刷新进入文件
writer.flush();
}
System.out.println("文件复制成功!");
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
reader.close();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
10.6、字节流(FileInputStream 和 FileOutputStream)
字节流:一般用来处理非文本文件,但是也可以处理文本文件。
FileInputStream:字节输入流
FileOutputStream:字节输出流
1、FileInputStream:字节输入流
a、构造方法创建对象
FileInputStream(File file)
通过打开一个到实际文件的连接来创建一个 FileInputStream ,该文件通过文件系统中的 File 对象 file 指定
FileInputStream(String name)
通过打开一个到实际文件的连接来创建一个 FileInputStream ,该文件通过文件系统中的路径名 name 指定
b、输入流 InputStream 介绍
void close() 关闭此输入流并释放与该流关联的所有系统资源。
abstract int read() 从此输入流中读取数据的下一个字节。
int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中
int read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组
c、如何使用
跟字符流使用方式差不多
案例:演示使用字节输入流读取文本文件内容。
@Test
public void test02() throws IOException {
//使用字节流读取 D:/xf2007/U1/dd.txt
FileInputStream fis = new FileInputStream("D://xf2007//U1//dd.txt");
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes)) != -1){
String string = new String(bytes, 0, len);
System.out.println(string);
}
fis.close();
}
2、FileOutputStream:字节输出流
a、构造方法创建对象
FileOutputStream(File file)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流
FileOutputStream(File file, boolean append)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流
FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(String name, boolean append)
创建一个向具有指定 name 的文件中写入数据的输出文件流。
b、输出流 OutputStream 介绍
void close() 关闭此输出流并释放与此流有关的所有系统资源。
void flush() 刷新此输出流并强制写出所有缓冲的输出字节。
void write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流
void write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
abstract void write(int b) 将指定的字节写入此输出流。
在字节输出流的方法中,没有write(String),所以,如果想写入字符
串,必须要先转换成字节数组。
可以使用str.getBytes()方法,把一个字符串转换成字节数组,然后
再写入到文件中。
c、如何使用
案例:演示使用字节输出流把程序中的字符写入文本文件中。
@Test
public void test03() throws IOException {
//通过字节输出流写入数据到 ff.txt
FileOutputStream fos = new FileOutputStream("ff.txt", true);
// getBytes():把字符串转换为字节数组
fos.write("小黄你好".getBytes());
fos.write('A');
//UTF-8 :1个汉字 = 3个字节
fos.write("郭德纲你好".getBytes(),3,3);
fos.close();
}
d、使用字节流复制文件
需求:复制图片文件
@Test
public void test04() throws IOException {
//创建字节流输出和输入对象
FileInputStream fis = new FileInputStream("D://图片//壁纸onepiece.jpg");
FileOutputStream fos = new FileOutputStream("tt.jpg");
byte[] bytes = new byte[1024*5];
int len = 0;
while ((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
fos.flush();
}
System.out.println("图片已复制完成");
fis.close();
fos.close();
}
e、总结
字节流:操作2进制数据
字符流:操作文本数据
10.7、转换流
1)概念:
转换流也是一种处理流,它提供了字节流和字符流之间的转换,是字节和字符之间的桥梁。
输入流:InputStreamReader
输出流:OutputStreamWriter
2)使用场景:
当字节和字符之间有转换动作时
流操作的数据需要编码或解码时
参考资料: https://blog.csdn.net/u013905744/article/details/51923671
3)解决乱码思路:
1、只需要修改文件的编码格式就可以了
2、使用转换流来解决该问题
你好:GBK : 55 -44 , 33 -34
你好:UTF-8 : 11 -12 -23 , -19 -56 -78
图示:
解码:
编码:
4)转换流特点:
1、转换流是字节和字符之间的桥梁。
2、可以通过获取 字符流 的数据,通过指定的 编码 转换成 字节 。
3、可以通过获取 字节流 的数据,通过指定的 编码 转换成 字符 。
4、可以指定编码格式。
5)具体的对象体现:
1、inputStreamReader 是字节流通向字符流的桥梁,是 Reader 类的子类,把字节流转换成字符流。
2、OutputStreamWriter 是字符流通向字节流的桥梁,是 Writer 类的子类,把字符流转换成字节流。
6)InputStreamReader 介绍
如何创建转换流对象?
语法:输入转换流(字节输入流);
InputStreamReader(InpurStream in)
创建一个使用默认字符集的 InputStreamReader 。
InputStreamReader(InputStream in,String charsetname)
创建使用指定字符集的 inputStreamReader。
charsetName:表示指定的字符编码,可以使用指定的字符编码来实现编码的转换。
常用方法:
int read(char[] cbuf) 将字符读入数组。
7)OutputStreamWriter 介绍
如何创建转换流对象?
OutputStreamWriter(OutputStream out)
创建使用默认字符编码的 OUtputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName)
创建使用指定字符集的 OutputStreamWriter。
常用方法:
void write(String str)
写入字符串
8)练习
1)使用转换流指定编码格式来读取文本文件。
2)使用转换流指定编码格式来写入文本文件。
//使用转换流指定编码格式来读取文本文件。
@Test
public void test02() throws Exception {
//转换流:输入流
//创建字符输入流
InputStream fis = new FileInputStream("E://aa.txt");
//创建转换流:输入流
//指定编码:GBK 去解码转换流转换的字符。
InputStreamReader isr = new InputStreamReader(fis,"gbk");
char[] chars = new char[1024];
int len = 0;
while ((len = isr.read(chars))!=-1){
System.out.println(new String(chars,0,len));
}
//从小往大关闭
fis.close();
isr.close();
}
//使用转换流指定编码格式来写入文本文件。
@Test
public void test03() throws Exception {
//创建转换流:输出流
//把字符数据写入到文件中,指定编码格式:UTF-8
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E://aa.txt"),"utf-8");
osw.write("你好");
osw.close();
}
10.8、缓冲流(也叫高效流)
1)什么是缓冲流?为什么需要缓冲流?什么时候使用缓冲流?
(1) 通过对字符流和字节流的封装/包装,提高IO流的读写速度。
(2) 一般我们还是使用
FileReader,FileWriter,FileIputStream,FileOutputStream(基础流); 但是需要增强流的时候,就使用缓冲流,读取的时候,是一行一行的读取
(3) 相当于在基础流(字节流,字符流) ,的基础上套接了缓冲(Buffered) => 缓冲流(基础流)
基础流:直接对硬盘进行数据的读写。
缓冲流:在内存中创建了缓冲区,来暂时保存数据,然后在读取/写入
2)缓冲流的分类:
缓冲:Buffered
缓冲字符流:
缓冲字符输入流:BufferedReader(FileReader(文件对象/路径))
缓冲字符输出流:BufferedWriter(FileWriter)
缓冲字节流:
缓冲字节输入流:BufferedInputStream(FileInputStream)
缓冲字节输出流:BufferedeOutputStream(FileOutputStream)
3)缓冲字符输入流:BufferedReader
1、使用构造方法创建对象
套接:缓冲流(字符流)
语法:BufferedReader(FileReader)
BufferedReader(Reader in)
创建一个使用默认大小输入缓冲区的缓冲字符输入流。
2、常用方法
String readLine()
读取一个文本行。
包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾·,则返回 null
4)缓冲字符输出流:BufferedWriter
1、使用构造方法创建对象
BufferedWriter(FileWriter)
BufferedWriter(Writer out)
创建一个使用默认大小输出缓冲区的缓冲字符输出流。
2、常用方法
void newLine()
换行的意思,写入一个行分隔符,跟 /n 是一样的效果,但是它跨平台,windows 和 linux 平台都能使用。
@Test
public void test04() throws Exception {
//创建【缓冲字符输入流】对象
BufferedReader br = new BufferedReader(new FileReader("aa.txt"));
String str = null;//判断流是否到达末尾
//readLine(): 一次读取一行数据,如果读到末尾,返回null
while ((str = br.readLine())!=null){
System.out.println(str);
}
br.close();
}
@Test
public void test05() throws Exception {
//创建【缓存字符输出流】对象
BufferedWriter bw = new BufferedWriter(new FileWriter("bb.txt"));
// /n 平台不通用
bw.write("中国");
bw.flush();
//换行
bw.newLine();
bw.write("美国");
bw.flush();
bw.close();
}
3、案例
使用缓冲流来复制文本文件
@Test
public void test06(){
//案例:
//需求:使用缓冲流来复制文本文件
//分析:思路跟我们之前写的字符流的复制文件,完全一样。只是写法略微不同。
//创建流对象
BufferedReader br = null;
BufferedWriter bw = null;
try{
//缓冲流(基础流)
br = new BufferedReader(new FileReader("aa.txt"));
bw = new BufferedWriter(new FileWriter("copy.txt",true));
//读取数据:读取缓冲区中的数据
String str = null;
while ((str=br.readLine())!=null){
//写入数据
bw.write(str);
bw.newLine();//换行
bw.flush();
}
System.out.println("文本文件复制成功!");
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(bw!=null){
bw.close();
}
if(br!=null){
br.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
5)缓冲字节输入流:BUfferedInputStream
1、使用构造方法创建对象
BufferedInputStream(InputStream in)
创建一个 BufferedInputStream 并保存其参数,即输入流 in ,以便将来使用。
2、常用方法
跟 FileInputStream 一样
6)缓冲字节输出流:BufferedOutputStream
1、使用构造方法创建对象
BufferedOutputStream(OutputStram out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
2、常用方法
跟 FileOutputStream 方法一样
3、案例
用缓冲字节流来实现复制MP3文件
@Test
public void test07(){
//演示案例
// 需求:用缓冲字节流来实现复制mp3文件
//创建流对象
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try{
bis = new BufferedInputStream(new FileInputStream("金坷垃原版广告_标清.flv"));
bos = new BufferedOutputStream(new FileOutputStream("搞笑的电影.flv"));
//读取文件
byte[] bytes = new byte[1024*10];
int len = 0;
while ((len=bis.read(bytes))!=-1){
//写入数据
bos.write(bytes,0,len);
bos.flush();
}
System.out.println("视频复制成功!");
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(bos!=null){
bos.close();
}
if(bis!=null){
bis.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
使用缓冲流来复制文本文件,指定文件的编码
@Test
public void test08(){
//案例:
//需求:使用缓冲流来复制文本文件,指定文件的编码
//分析:思路跟我们之前写的字符流的复制文件,完全一样。只是写法略微不同。
//创建流对象
BufferedReader br = null;
BufferedWriter bw = null;
try{
//缓冲流(转换流(基础流))
br = new BufferedReader(new InputStreamReader(new FileInputStream("aa.txt"),"utf-8"));
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("aa.txt"),"utf-8"));
//读取数据:读取缓冲区中的数据
String str = null;
while ((str=br.readLine())!=null){
//写入数据
bw.write(str);
bw.newLine();//换行
bw.flush();
}
System.out.println("文本文件复制成功!");
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(bw!=null){
bw.close();
}
if(br!=null){
br.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
10.9、序列化流
使用场景
序列化流专门用来保存 对象/基本数据类型 到文件中
1)什么是对象的序列化?
实际上,java 程序中的数据本来是不能脱离程序的。想把对象保存到文件中,在需要重新获取对象的时候,再把对象从文件中读取出来。
就是把 java 程序中的对象,写入到文件中存储,这个过程叫对象的序列化。
对象肯定是一个 2进制数据
把对象写入到文件:对象字节输出流:ObjectOutputStream
2)什么是对象的反序列化?
就是把文件中的对象,加载到 java 程序中继续使用,这个过程叫对象的反序列化。
把对象读取到内存中:对象字节输入流:ObjectInputStream
3)总结
对象的序列化:就是把对象转换成字节序列,保存到文件中
对象的反序列化:就是把字节序列转换成对象,读取到内存中
4)应用场景:
1、把对象保存到硬盘中,永久保存。
2、在网络传输中,可以使用序列化来传递对象。
网络编程:TCP编程,把对象通过客户端传递到服务器上使用,或者是交互,使用序列化完成。
5)序列化和反序列化的前提
序列化实现前提:
所操作对象必须实现 java.io.Serializable 接口。否则程序抛
出java.io.NotSerializableException异常
(Serializable :可串行化的,可序列化的)
反序列化实现的前提:
将文件中的serialVersionUID修改与程序中的类版本号码一致。
否则会抛出异常:java.io.InvalidClassException
6)对象字节输出流:ObjectOutputStream
可以把基本数据类型和对象写入到文件中
1、通过构造方法创建对象
语法:对象字节输出流(FileOutputStream)
ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream 的ObjectOutputstream。
2、常用方法
void writeObject(Object obj)
将指定的对象写入 ObjectOutputStream。
3、对象序列化包括如下步骤:
1)必须实现序列化接口:Serializable,如果不实现,报异常:java.io.NotSerializableException
序列化接口没有任何内容,作用:标准、规范,凡是实现了序列化接口的类,可以序列化,否则,报错。
2)创建序列化对象
3)调用 writeobject() 方法
7)对象字节输入流:ObjectInptuStream
可以把我呢见中的对象或者是基本数据类型加载到内存中。
1、通过构造方法创建对象
语法:对象字节输入流(FileInputStream)
ObjectInputStream(InputStream in)
//创建从指定 InputStream 读取的ObjectInputStream。
2、常用方法
Object readObject()
从 ObjectInputStream 读取对象。
3、对象反序列化包括如下步骤:
1)为了保证类修改之后,不会造成版本问题,我们需要给类加上版本号=静态常量属性。
2)创建序列化对象
3)调用 readObject() 方法
8)如何设置自动添加版本号吗?
import lombok.*; //要手动导入lombok包
import java.io.Serializable;
@Builder
@Data //提供了实例类的 getter/setter 方法
@NoArgsConstructor //无参构造
@AllArgsConstructor //全参构造
@ToString //给实体类提供 toString 方法
//实现序列化的接口
public class Person implements Serializable {
//序列号的版本号
private static final long serialVersionUID = 3399676340395159648L;
private String name;
private int age;
private String email;
private String className;
}
//序列化
@Test
public void test01() throws IOException {
//创建 对象 字节输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
//new 对象 - 堆内存
Person person = new Person("郭德纲",48, "[email protected]","2207");
//把对象写入本地文件中,实现对象的保存
oos.writeObject(person); //异常:NotSerializableException
oos.close();
}
//反序列化
@Test
public void test02() throws IOException, ClassNotFoundException {
//创建 对象字节输入流(字节输入流)
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"));
//读取文件中对象
Object object = ois.readObject();
if (object instanceof Person){
Person person = (Person) object;
System.out.println(person);
}
ois.close();
//继续使用person对象
//...
}
9)过度类:DataInputStream 和 DataOutputStream = 了解
主要用来读写基本数据类型
10.10、打印流
可以提高写速度,方便写。
注意:只要写,没有读。
字节打印流:PirntStream
字符打印流:PrintWriter
void println(String x)
打印 String ,然后终止该行。
@Test
public void test03() throws Exception {
//打印流对象 => 只能写入文件
PrintWriter pw = new PrintWriter("dd.txt");
pw.println("今天是周六");
pw.println("哈哈哈");
pw.close();
}
10.11、配置文件(暂时先初步了解)
1)使用场景:
有时候,需要把一些关键性的信息,保存在文件中,在项目运行过程中,去读取这些文件,那么就把这些文件叫做 配置文件 。
把一些重要的数据配置,保存在配置文件中,不保存在代码中。
比如:数据库连接信息(用户名,密码,连接url …) , 关键账号信
息,配置信息。
配置文件的格式:.xml .properties .yml
2)properties 配置文件的特点:
- 以 .properties 作为后缀
- 它的内容必须严格都是以 key = value 的方式保存的,类似 Map 集合
- 不支持泛型,键和值类型固定:String
3)如何创建 properties 文件?
项目 -> 右键 -> new -> file -> Resourse Bundle
一般把数据库访问的关键信息放在 src 目录下。
表示注释
4)使用 Properties类来操作配置文件
Properties 类:本质就是双列集合。父类 Hashtable
5)加载配置文件的方式
- 创建 Properties 对象:Properties prop = new Properties();
- 存储数据:prop.setProperty(String,String);
- 获取数据:prop.getProperty(Strign key)
- 如何遍历?同HashMap
void load(InputStram inStream)
从输入流中读取属性列表(键和元素对)。
void load(Reader reader)
按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
6)练习
通过Properties 读取 key 对应的值
//配置文件信息
#注释:数据库连接配置
#key=value
#key1.key2.key3=value
userName=root
password=123456
java.io.InputStream=这是输入流
java.io.OutputStream=这是输出流
import java.io.FileReader;
import java.util.Properties;
public class PropertiesTest {
public static void main(String[] args) throws Exception{
//1.先创建 Properties 对象
Properties properties = new Properties();
//2.加载 配置文件
properties.load(new FileReader("D://IdeaProjects//wc//U1//U1//day24//src//user.properties"));
//3.获取 value :通过 key 获取 value
String userName = properties.getProperty("userName");
System.out.println("userName = " + userName);
System.out.println(properties.getProperty("password"));
System.out.println(properties.getProperty("java.io.InputStream"));
System.out.println(properties.getProperty("java.io.OutputStream"));
}
}
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/java/280189.html