文章目录
缓冲流
缓冲流概述
- 缓冲流也称为高效流、或者高级流。之前学习的字节流可以称为原始流
- 作用: 缓冲流自带缓冲区、可以提高原始字节流、字符流读写数据的性能
模型图大概是这样的
我是这样理解的:
数据源相当于水厂,目的地相当于用户,内存相当于居民楼里的水库。
我们想要喝水的话,原始流就是一桶一桶的的从水厂往用户楼的水库挑,用户再从水库往家挑;而缓冲流就是给水厂到用户家的道路进行了装修,通过一条管道直接送到了居民楼中的水库,我们要喝水的话只要从水库里流水就行了。
缓冲流结合字节、字符流的结构图的位置所在
字节缓冲流
字节缓冲流性能优化原理:
- 字节缓冲输入流自带了8KB缓冲池,以后我们直接从缓冲池读取数据,所以性能较好
- 字节缓冲输出流自带了8KB缓冲池,数据就直接写入到缓冲池中去,写数据性能极高了
字节缓冲流
- 字节缓冲输入流(缓冲字节输入流): BufferedInputStream,提高字节输入流读取数据的性能,读写功能上并无变化
- 字节缓冲输出流(缓冲字节输出流): BufferedOutputStream,提高字节输出流读取数据的性能,读写功能上并无变化
构造器 | 说明 |
---|---|
public BufferedInputStream(lnputStream is) | 可以把低级的字节输入流包装成一个高级的缓冲字节输入流管道,从而提高字节输入流读数据的性能 |
public BufferedOutputStream(OutputStream os) | 可以把低级的字节输出流包装成一个高级的缓冲字节输出流,从而提高写数据的性能 |
字节缓冲输入流代码及其相关操作展示
public static void main(String[] args) throws Exception{
try ( InputStream fis=new FileInputStream("Object/abc123.txt");
InputStream bis=new BufferedInputStream(fis);
//InputStream bis=new BufferedInputStream(new FileInputStream("Object/abc123.txt"));
){
byte[] buffer=new byte[1024];
int len;
while ((len=bis.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}
}catch (Exception e){
e.printStackTrace();
}
}
字节缓冲输出流代码及其相关操作展示
public static void main(String[] args) throws Exception{
try ( OutputStream fos=new FileOutputStream("Object/abc.txt");
OutputStream bos=new BufferedOutputStream(fos);
//OutputStream bos=new BufferedOutputStream(new FileOutputStream("Object/abc.txt"));
){
bos.write('a');
bos.write("\r\n".getBytes());
bos.write(97);
}catch (Exception e){
e.printStackTrace();
}
}
建议使用字节缓冲输入流、字节缓冲输出流,结合字节数组的方式来提高字节流读写数据的性能,目前来看是性能最优的组合
综合代码展示
public static void main(String[] args) throws Exception{
try (InputStream bis=new BufferedInputStream(new FileInputStream("Object/abc123.txt"));
OutputStream bos=new BufferedOutputStream(new FileOutputStream("Object/abc.txt"));
){
byte[] buffer=new byte[1024];
int len;
while ((len=bis.read(buffer))!=-1){
bos.write(buffer,0,len);
}
}catch (Exception e){
e.printStackTrace();
}
}
字符缓冲流
字符缓冲输入流
- 字符缓冲输入流: BufferedReader。
- 作用: 提高字符输入流读取数据的性能,除此之外多了按照行读取数据的功能(所以我们最好不用多态)
构造器 | 说明 |
---|---|
public BufferedReader(Reader r) | 可以把低级的字符输入流包装成一个高级的缓冲字符输入流管道,从而提高字符输入流读数据的性能 |
字符缓冲输入流新增功能
方法名称 | 说明 |
---|---|
public String readLine() | 读取一行数据返回,如果读取没有完毕,无行可读返回null |
代码及其相关操作展示
public static void main(String[] args) throws Exception{
try ( Reader fis=new FileReader("Object/abc123.txt");
BufferedReader br=new BufferedReader(fis);
//BufferedReader br=new BufferedReader(new FileReader("Object/abc123.txt"));
){
String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}
}catch (Exception e){
e.printStackTrace();
}
}
字符缓冲输出流
- 字符缓冲输出流: BufferedWriter
- 作用: 提高字符输出流写取数据的性能,除此之外多了换行功能
构造器 | 说明 |
---|---|
public BufferedWriter(Writer w) | 可以把低级的字符输出流包装成一个高级的缓冲字符输出流管道,从而提高字符输出流写数据的性能 |
字符缓冲输出流新增功能
方法名称 | 说明 |
---|---|
public void newLine() | 换行操作 |
代码及其相关操作展示
public static void main(String[] args) throws Exception{
try ( Writer fr=new FileWriter("Object/abc.txt");
BufferedWriter br=new BufferedWriter(fr);
//BufferedWriter br=new BufferedWriter(new FileWriter("Object/abc.txt"));
){
br.write('a');
br.newLine();
br.write(97);
}catch (Exception e){
e.printStackTrace();
}
}
字符缓冲流性能优化原理:
- 字符缓冲流自带8K缓冲区
- 可以提高原始字符流读写数据的性能
转换流
- 之前我们使用字符流读取中文没有乱码,因为代码编码和文件编码都是UTF-8
- 如果代码编码和文件编码不一致,使用字符流直接读取会乱码
- 文件编码和读取的编码必须一致才不会乱码
解决方案
- 使用字符输入转换流
- 可以提取文件(GBK)的原始字节流,原始字节不会存在问题
- 然后把字节流以指定编码转换成字符输入流,这样字符输入流中的字符就不乱码了
转换流结合字节、字符流的结构图的位置所在
字符输入转换流
- 字符输入转换流: InputStreamReader,可以把原始的字节流按照指定编码转换成字符输入流
构造器 | 说明 |
---|---|
public InputStreamReader(InputStream is) | 可以把原始的字节流按照代码默认编码转换成字符输入流(几乎不用,与默认的FileReader一样) |
public InputStreamReader(lnputStream is ,String charset) | 可以把原始的字节流按照指定编码转换成字符输入流,这样字符流中的字符就不乱码了 |
字符输入转换流InputStreamReader作用
- 可以解决字符流读取不同编码乱码的问题
代码及其相关操作展示
public static void main(String[] args) throws Exception {
try (InputStream fis=new FileInputStream("Object/abc123.txt");
Reader isr=new InputStreamReader(fis,"GBK");
//Reader isr=new InputStreamReader(new FileInputStream("Object/abc123.txt"));
//Reader isr=new InputStreamReader(new FileInputStream("Object/abc123.txt"),"GBK");
){
int len;
char[] buffer=new char[1024];
while ((len=isr.read(buffer))!=-1){
System.out.print(new String(buffer,0,len));
}
}catch (Exception e){
e.printStackTrace();
}
}
如果需要控制写出去的字符使用的编码,有两种办法
- 可以把字符以指定编码获取字节后再使用字节输出流写出去 “字符串内容”.getBytes(编码)
- 也可以使用字符输出转换流实现
字符输出转换流
- 字符输出转换流:OutputStreamWriter,可以把字节输出流按照指定编码转换成字符输出流
构造器 | 说明 |
---|---|
public OutputStreamWriter(OutputStream os) | 可以把原始的字节输出流按照代码默认编码转换成字符输出流(几乎不用,与默认的FileWriter一样) |
public 0utputstreamWriter(0utputstream os,String charset) | 可以把原始的字节输出流按照指定编码转换成字符输出流 |
字符输出转换流OutputStreamWriter的作用
- 可以指定编码把字节输出流转换成字符输出流,从而可以指定写出去的字符编码
代码及其相关操作展示
public static void main(String[] args) throws Exception{
try ( OutputStream fos=new FileOutputStream("Object/abc.txt");
Writer osw=new OutputStreamWriter(fos,"GBK");
//Writer osw=new OutputStreamWriter(new FileOutputStream("Object/abc.txt"));
//Writer osw=new OutputStreamWriter(new FileOutputStream("Object/abc.txt"),"GBK");
){
osw.write('a');
osw.write("\r\n");
osw.write(97);
}catch (Exception e){
e.printStackTrace();
}
}
序列化对象
对象字节流结合字节、字符流的结构图的位置所在
对象序列化(对象字节输出流)
- 作用: 以内存为基准,把内存中的对象存储到磁盘文件中去,称为对象序列化
- 使用到的流是对象字节输出流: ObjectOutputStream
- 序列化对象的要求:对象必须实现序列化接口 (Serializable)
- transient修饰的成员变量不参与序列化
class Student implements Serializable{
public static final long serialVersionUID=1;
private transient String name;
}
构造器 | 说明 |
---|---|
public ObjectOutputStream(OutputStream out) | 把低级字节输出流包装成高级的对象字节输出流 |
ObjectOutputStream序列化方法
方法名称 | 说明 |
---|---|
public final void writeObject(Object obj) | 把对象写出去到对象序列化流的文件中去 |
OutputStream fos=new FileOutputStream("Object/abc.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
//ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("Object/abc.txt"));
Student s=new Student("小明",25,65.5);
oos.writeObject(s);
oos.close();
(自己定义一个类,我定义的是Student类)
对象反序列化(对象字节输入流)
- 使用到的流是对象字节输入流: ObjectlnputStream
- 作用:以内存为基准,把存储到磁盘文件中去的对象数据恢复成内存中的对象,称为对象反序列化
构造器 | 说明 |
---|---|
public ObjectInputStream(InputStream out) | 把低级字节输如流包装成高级的对象字节输入流 |
ObjectInputStream序列化方法
方法名称 | 说明 |
---|---|
public Object readObject() | 把存储到磁盘文件中去的对象数据恢复成内存中的对象返回 |
InputStream fis=new FileInputStream("Object/abc.txt");
ObjectInputStream ois=new ObjectInputStream(fis);
//ObjectInputStream ois=new ObjectInputStream(new FileInputStream("Object/abc.txt"));
Student s= (Student) ois.readObject();
System.out.println(s);
ois.close();
我们可以申明序列化的版本号码
- 序列化的版本号与反序列化的版本号必须一致才不会出错
(如果对象序列化中的版本号码进行更改,除非再度实行对象序列化,否则对象反序列化中的代码是不能跑的) - 代码:private static final long serialVersionUID = 1;(必须为serialVersionUID,在类中定义)
public static final long serialVersionUID=1;
打印流
打印流结合字节、字符流的结构图的位置所在
PrintStream和PrintWriter的区别
- 打印数据功能上是一模一样的,都是使用方便,性能高效(核心优势)
- PrintStream继承自字节输出流OutputStream,支持写字节数据的方法
- PrintWriter继承自字符输出流Writer,支持写字符数据出去
(我只说PrintWriter,因为PrintWriter的有参构造器能接Writer类对象,而PrintSteam不能,而且这俩这的功能基本都相同)
PrintWriter
构造器 | 说明 |
---|---|
public PrintWriter(Outputstream os) | 打印流直接通向字节输出流管道 |
public PrintWriter (Writer w) | 打印流直接通向字符输出流管道 |
public PrintWriter (File f) | 打印流直接通向文件对象 |
public PrintWriter (String filepath) | 打印流直接通向文件路径 |
//打印流直接通向字节输出流管道
PrintWriter pw=new PrintWriter(new FileOutputStream("Object/abc123.txt"));
//打印流直接通向字符输出流管道
PrintWriter pw1=new PrintWriter(new FileWriter("Object/abc123.txt"));
//打印流直接通向文件对象
PrintWriter pw2=new PrintWriter(new File("Object/abc123.txt"));
//打印流直接通向文件路径
PrintWriter pw3=new PrintWriter("Object/abc123.txt");
方法名称 | 说明 |
---|---|
public void print(Xxx xx) | 打印任意类型的数据出去 |
public void println(Xxx xx) | 打印任意类型的数据出去并换行 |
pw.print(97); //97
pw.println("你好");
pw.print('a');
pw.println("你好,我是小明");
我们可以改变输出语句的位置,把系统打印流改成我们自己的打印流(只有PrintStream能用)
方法名称 | 说明 |
---|---|
public static void setOut(PrintStream out) | 重新分配“标准”输出流 |
PrintStream pw=new PrintStream("Object/abc.txt");
System.setOut(pw);
System.out.println("hello");
System.out.println("你好");
这样控制台就不打印我们的内容了,而在指定的文件中所显示
Properties集合
Properties集合所在地
Properties属性集对象
- 其实就是一个Map集合,但是我们一般不会当集合使用,因为HashMap更好用
Properties核心作用:
- Properties代表的是一个属性文件,可以把自己对象中的键值对信息存入到一个属性文件中去
- 属性文件:后缀是properties结尾的文件,里面的内容都是 key=value,后续做系统配置信息的
Properties的API:
- Properties和IO流结合的方法:
方法名称 | 说明 |
---|---|
void load(InputStream inStream) | 从输入字节流读取属性列表(键和元素对) |
void load(Reader reader) | 从输入字符流读取属性列表(键和元素对) |
void store(OutputStream out,String comments) | 将此属性列表(键和元素对)写入此 Properties表中,以适合于使用load(Inputstream) 方法的格式写入输出字节流 |
void store(Writer writer, String comments) | 将此属性列表(键和元素对)写入此 Properties表中,以适合使用load(Reader) 方法的格式写入输出字符流 |
public Object setProperty(string key,string value) | 保存键值对 (put) |
public String getProperty(String key) | 使用此属性列表中指定的键搜索属性值(get) |
public Set stringPropertyNames() | 所有键的名称的集合(keySet()) |
setProperty、store代码展示
Properties p=new Properties();
p.setProperty("wanju","5");
p.setProperty("youxiji","6");
p.setProperty("dangao","7");
//参数一:保存字符输出流管道
//参数二:写自己想写的话,可以不写
p.store(new FileWriter("Object/abc.properties"),"hello");
(就是往文件中加入数据)
load代码展示
Properties p=new Properties();
p.load(new FileReader("Object/abc.properties"));
System.out.println(p);
(就是得到文件中的数据)
commons-io框架
commons-io概述
- commons-io是apache开源基金组织提供的一组有关IO操作的类库,可以提高IO功能开发的效率
- commons-io工具包提供了很多有关io操作的类。有两个主要的类FileUtils,IOUtils
jar包可以去官网下,链接: https://commons.apache.org/proper/commons-io/
我这里也准备了资源
链接: https://download.csdn.net/download/m0_75278009/87352013
FileUtils主要有如下方法:
方法名称 | 说明 |
---|---|
String readFileToString(File file,String encoding) | 读取文件中的数据,返回字符串 |
void copyFile(File srcFile,File destFile) | 复制文件 |
void copyDirectoryToDirectory(File srcDir,File destDir) | 复制文件夹 |
代码展示
// 完成文件复制
IOUtils.copy(new FileInputStream("Object/abc123.txt"),new FileOutputStream("Object/abc1.txt"));
// 完成文件复制到某个文件夹下
FileUtils.copyFileToDirectory(new File("D:\\code\\logback.xml"),new File("D:\\"));
// 完成文件夹复制到某个文件夹下!
FileUtils.copyDirectoryToDirectory(new File("D:\\code\\logback"),new File("D:\\"));
JDK1.7自己也做了一些一行代码完成复制的操作:New IO的技术
方法名称 | 说明 |
---|---|
public static Path copy(Path source, Path target, CopyOption… options) | 复制文件 |
//复制文件
Files.copy(Path.of("D:\\Logback类库\\logback.xml"),Path.of("D:\\Logback类库\\logback1.xml"));