IO高级
缓冲流
简介:给普通的IO流套上一个缓冲区,所有的使用缓冲流进行的读写操作都是和缓冲区进行交互的,避免了频繁的IO操作,这样一来,带来的好处就是可以提高读写的效率,这个缓冲区实质上是一个数组。
缓冲流的作用:
为了提高读写的能力,本身没有读写的能力,要想进行读写就必须借助字符流/字节流实现,可以将缓冲流类比于催化剂或者高速的小车
常见的缓冲流:
BufferedInputStream:缓冲字节输入流
BufferedOutputStream:缓冲字节输出流
BufferedReader:缓冲字符输入流
BufferedWriter:缓冲字符输出流
字符流和缓冲字符流对比:
FileWriter | BufferedWriter |
---|---|
有写的能力 | 没有写的能力 |
FileWriter(){} | public BufferWriter(Writer writer){this.writer = writer;} |
write() | write(){//1.实现写 writer.write(); //2.提高效率的代码 } |
write(数组) | |
write(字符串) | |
close() | close(){//1.将写出流关闭并刷新 writer.close() //2.将自己关闭} |
使用缓冲流实现读写的步骤与字符流一样,只需要我们先通过构造方法传入一个字符流对象,同时缓冲流可以提高读写效率
总结:大家在使用流读写数据时,尽量使用缓冲流,缓冲流中尽量使用缓冲字符流,在字符缓冲流中比缓冲字节流中多了readLine()和newLine()方法
缓冲字节流
package bk.javase.p604.IO.Buffer;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
BufferedInputStream使用
*/
public class TestBufferedInputStream {
public static void main(String[] args){
/*
过程与InputStream一模一样的
缓冲字节输入流是需要基于一个字节输入流来进行实例化的
在这里,BufferedInputStream构造方法中的InputStream对象,只是用来做当前的对象的实例化,在使用结束的时候,理论上来讲是需要关闭的
实际上使用结束之后,只需要关闭BufferedInputStream即可
*/
try( BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("C:\\TestIO\\from\\hello.txt"))) {
//1.实例化一个字节数组
byte[] array = new byte[1024];
//2.声明一个整型变量,用来记录每次读取到了多少个字节数据
int length = 0;
//3.循环读取
while((length = bufferedInputStream.read(array))!= -1){
//4.将读取到的数据转成字符串输出到控制台
String message = new String(array,0,length);
System.out.println(message);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package bk.javase.p604.IO.Buffer;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestBufferedOutputStream {
public static void main(String[] args){
//1.实例化一个缓冲字节输出流对象
try(BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("C:\\TestIO\\from\\hello.txt"))){
//2.将数据写到输出流中
bufferedOutputStream.write("hello,world,hello,everyone".getBytes());
bufferedOutputStream.flush();
} catch(FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
缓冲字符流
package bk.javase.p604.IO.Buffer;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class TestBufferedWriter {
public static void main(String[] args){
//1.借助一个字符输出流,实例化一个缓冲字符输出流对象
try(BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("C:\\TestIO\\from\\hello.txt"))){
bufferedWriter.write("王者荣耀是真的好玩,都给我上号");
bufferedWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package bk.javase.p604.IO.Buffer;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class TestBufferedReader {
public static void main(String[] args){
//借助一个字符输入流,实例化一个缓冲字符输入流
try(BufferedReader bufferedReader = new BufferedReader(new FileReader("C:\\TestIO\\from\\hello.txt"))) {
//从流中读取数据
char[] array = new char[100];
int length = 0;
while((length = bufferedReader.read(array)) != -1){
System.out.println(new String(array,0,length));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
缓冲字符流中的特殊方法:
BufferedReader类中多了一个方法readLine()
意义:读取缓冲流中的一行数据,可以逐行读取,一直到读到的数据为null,表示数据读完了,没有下一行数据了
注意事项:readLine()是逐行读取,但是,只能读到一行中的内容,并不能读取换行符
package bk.javase.p604.IO.Buffer;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderSpecial {
public static void main(String[] args){
try(BufferedReader reader = new BufferedReader(new FileReader("C:\\TestIO\\from\\hello.txt"))) {
//1.定义一个字符串,用来接收每行读取到的数据(形如length)
String line = "";
//2.循环读取数据
while((line = reader.readLine()) != null){
//3.将读取到的数据输出
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} ;
}
}
BufferedWriter类中多了一个newLine()
1.写换行符,不同的系统中使用的默认换行符不一样,window系统 \r\n Linux系统 \n
2.意义:无参的方法,写一个换行符,支持跨平台(平台无关性)
package bk.javase.p604.IO.Buffer;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriterSpecial {
public static void main(String[] args){
try(BufferedWriter bufferWriter = new BufferedWriter(new FileWriter("C:\\TestIO\\from\\hello.txt"))) {
bufferWriter.write("王者荣耀");
bufferWriter.newLine();
bufferWriter.write("是真的");
bufferWriter.newLine();
bufferWriter.write("好玩");
} catch (IOException e) {
e.printStackTrace();
}
}
}
LineNumberReader:
是BufferedReader的子类,不能读,但是可以提高效率,特有功能;设置行号,获取行号
设计模式简介:
设计模式是前人总结出来的对一些常见问题的解决方案,后人直拿来使用。常见的设计模式:单例,工厂,代理,适配器,装饰,适配器,装饰,模板,观察者等,一共有23种
装饰设计模式:
基于已经实现的功能,提供增强的功能
装饰设计模式的特点:
1.装饰设计模式的由来就来自于缓冲流的实现
2.从缓冲流的角度分析:使流原来的继承体更加简单;提高了效率;由于是在原有的基础上提高增强的功能,所 以他还属于原来的体系
Scanner
简介:
这个类,并不是一个IO流。而是一个扫描器,这个类最主要的作用,是从一个文件中或者一个流中浏览数据,在这个类中封装了若干个方法,方便了数据的读取
API:
方法 | 描述 |
---|---|
next() | 读取一个单词,遇到空格或者换行符就不再读取了 |
hasNext() | 判断是否还有下一个单词可以读取 |
nextLine() | 读取一行内容,遇到换行符就不再读取了 |
hasNextLine() | 判断是否还有下一行可以读取 |
注意事项:
这里的nextLine()和BufferedReader中的readLine()都可以读取一行数据,但是区别条件在于:结束条件不同
1.BufferedReader:如果读取到的数据时null,说明没有下一行数据了
2.Scanner:如果没有下一行了,再去读取,会出现异常,所以,此时的结束条件是hasNextLine()为false
package bk.javase.p604.IO.Buffer;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class TestScanner {
public static void main(String[] args){
//其实,Scanner在使用结束之后,也是需要进行关闭的,调用close()方法
try(Scanner scanner = new Scanner(new File("C:\\TestIO\\from\\hello.txt"))){
//读取文件中的内容
while(scanner.hasNextLine()){
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
标准输入输出流:
简介:
标准输入流:System.in:“标准”输入流。此流已打开并准备提供输入数据。通常对应于键盘输入或者由主机环境或用户指定的另一个输入源
package bk.javase.p604.IO.Buffer;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
/*
标准输出流
*/
public class TestSystem {
public static void main(String[] args) {
// //创建了标准输入流并关联了键盘(默认的)
// InputStream inputStream = System.in;
// //阻塞式方法
// int num = 0;
// try {
// num = inputStream.read();
// } catch (IOException e) {
// e.printStackTrace();
// }
// System.out.println(num);
// }
try(BufferedInputStream bufferedInputStream = new BufferedInputStream(System.in)){
byte[] array = new byte[128];
int length = 0;
while((length = bufferedInputStream.read(array)) != -1){
String str = new String(array,0,length);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
输入源:可以发送数据到内存的设备
输出源:可以接收内存的数据的设备
1.当前的流已经打开并关联了输入源-键盘
2.是一个字节流
3.如果不想让键盘充当输入源,可以通过setIn进行更换
标准输入流:System.out:标准输出流,此流已经打开并准备接受输出数据。通常,此流对应于显示器输出,或者由主机环境或用户指定的另一个输出目标
package bk.javase.p604.IO.Buffer;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
/*
标准输出流
*/
public class TestSystemOut {
public static void main(String[] args){
PrintStream original = System.out;
//PrintStream:是一个打印,可以将数据输出到指定位置
try(PrintStream ps = new PrintStream(new FileOutputStream("C:\\TestIO\\from\\hello.txt",true))){
//此时输出流会将内容打印到C:\TestIO\from\hello.txt中
// ps.println("helloWorld");
System.setOut(ps);
//原本按照经验来说,System.out.println()会将内容打印到控制台
//但是因为我重新设置了标准输出流,所以内容没被打赢到控制台而是指定的位置
System.out.println("123");
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally{
System.setOut(original);
}
System.out.println("你好");
//System.out 标准输出流地址,将内容输出到控制台
}
}
转换流:
使用转换流的作用:在进行文件读取的时候,如果项目采用的字符集和文件的字符集不同,会出先乱码的情况下,但使用转换流可以解决这个问题
//使用方法类似于缓冲流
//转换输入流:可以以指定的字符集读取某一个文件中的数据
//转换输出流:可以以指定的字符集把数据写入到某一个文件
InputStreamReader reader = new InputStreamReader(new FileInputStream(),"GBK");
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(),"GBK");
打印流
简介:除了拥有输出流的特点之外,还有打印的功能
字节打印流:PrintStream
字符打印流:PrintWriter
字节打印流:
字节打印流支持的设备:
File类型的文件
字符串类型的文件
字节输出流
package bk.javase.p604.IO.Buffer;
import java.io.*;
public class TestPrintStream {
public static void main(String[] args){
/*
字节打印流支持的设备
*/
// //1.File类型的文件
// PrintStream p1 = new PrintStream(new File("C:\\TestIO\\from\\hello.txt"));
// //2.字节输出流
// PrintStream p2 = new PrintStream(new FileOutputStream("C:\\TestIO\\from\\hello.txt"));
// //3.字符串类型的文件
// PrintStream p3 = new PrintStream("C:\\TestIO\\from\\hello.txt");
//实例
try {
PrintStream p1 = new PrintStream(new File("C:\\TestIO\\from\\hello.txt"));
//直接使用write方法打印,默认只支持一个字节,所以当数据超出了一个字节的范围,会出现以下错误
// p1.write(97);//00000000 01100001----->a
// p1.write(353);//00000001 01100001---->a 默认直接删掉八位之外的所有数据
//所以为了避免出现这样的问题,我们不直接使用write()方法,而是使用print()方法
p1.print(353);
//此时展示一下print方法的内部实现原理
//先将353转成字符串再转成字节数组
p1.write(String.valueOf(353).getBytes());
p1.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符打印流:
字符打印流支持的设备:
File类型的文件
字符串类型的文件
字节输出流
字符写入流
package bk.javase.p604.IO.Buffer;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class TestPrintWriter {
public static void main(String[] args) {
PrintWriter pw;
{
try {
pw = new PrintWriter(new FileWriter("C:\\TestIO\\from\\hello.txt"));
pw.write("bingbing");
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意点:
public PrintWriter(Writer out,boolean autoFlush){}
autoFlush-boolean变量:如果为true,则println,printf或format方法将自动刷新输出缓冲区,但是执行print()方式时需要手动刷新
编码问题:
常用的字符集:
中国的字符集:GBK/GB2312
欧洲的:ISO8859-1
通用的:UTF-8
美国的:ASCII
对中文的处理:
GBK:2个字节,ISO8859-1:1个字节,UTF-8:3个字节,Unicode:2个字节
说明:GBK,UTF-8支持中文,ISO8859-1不支持中文
编码:将字符串转化成byte序列的过程
解码:将byte序列转成字符串的过程
编码错误(乱码):乱码,在执行读写的时候,由于使用的字符集不同,会出现编码的错误
解决办法:先编码再解码
序列化流:
简介:
将短期存储的数据实现长期存储,这个过程对应的流的就是序列化流
数据的存储分成两类:
1.短期存储:存放到内存里,随着程序的关闭而释放----对象,集合,数组,变量
2.长期存储:存储在磁盘中,即使程序关闭了,数据仍然存在—文件
序列化:将数据从内存放到磁盘,可以实现数据的长久保存
反序列化:将数据从磁盘放回到内存
注意事项:
ObjectInputStream,ObjectOutpurStream,主要是用来做对象的序列化和反序列化
序列化和反序列化是对象的持久化存储的一种常用手段
所有的要序列化到本地的对象,类必须实现java.io.Serilizable接口
实现Serilizable接口的类可以达到的目的
1.可以进行序列化
2.进行序列化的类的元素必须支持可序列化
3.可序列化类的所有子类型本身都是可序列化的
4.接口本省没有方法或者字段,只是用来表示可序列化的语义
如果需要序列化多个文件到本地,尽量不要序列化到一个文件中,如果需要序列化多个文件到本地,通常采用的方式,是存集合,将多个对象存入到一个集合中,将这个集合序列化到本地
Properties
简介:
properties不是一个IO流,而是一个集合,是HashTable的子类
使Properties主要是为了描述程序中的属性列表文件,有时候,我们会将一些比较简单的项目配置信息,以.properties格式的文件进行存储,可以使用Propeprties对象读写.properties文件
注意:
因为存储的是属性,属性本身就是以键值对的方式存储,这里的键和值都必须是字符串,所以不需要考虑泛型