一、认识IO流
咱们目前学习的是BIO,阻塞的IO流,NIO(none-block-I-O)不阻塞的IO。学习IO流的目的是使用它来读写数据或者写数据到文件。
- BIO 就是传统的 java.io 包,它是基于流模型实现的,交互的方式是同步、阻塞方式,也就是说在读入输入流或者输出流时,在读写动作完成之前,线程会一直阻塞在那里,它们之间的调用时可靠的线性顺序。它的有点就是代码比较简单、直观;缺点就是 IO 的效率和扩展性很低,容易成为应用性能瓶颈。
- NIO 是 Java 1.4 引入的 java.nio 包,提供了 Channel、Selector、Buffer 等新的抽象,可以构建多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层高性能的数据操作方式。Netty 服务器底层使用Netty通信 Tomcat 8.x 底层也支持NIO通信。
- AIO 是 Java 1.7 之后引入的包,是 NIO 的升级版本,提供了异步非堵塞的 IO 操作方式,所以人们叫它 AIO(Asynchronous IO),异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
1.1 IO流分类
1:方向:输入流 和 输出流,输入流是指从磁盘或者其他位置读到内存,输出流是指从内存到磁盘等其他位置
2:内容:字符流 和 字节流
1.2 IO流体系
二、字节流
2.1 文件流
以字节形式读取文件数据,通常适用于读二进制文件 如图片 视频 音频文件等。
2.1.1 输入流 FileInputStream
System.out.println("-------------文件--------------");
//1.创建文件 f 给定文件位置
File file=new File("G:\\javaWorkspeace\\day22\\src\\classExmaple\\FileinputStream\\test.txt");
//判断文件是否存在
if (file.exists()){
System.out.println("该路径是否是文件:"+file.isFile()+" 是不是文件夹:"+file.isDirectory());
System.out.println("路径:"+ file.getPath()+" \n绝对路径:"+file.getAbsolutePath());
System.out.println("最后修改时间:"+file.lastModified()+" 文件大小:"+file.length());
System.out.println("文件名:"+file.getName());
}else {
//新建文件f
file.createNewFile();
}
System.out.println("----------文件输出流-----------");
//2.文件输出流(内存到磁盘)
FileOutputStream fos=new FileOutputStream(file);
String[] masage=new String[]{"你好啊","word","爪洼"};
for (int i = 0; i < 3; i++) {
//翔文件里面写内容,由于文件存储的字节类型,所以这里的masage要转换成字节类型再写进去
fos.write(masage[i].getBytes());
}
//关闭流
fos.close();
2.1.2 输出流 FileOutStream
//3.文件输入流
FileInputStream fis=new FileInputStream(file);
//读数据(磁盘到内存)
byte [] buff=new byte[6]; //6个长度的byte数组来接受磁盘的内容
int len=0; //定义一个长度,来表示缓冲区buff里有没有内容,如果没有则为-1,有则为内容的长度
while ((len=fis.read(buff))!=-1){
//从buff中读取0到len的内容,变成String类型输出
System.out.println(new String(buff,0,len));
}
//关闭输入流
fos.close();
2.2 缓存流
没有特别功能,指定提供了缓冲,优先从缓存中读写,降低和IO设备访问次数提高效率。
2.2.1 输入流 BufferedInputStream
public static void main(String[] args) throws IOException {
//1. 创建流
BufferedInputStream bis =
new BufferedInputStream(
new FileInputStream("G:/word.txt"));
//2. 读文件
byte[] buff = new byte[1024];
int len = 0;
while( (len=bis.read(buff)) !=-1 ){
String xx = new String( buff, 0 , len );
System.out.println(xx);
}
//3.关闭
bis.close();
}
2.2.2 输出流 BufferedOutputStream
public static void main(String[] args) throws IOException {
//1. 创建流
BufferedOutputStream bos =
new BufferedOutputStream(
new FileOutputStream("G:/word.txt") );
//2. 写数据
String massage = "q床前明月光,疑是地上霜q";
bos.write( massage.getBytes() );
bos.flush(); //缓冲流的方法
//3. 关闭流
bos.close();
}
2.3 对象流
对象流作用是,可以把一个对象写到文件中,或者把一个文件中的对象,读取到内存。它就是序列化和反序列化的流:
序列化: 把对象二进制信息 写入流。
反序列化: 从流中读取对象的二进制信息,还原到内存。
2.3.1 序列化流ObjectOutputStream
一个类的对象支持序列化,那么这个类型必须实现一个 Serializable 标志接口。
细节: 一个类要可以被序列化,要求其属性也是可序列化的除非显示添加 transient 修饰 ,表示这个属性不参与序列化。静态属性不参与序列化
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1. 创建流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.dat"));
//2. 读,必须按照序列化顺序读取且不可多读,否则引发EOFException异常。
int num = ois.readInt();
int num2 = ois.readInt();
Coder coder = (Coder) ois.readObject();
System.out.println(num);
System.out.println(num2);
System.out.println(coder);
//3.关闭
ois.close();
}
2.3.2 反序列化流ObjectInputStream
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1. 创建流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.dat"));
//2. 读,必须按照序列化顺序读取且不可多读,否则引发EOFException异常。
int num = ois.readInt();
int num2 = ois.readInt();
Coder coder = (Coder) ois.readObject();
System.out.println(num);
System.out.println(num2);
System.out.println(coder);
//3.关闭
ois.close();
}
三.字符流
3.1 文件流[重点]
以子符形式读取文件数据,通常适用于读取纯文本文件 存文本信息。
3.1.1 FileReader 输入流
public static void main(String[] args) throws IOException {
//1 创建流
FileReader reader = new FileReader("node.txt");
//2 读数据
char[] buff = new char[1024];
int len=0;
while ( (len=reader.read(buff)) !=-1 ){
String str = new String( buff,0,len );
System.out.println(str);
}
//3 关闭
reader.close();
}
3.1.2 FileWriter 输出流
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
System.out.println("输入标题");
String title = scanner.next();
System.out.println("输入内容");
String content = scanner.next();
//把数据写到文件中
//1. 创建
FileWriter fw = new FileWriter("node.txt",true);
//2. 写数据
fw.write(title);
fw.write("\n------------------------------------------\n");
fw.write(content);
fw.write("\n-----------------end----------------------\n");
//3.关闭
fw.close();
}
3.2 缓冲流
3.2.1 BufferedReader 输入流
特别方法 readLine() 可以一次读取一行,如果未读到返回null
public static void main(String[] args) throws IOException {
//1 创建流
BufferedReader br = new BufferedReader( new FileReader("g:/book.txt"));
//2 读数据
String buff=null;
while( (buff =br.readLine()) !=null ){
// System.out.println(buff);
String[] info = buff.split(",");
System.out.println(info[0]);
}
//3.关闭流
br.close();
}
3.2.2 BufferedWriter 输出流
特别方法 newLine() 相当于写一个换行符
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
System.out.println("输入标题");
String title = scanner.next();
System.out.println("输入内容");
String content = scanner.next();
//1.创建流
BufferedWriter bw = new BufferedWriter( new FileWriter("node.txt",true));
//2.写数据
bw.write( title );
bw.newLine(); //写一个回车 换行
bw.write("-------------------------------------");
bw.newLine();
bw.write(content);
bw.newLine();
bw.write("----------------end--------------------");
//3.刷新
bw.flush();
//4.关闭
bw.close();
}
3.3 转换流[重点]
有些时候,如果读取的文件是文本文件,但是提供的却是字节流,字符流明显读取文本字符更加方便,这时可以把字节流转换成字符流操作。
只有字节流转 字符流没有字符流转字节流,转换流本身就是一种字符流。
3.3.1 InputStreamReader 输入流
/**
* 字节输入流 转 字符输入流
*/
public class InputStreamReaderCase {
public static void main(String[] args) throws IOException {
//字符流
BufferedReader br = new BufferedReader( new InputStreamReader( new FileInputStream("d:/text.txt") ) );
String buff = null;
while ( (buff=br.readLine()) !=null ){
System.out.println(buff);
}
br.close();
}
}
3.3.2 OutputStreamWriter 输出流
*
* 字节输出流 转 字符输出流
*/
public class OutputStreamWriterCase {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter( new OutputStreamWriter( new FileOutputStream("d:/text.txt") ) );
bw.newLine();
bw.write("王麻子,20,男,C#");
bw.flush();
bw.close();
}
}
3.4 编码与字符集
编码指的是把字符与数字对应的过程。 字符集就是一张记录了对应关系的信息表。ASCII就是一种编码表。像这种还有很多。
- GBK 国标码
- ISO-8859-1 西欧语言
- Big5 台湾香港 繁体字
- Unicode 联合编码( UTF-8 UTF-16 )
public static void main(String[] args) throws IOException {
String hello = "你好中国";
byte[] bytes = hello.getBytes();// UTF-8 解码
System.out.println(Arrays.toString(bytes));
byte[] buff = {-28, -67, -96, -27, -91, -67, -28, -72, -83, -27, -101, -67};
String newHello = new String( buff ,"UTF-8" ); // 使用 UTF-8 编码
System.out.println(newHello);
System.out.println("--------------------------------------");
FileInputStream fis = new FileInputStream("d:/hello.txt");
InputStreamReader isr = new InputStreamReader(fis,"GBK");
char[] buff2= new char[1204];
int len;
while ( ( len = isr.read(buff2))!=-1 ){
System.out.println(buff2);
}
isr.close();
fis.close();
}
编码解码不一致,就会出现乱码
四.打印流
打印流也是输出流, 存在字节打印流和字符打印流。
字节打印流PrintStream
public class PrintDemo {
public static void main(String[] args) throws IOException {
// 直接打印到文件
PrintStream out = new PrintStream("d:/abc.txt");
out.println("helloword");
// 打印到 其他字节输出流
FileOutputStream os = new FileOutputStream("d:/abc.txt",true);
PrintStream out2 = new PrintStream( os);
out2.println("java");
}
}
字符打印流 PrintWriter
public class PrintDemo {
public static void main(String[] args) throws IOException {
//直接 打印到文件
PrintWriter pw = new PrintWriter("D:/abc.txt");
pw.println("css");
pw.close();
//打印 到其它字符输出流
PrintWriter pw2 = new PrintWriter( new FileWriter("d:/abc.txt",true));
pw2.println("java");
pw2.close();
//打印 到其他字节输出流
PrintWriter pw2 = new PrintWriter( new FileOutputStream("d:/abc.txt",true) );
pw2.println("java");
pw2.close();
}
}