day28_io
- io流
- 字节流
- 字符流
- io中的异常处理
学习目标:
- 说出io流的分类与功能
- 使用字节输出流写出数据到文件
- 使用字节输入流读取数据到程序中
- 理解读取数据read方法的原理
- 使用字节流完成文件的复制
- 使用FileWriter写数据到文件中
- 说出FileWriter中关闭和刷新方法的区别
- 使用FileWriter写数据的常用方法
- 使用FileWriter实现数据的追加和换行
- 使用FileReader读取数据
- 使用FileReader读取数据一次一个字符数组
- 使用Properties的load方法和store方法加载文件中的配置信息
IO
两大类 抽象类 实现子类 缓冲流
----|字节流
----|InputStream
----|FileInputStream
********
----|BufferedInputStream
----|OutputStream
----|FileOutputStream
********
----|BufferedOutputStream
抽象类 缓冲流 实现子类
----|字节流
----|Reader
----|BufferedReader
----|InputStreamReader
----|FileReader
********
----|Writer
----|BufferedWriter
----|OutputStreamWriter
----|FileWriter
********
什么是io呢?
输入与输出
输入:把硬盘中的数据,读取到内存中使用
输出:把内存中的数据写入到硬盘保存
IO流的顶级父类
输入流 | 输出流 | |
---|---|---|
字节流 | InputStream | OutputStream |
字符流 | Reader | Writer |
Java中I/O的操作主要是靠java.io
包下的类和接口来实现的,进行输入和输出操作。输入也可以叫做读取数据,输出也可以叫做写入数据。
IO分类
根据数据的流向分为:输入流 / 输出流
- 输入流:把数据从其他设备上读取到内存当中的流
- 输出流:把数据从内存当中写入到其他设备上的流
根据数据的类型分为:字节流 / 字符流
- 字节流:以字节为单位,读写数据的流
- 字符流:以字符为单位,读写数据的流
字节流
一切皆为字节
一切文件数据(文档、图片、视频、音频...)都是以二进制数字的形式保存,都是一个个字节。数据进行传输的时候,也是以字节形式传输。so字节流可以传输任意文件的数据,在操作流的时候,我们必须明确:无论使用什么样的流对线,低层始终以二进制传输。
字节输出流【OutputStream】
java.io.OutputStream
此抽象类是表示输出字节流的所有类的超类,讲指定的字节信息写入目的地,定义了字节输出流基本共性的方法:
- public void close():关闭此输出流,释放与此流相关的其他任何系统资源
- public void flush():刷新此输出流并强制任何缓冲的输出字节信息被写入
- public void write(byte[ ] b):将b.length字节从指定的字节数组写入到输出流中
- public void write(bytr [ ] ,int off,int len):从指定的字节数组写入len个字节,从偏移量off开始输出到此输出流中
- public abstract void write(int b) :将指定的字节输出到此输出流中
备注:close方法,当完成流的操作时,必须完成此方法,释放系统资源。
FileOutPutStream
java.io.FileOutPutStream
类是文件字节输出流,用于将数据写入到文件
构造方法:
- public FileOutputStream(File file): 创建一个向指定
File
对象表示的文件中写入数据的文件输出流 - public FileOutputStream(String name):创建文件输出流以指定的文件名称写入文件
File file :目的地是一个文件
String name :目的地是一个文件路径
构造方法作用:
- 创建一个FileOutputStream类对象
- 根据构造方法中传递的文件 / 文件路径 (路径上的文件不存在),创建一个空文件
- 会把FileOutputStream对象指向创建好的文件
当你创建一个流对象是,必须先传递文件路径,该路径如果没有这个文件,自己创建;如果有这个文件,情况这个文件当中的数据,再把新的内容写入
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\42123\\Desktop\\newFile.txt");//1
fileOutputStream.write(98);//2
fileOutputStream.close();//3
写入数据的原理:
Java程序--->JVM虚拟机--->OS--->OS中写入数据的方法--->把数据写入
备注:使用FileOutputStream写入硬盘文件时,写入的都是二进制码,使用文本编辑器查看的时候,文本编辑器根据编码表,把字节转换为字符表示让我们看到
数据的追加与续写
如何在保留目标文件中数据的情况下,还能继续添加新的数据到目标文件中?
构造方法:
- public FileOutputStream(File file,boolean append):创建文件输出流以写入由指定的File对象表示的文件中。
- public FileOutputStream(String name,boolean append):创建文件输出流以指定的名称写入文件中
这两个构造方法,参数中都需要传入一个boolean类型的值,true
表示追加数字、false
表示清空原有数据。这样的清况下创建输出流对象,就可以指定是否需要在文件的末尾追加内容。
***使用write方法写入字节***
FileOutputStream fileOutputStream1 = new FileOutputStream("C:\\Users\\42123\\Desktop\\newFile.txt", true);
fileOutputStream1.write("\r\n追加的内容:****".getBytes());
fileOutputStream1.close();
写入换行
在Windows中,换行符号是\r\n
. \r代表回车 \n代表开始新的一行。
在Linux中,换行符号是/n
.
在Mac中,换行符号是/r
.
在Unix中,每行结尾只有换行,即/n
.
回车符\r
和换行符\n
- 回车符:回到一行的开头
- 换行符:下一行(new Line)
系统中的换行:
Windows:每行结尾回车+换行
,即\r\n
Unix系统中,每行结尾只有换行
,即/n
Max系统中,每行结尾只有回车
,即/r
字节输入流【InputStream】
java.io.InputStream
此抽象类表示字节输入流所有类的超类,可以读取字节信息到内存中,它定义了输入流的基本共性方法:
- public void close():关闭此输入流并释放与此相关的其他的任何系统资源
- public abstract int read():从输入流中读取数据的下一个字节
- public int read(byte[ ] b):从输入流中读取一些字节数,并将它们存储到字节数组b当中
备注:close方法,当完成流的操作时,必须完成此方法,释放系统资源。
FileInputStream类
java.io.FileInputStream
类是文件输入流,从硬盘文件中读取字节内容到内存
构造方法
- FileInputStream(File file):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的File对象file命名
- FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名
参数:读取文件的数据源
String name :文件的路径
File file :文件
构造方法的作用:
- 创建一个FileInputStream类对象
- 会把FileInputStream类对象指定到构造方法中要读取的文件
当你创建一个流对象时,必须传入一个文件路径,该路径下,如果没有该文件,会抛出FileNotFoundException
***使用read方法读取字节***
File file = new File("C:\\Users\\42123\\Desktop\\newFile.txt");//路径不存在 抛出FileNotFoundException
//1.
FileInputStream fis = new FileInputStream(file);
//2.
int read = fis.read();//虽然读取了一个字节,但是会被自动提升为int类型
System.out.println(read);//读取到文件末尾会返回-1
读取数据的原理:
Java程序--->JVM虚拟机--->OS--->OS中读取数据的方法--->把数据读取
练习:通过字节流实现图片复制
原理:从已知的文件读取字节,再把读取到的字节写入到另一个文件
FileInputStream fileInputStream = new
FileInputStream("C:\\Users\\42123\\Desktop\\JDK1.6\\QQ图片20201204140227.jpg");
byte[] bytes = new byte[1024];
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\42123\\Desktop\\sss\\bbb.jpg",true);
//1k1k传输
int len = 0;
while ((len = fileInputStream.read(bytes))!=-1){
fileOutputStream.write(bytes,0,len);
}
fileOutputStream.close();
fileInputStream.close();//关闭流有先后顺序 先开的要后关
字符流
当使用字节流读取文件的时候,可能会引发一些小问题。如果你遇到了中文字符时,可能不会显示完整的字符。那是因为一个中文字符占多个字符存储,不同的解码方式导致 。所以出现了字符流类,以字符为单位读写数据,专门用来处理文档文件
字符输入流【Reader】
java.io.Reader
是一个抽象类,表示用于读取字符流所有类的超类,可以读取字符信息到内存当中,定义了字符输入流基本的共性方法:
- public void close():关闭此输入流并且释放与此流相关的其他系统资源
- public int read():从输入流中读取一个字符
- public int read(char [ ] chuf):从输入流中读取多个字符,并将他们存储到字符数组chuf中
FileReader类
java.io.FileReader
类主要用于读取字符文件的便捷类。构造方法使用的是默认的编码字符集和默认的字节缓冲区
备注:
- 字符编码:字节与字符的对应规则在Windows系统中,中文编码默认为GBK编码表,ideal中默认UTF-8
- 字节缓冲区:一个数组,临时存储字节数据
构造方法:
- FileReader(File file):创建一个新的FileReader对象,指定需要读取的file对象
- FileReader(String filename):创建一个新的FileReader对象,指定需要读取的文件名称
当你创建一个流对象时,必须传入一个文件路径,类似于FileInputStream。
char []chuf = new char[1024];
int len =0;
while ((len =fr.read(chuf))!=-1){
/*
字符数组转换为字符串
1.String static valueOf();
2.String (char[] value);
3.String (char[] value,int offset,int count);
*/
System.out.println(String.valueOf(chuf,0,len));
}
fr.close();
使用字符数组读取数据:read( char []chuf)每次读取chuf的长度个字符到数组当中,返回读取到的有效字符个数,当读到末尾的时候,返回-1
.
字符输出流【Writer】
java.io.Writer
抽象类是表示用于输出字符流所有类的超类,将指定的字符信息写入到目的地,它定义了字符输出流的基本共性方法:
- void writer(int c):写入单个字符
- void writer(char [ ] chuf):写入字符数组
- abstract void writer(char [ ] chuf ,int off,int len):写入char数组的一部分,从索引off位置开始,写入len个字符个数
- void writer(String str):写入字符串
- void writer(String str,int off,int len):写入字符串的一部分,从字符串的起始索引off开始,写入len个字符
- void flush():刷新该流的缓冲。
- void close():关闭此流,但是需要先刷新它
FileWriter类
java.io.FileWriter
类是用于写入字符到文件中,构造方法使用系统默认的字符编码和默认的字节缓冲区
构造方法
FileWriter(File file):创建一个新的FileWriter,指定写入的file对象
FileWriter(String name):创建一个新的FileWriter,指定需要写入的文件名称
当你创建一个流对象时,必须传入一个文件路径,类似于FileOutputStream
FileWriter fileWriter = new FileWriter("C:\\Users\\42123\\Desktop\\newFile.txt");
fileWriter.write("34");
//fileWriter.flush();//3.刷新,不释放资源的情况下无法写入
fileWriter.close();//会先把内存缓冲区中的数据刷新到文件中
关闭和刷新
因为内置缓冲区的原因,如果不关闭输出流,无法写入字符到文件中。但是关闭流对象就无法写入数据到文件中。如果既想写入数据到文件中、又不想关闭流对象,那么就需要flush方法
flush():刷新缓冲区,流对象可以继续使用
close():先刷新缓冲区,然后关闭流对象,释放资源,流对象不可使用
写入字符数组:write(char [ ] chuf)
和writer(char [ ] chuf ,int off,int len)
每次可以写入一个字符数组的数据
数据的追加和续写
- FileWriter(File file,boolean append)
- FileWriter(String filename,boolean append)
filename / file:写入数据的目的地
boolean append:追加数据的开关
true:不会创建新的文件覆盖源文件,可以续写
false:创建新的文件覆盖原文件,不能续写
备注:字符类,只能操作文本文件,不能操作图片、视频等非文本文件
所以当我们单纯的就是想操作文本文件,就使用字符流,其他情况一律使用字节流
io的异常处理
JDK1.7之前的处理:
使用try...catch...finally处理流中的异常
FileWriter fileWriter = null; //提高变量的作用域范围,使finally语句块能够使用到
//为什么要初始化?
//以下new对象时可能发生异常 进入catch块,对象可能创建失败,未完成初始化
try {
fileWriter = new FileWriter("", true);
} catch (IOException e) {
e.printStackTrace();
}
try {
fileWriter.write(97);
} catch (IOException e) {
e.printStackTrace();
}
try {
fileWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
JDK1.7之后的处理:
在try后可以增加一个(),在括号中定义流对象,那么这个流对象的作用域就在try中有效。
try中代码执行完毕,会自动把流对象释放,那么自然finally就舍弃了
try(FileWriter fileWriter = new FileWriter("C:\\Users\\42123\\Desktop\\newFile.txt",true);
FileReader fr =new FileReader("C:\\Users\\42123\\Desktop\\newFile.txt")
){//创建流对象,如果多个,使用';'隔开
int len = 0;
while ((len =fr.read())!=-1){
fileWriter.write(len);
}
}catch (IOException e){
e.printStackTrace();
}
可以使用try-with-resource语句,该语句确保了每个资源在语句结束时关闭,所谓的资源(resource)是指在程序完成后,必须要关闭的对象
实际上,编译器并不会特别地为InputStream加上自动关闭。编译器只看try(resource = ...)中的对象是否实现了java.lang.AutoCloseable接口,如果实现了,就自动加上finally语句并调用close()方法。InputStream和OutputStream都实现了这个接口,因此,都可以用在try(resource)中。