一、前言
二、文件字节流
2.1 概述
Java中,凡是涉及到Java程序的输入输出,一般都逃不过IO流,Java中的IO包括BIO和NIO,其中BIO只要是以四大基流基础的各种各样的阻塞流。BIO的四大基流是:InputStream OutputStream Reader Writer,但是它们都是抽象类,不能实例化对象来完成输入输出操作,直接使用的是它们的子类,本部分中,使用FileInputStream和FileOutputStream就可以完成输入输出。
BIO的四大基流
输入流 | 输出流 | |
---|---|---|
字节流 | 字节输入流InputStream | 字节输出流OutputStream |
字符流 | 字符输入流Reader | 字符输出流Writer |
使用BIO流的四个步骤:
1):创建源或者目标对象(挖井).
输入操作: 把文件中的数据流向到程序中,此时文件是源,程序是目标.
输出操作: 把程序中的数据流向到文件中,此时文件是目标,程序是源.
2):创建IO流对象(水管).
输入操作: 创建输入流对象.
输出操作: 创建输出流对象.
3):具体的IO操作.
输入操作: 输入流对象的read方法.
输出操作: 输出流对象的write方法.
4):关闭资源(勿忘). 一旦资源关闭之后,就不能使用流对象了,否则报错.
输入操作: 输入流对象.close();
输出操作: 输出流对象.close().
关于BIO流的方向:
读进来,写出去。
读进来是指:从文件、网络、压缩包或其他数据源到Java程序;
写出去是指:从Java程序到文件、网络、压缩包或其他输出目标。
2.2 文件字节输入流FileInputStream、文件字节输出流FileOutputStream
注意,这里指的文件仅为纯文本文件txt,不包括doc docx等文件。
2.2.1 文件字节输出流
package mypackage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//文件字节输出流
public class Test {
public static void main(String[] args) throws IOException {
File target = new File("stream.txt");// 程序可以自动创建txt文件
OutputStream outputStream = new FileOutputStream(target); // 四大基流不能直接实例化对象,实例化对象还要具体IO类,这里是FileOutputStream
outputStream.write("hello world!".getBytes(), 0, 12);
outputStream.close();
}
}
输出1:
小结1:文件字节输出流,将文本从程序输出到stream.txt中。
2.2.2 文件字节输入流
package mypackage2;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
//文件字节输入流
public class Test {
public static void main(String[] args) throws IOException {
File file = new File("stream.txt");
InputStream inputStream = new FileInputStream(file);
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
String string = new String(buffer, 0, len); // 每次读入一个缓冲大小然后输出
System.out.println(string);
}
inputStream.close();
}
}
输出2:
hello world!
小结2:文件字节输入流,将文本从stream.txt输入到程序中,并打印到控制台。
2.2.3 先读入再写出 从myStream.txt读入,写出到myStream_copy.txt中
package mypackage3;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Test {
// 先读入再写出 从myStream.txt读入,写出到myStream_copy.txt中
// 从myStream.txt中读入数据,然后写入到myStream_copy.txt中
public static void main(String[] args) throws IOException {
File srcFile = new File("myStream.txt"); // 源文件
File destFile = new File("myStream_copy.txt");// 目标文件
InputStream inputStream = new FileInputStream(srcFile);
OutputStream outputStream = new FileOutputStream(destFile);
byte[] buffer = new byte[10];
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
inputStream.close();
outputStream.close();
}
}
输出3:
小结3:先读入再写出,从myStream.txt读入,写出到myStream_copy.txt中,将输入输出流一起使用。
2.2.4 先写出再读入 写出到FileStream.txt,在读入到程序中,打印出来
package mypackage4;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Test {
// 先写出再读入 写出到FileStream.txt,在读入到程序中,打印出来
public static void main(String[] args) throws IOException {
File srcFile = new File("FileStream.txt");// 程序可以自动创建txt文件
File destFile = new File("FileStream.txt");
OutputStream outputStream = new FileOutputStream(srcFile); // 四大基流不能直接实例化对象,实例化对象还要具体IO类,这里是FileOutputStream
InputStream inputStream = new FileInputStream(destFile);
outputStream.write("hello world!".getBytes(), 0, 12);
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
String string = new String(buffer, 0, len); // 每次读入一个缓冲大小然后输出
System.out.println(string);
}
outputStream.close();
inputStream.close();
}
}
输出4:
hello world!
小结4:先写出再读入,写出到FileStream.txt,再读入到程序中,打印出来,输入输出流一起使用。
2.3 面试金手指:文件字节输入流 + 文件字节输出流
Java中,凡是涉及到Java程序的输入输出,一般都逃不过IO流,Java中的IO包括BIO和NIO,其中BIO只要是以四大基流基础的各种各样的阻塞流。BIO的四大基流是:InputStream OutputStream Reader Writer,但是它们都是抽象类,不能实例化对象来完成输入输出操作,直接使用的是它们的子类,本部分中,使用FileInputStream和FileOutputStream就可以完成输入输出。
BIO的四大基流
输入流 | 输出流 | |
---|---|---|
字节流 | 字节输入流InputStream | 字节输出流OutputStream |
字符流 | 字符输入流Reader | 字符输出流Writer |
使用BIO流的四个步骤:
1):创建源或者目标对象(挖井).
输入操作: 把文件中的数据流向到程序中,此时文件是源,程序是目标.
输出操作: 把程序中的数据流向到文件中,此时文件是目标,程序是源.
2):创建IO流对象(水管).
输入操作: 创建输入流对象.
输出操作: 创建输出流对象.
3):具体的IO操作.
输入操作: 输入流对象的read方法.
输出操作: 输出流对象的write方法.
4):关闭资源(勿忘). 一旦资源关闭之后,就不能使用流对象了,否则报错.
输入操作: 输入流对象.close();
输出操作: 输出流对象.close().
关于BIO流的方向:
读进来,写出去。
读进来是指:从文件、网络、压缩包或其他数据源到Java程序;
写出去是指:从Java程序到文件、网络、压缩包或其他输出目标。
三、文件字符流
3.1 引入:字符流
问题1:为什么有了字节流还要有字符流呢?
回答1:乱码问题引入字符流:上面操作的文本都是英文文本,不存在任何乱码问题,如果操作中文文本,字节流存在乱码问题,用字符流解决。使用字节流操作汉字或特殊的符号语言的时候,容易乱码,建议使用字符流.
问题2:为什么有了文件字节流还要有文件字符流呢?
回答2:字符流是字节流的补充:先有字节流,后有字符流,字符流是对字节流的补充.
使用记事本打开某个文件,可以看到内容的就是文本文件,否则可以理解二进制.
一般的,操作二进制文件(图片,音频,视频等)必须使用字节流.
一般的,操作文本文件使用字符流.
如果不清楚是哪一类型文件,使用字节流.
3.2 字符流
3.2.1 文件字符输入流
package mypackage;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
//字符输入流
public class Test {
public static void main(String[] args) throws IOException {
File srcFile = new File("china.txt");
Reader reader = new FileReader(srcFile);
char[] buffer = new char[1024];
int len = -1;
while ((len = reader.read(buffer)) != -1) {
System.out.println(buffer);
}
reader.close();
}
}
输出1:
Java程序员就业前景好,薪资高!
一起来学习Java吧!
小结1:文件字符输入流,将文本内容从china.txt读入程序并打印出来。
3.2.2 文件字符输出流
package mypackage2;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
//字符输出流
public class Test {
public static void main(String[] args) throws IOException {
File file = new File("china.txt");
Writer writer = new FileWriter(file, false);
writer.write("Java程序员就业前景好,薪资高!");
writer.write("\n");
writer.write("一起来学习Java吧!");
writer.flush();
writer.close();
}
}
输出2:
小结2:文件字符输出流,将程序的文本写出到china.txt中。
2.2.3 先输入后输出 从mychina.txt文件输入,输出到mychina_copy.txt文件
package mypackage3;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;
//先输入后输出 从mychina.txt文件输入,输出到mychina_copy.txt文件
public class Test {
public static void main(String[] args) throws Exception {
File srcFile = new File("mychina.txt");
File destfile = new File("mychina_copy.txt");
Reader reader = new FileReader(srcFile);
Writer writer = new FileWriter(destfile, false);
char[] buffer = new char[1024];
int len = -1;
while ((len = reader.read(buffer)) != -1) {
writer.write(buffer, 0, len);
}
reader.close();
writer.close();
}
}
输出3:
小结3:先输入后输出,从mychina.txt文件输入,输出到mychina_copy.txt文件。
2.2.4 先输出后输入 先写出到mychinaChar,再从mychinaChar读入程序,打印到控制台:
package mypackage4;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;
//先输出后输入 先写出到mychinaChar,再从mychinaChar读入程序,打印到控制台
public class Test {
public static void main(String[] args) throws Exception {
File targetFile = new File("mychinaChar.txt");
Writer writer = new FileWriter(targetFile, false);
Reader reader = new FileReader(targetFile);
// 写出到mychinaChar
writer.write("Java程序员就业前景好,薪资高!");
writer.write("\n");
writer.write("一起来学习Java吧!");
writer.flush(); // 字符写出 一定要刷新
char[] buffer = new char[1024];
int len = -1;
while ((len = reader.read(buffer)) != -1) {
System.out.println(buffer);
}
reader.close();
writer.close();
}
}
输出4:
Java程序员就业前景好,薪资高!
一起来学习Java吧!
小结4:先输出后输入,先写出到mychinaChar,再从mychinaChar读入程序,打印到控制台!
3.3 面试金手指:文件字符输入流 + 文件字符输出流
JavaIO流——文件字符流,包括文件字符输入流FileReader,文件字符输出流FileWriter,这两种流联合起来完成最基本的字符操作。
四、提交效率:缓冲流 + byte数组
4.1 引入:缓冲流 + byte数组,两种提高IO效率的方式
比较四种方式下,对于同一文件stream.txt,JavaIO流输入输出操作的总时间。分别是:不使用缓冲流不使用byte数组(代码1),使用缓冲流(代码2),使用byte数组(代码3),同时使用缓冲流和byte数组(代码4)。
注意:txt内容一定要足够大,否则效果不明显,IO流一下子就操作完了
4.2 缓冲流 + byte数组
4.2.1 不使用缓冲流不使用byte数组:直接使用文件字节输入和文件字节输出
package mypackage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
//用缓冲流和缓冲数组提高读写效率 要将文本内容弄长一些效果才明显 同时拥有读入流和写出流
//先读入后写出 从stream.txt中读入,写出到stream_copy.txt中
public class Test {
public static void main(String[] args) throws Exception {
long begin = System.currentTimeMillis();
File srcFile = new File("stream.txt");
File destFile = new File("stream_copy.txt");
InputStream inputStream = new FileInputStream(srcFile);
OutputStream outputStream = new FileOutputStream(destFile);
int len = -1;
while ((len = inputStream.read()) != -1) {
outputStream.write(len);
}
inputStream.close();
outputStream.close();
System.out.println(System.currentTimeMillis() - begin);
}
}
输出1:
640
小结1:不使用缓冲流不使用byte数组,IO流操作速度最慢,640毫秒。
4.2.2 使用缓冲流包一层:缓冲流包裹文件字节输入和文件字节输出
package mypackage2缓冲流;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
//用缓冲流和缓冲数组提高读写效率 要将文本内容弄长一些效果才明显 同时拥有读入流和写出流
//先读入后写出 从stream.txt中读入,写出到stream_copy.txt中
public class Test {
public static void main(String[] args) throws Exception {
long begin = System.currentTimeMillis();
File srcFile = new File("stream.txt");
File destFile = new File("stream_copy.txt");
InputStream inputStream = new BufferedInputStream(new FileInputStream(srcFile));
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(destFile));
int len = -1;
while ((len = inputStream.read()) != -1) {
outputStream.write(len);
}
inputStream.close();
outputStream.close();
System.out.println(System.currentTimeMillis() - begin);
}
}
输出2:
8
小结2:使用缓冲流,加快了速度。
4.2.3 使用byte数组:文件字节读取和文件字节写出都是用byte数组
package mypackage3_1024数组;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
//用缓冲流和缓冲数组提高读写效率 要将文本内容弄长一些效果才明显 同时拥有读入流和写出流
//先读入后写出 从stream.txt中读入,写出到stream_copy.txt中
public class Test {
public static void main(String[] args) throws Exception {
long begin = System.currentTimeMillis();
File srcFile = new File("stream.txt");
File destFile = new File("stream_copy.txt");
InputStream inputStream = new FileInputStream(srcFile);
OutputStream outputStream = new FileOutputStream(destFile);
byte[] buffer = new byte[1024]; // 每次1024个
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
inputStream.close();
outputStream.close();
System.out.println(System.currentTimeMillis() - begin);
}
}
输出3:
1
小结3:使用了byte数组,加快了速度。
4.2.4 同时使用缓冲流和byte数组:缓冲流包一层,然后得到的缓冲流的读入和写出都用byte数组
package mypackage4缓冲流_1024数组;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
//用缓冲流和缓冲数组提高读写效率 要将文本内容弄长一些效果才明显 同时拥有读入流和写出流
//先读入后写出 从stream.txt中读入,写出到stream_copy.txt中
public class Test {
public static void main(String[] args) throws Exception {
long begin = System.currentTimeMillis();
File srcFile = new File("stream.txt");
File destFile = new File("stream_copy.txt");
InputStream inputStream = new BufferedInputStream(new FileInputStream(srcFile));
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(destFile));
byte[] buffer = new byte[1024]; // 每次1024个
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
inputStream.close();
outputStream.close();
System.out.println(System.currentTimeMillis() - begin);
}
}
输出4:
1
小结4:同时使用缓冲流和byte数组,大大加快速度。
4.3 面试金手指:缓冲流 + byte数组
缓冲流和byte数组(字节流byte数组,字符流char数组)都可以加速IO流读写速度,本程序(代码1、代码2、代码3、代码4)中由于stream.txt文本不够大,所以效果不是很明显。实际上,第四种方式,同时使用缓冲流和byte数组,速度是最快的,读者知道就好。
(1)不使用缓冲流不使用byte数组:直接使用文件字节输入和文件字节输出;
(2)使用缓冲流包一层:缓冲流包裹文件字节输入和文件字节输出;
(3)使用byte数组:文件字节读取和文件字节写出都是用byte数组;
(4)同时使用缓冲流和byte数组:缓冲流包一层,然后得到的缓冲流的读入和写出都用byte数组.
五、字符编码
5.1 编码和解码
编码: 把字符串转换为byte数组.
解码: 把byte数组转换为字符串.
一定要保证编码和解码的字符相同,否则乱码.
5.2 代码:编码和解码
5.2.1 字符串编码为byte数组,byte数组解码为字符串
代码1:
package mypackage;
import java.util.Arrays;
//编码: 把字符串转换为byte数组.
//解码: 把byte数组转换为字符串.
//一定要保证编码和解码的字符相同,否则乱码.
public class Test {
public static void main(String[] args) throws Exception {
String mString = "Java程序员就业前景好,薪资高"; // 字符串
byte[] data = mString.getBytes("UTF-8"); // 字符串变为byte数组,编码
// String ret=new String(data,"GBK"); //使用GBK解码乱码,一定要保证编码和解码的字符相同,否则乱码.
// System.out.println(ret);
String ret = new String(data, "UTF-8"); // byte数组变为字符串,解码
System.out.println(ret); // 打印解码
}
}
输出1:
Java程序员就业前景好,薪资高
小结1:一定要保证编码和解码的字符相同,否则乱码.
5.2.2 困境:字符串UTF-8编码为byte数组,byte数组GBK解码为字符串
代码2——困境:
package mypackage1;
//编码: 把字符串转换为byte数组.
//解码: 把byte数组转换为字符串.
//一定要保证编码和解码的字符相同,否则乱码.
public class Test {
public static void main(String[] args) throws Exception {
String mString = "Java程序员就业前景好,薪资高";
byte[] data = mString.getBytes("UTF-8"); // 编码UTF-8
String ret = new String(data, "GBK"); // 解码GBK
}
}
小结2:这里编码UTF-8,但是解码GBK,接下来怎么破,且看代码3.
5.2.3 解决:字符串UTF-8编码为byte数组,byte数组GBK解码为字符串,然后,字符串再次GBK编码一次得到byte数组,最后byte数组UTF-8解码一次得到字符串,打印出来
代码3——破解代码2的困境:
package mypackage1;
//编码: 把字符串转换为byte数组.
//解码: 把byte数组转换为字符串.
//一定要保证编码和解码的字符相同,否则乱码.
public class Test {
public static void main(String[] args) throws Exception {
String mString = "Java程序员就业前景好,薪资高";
byte[] data = mString.getBytes("UTF-8"); // 编码UTF-8
String ret = new String(data, "GBK"); // 解码GBK
data = ret.getBytes("GBK"); // 编码
ret = new String(data, "UTF-8");
System.out.println(ret);
}
}
输出3:
Java程序员就业前景好,薪资高
小结3:所谓的编码解码,无非就是正过来一次,反过来一次罢了,这里编码UTF-8,解码GBK,接下来只能编码GBK,解码UTF-8破解,就是破解方法和前面的编码解码反过来就好了。
5.3 面试金手指:字符编码
字符编码:只要记住两条,
第一,编码和解码的字符要相同,否则乱码;
第二,不管前面编码解码多么复杂,只要反过来操作就可以还原内容,打印出来。
2.1 字符串编码为byte数组,byte数组解码为字符串;
2.2 困境:字符串UTF-8编码为byte数组,byte数组GBK解码为字符串;
2.3 解决:字符串UTF-8编码为byte数组,byte数组GBK解码为字符串,然后,字符串再次GBK编码一次得到byte数组,最后byte数组UTF-8解码一次得到字符串,打印出来。
六、转换流
6.1 概述:转换流,将字节流转换为字符流
JavaIO流——转换流,将字节流转换为字符流。
InputStreamReader:把字节输入流转成字符输入流.
OutputStreamWriter:把字节输出流转成字符输出流.
为什么有字节转字符流,没有字符转字节流?
字节流可以操作一切文件(纯文本文件/二进制文件).字符流是用来操作中文纯文本使用的,本身是对字节流的增强.所以字节流转换为字符流是安全的,字符流转换为字节流不一定安全,所以没有字符流转换
为字节流,个人理解,非官方解释,皮!
解释上图:
字符流是接口,转化流是字符流的非抽象子类,可以实例化对象,但是使用字节流对象作为构造器参数,然后文件字符流和是转换流的子类,可以单独使用
6.2 代码:转换流,将字节流转换为字符流,一段代码,包裹使用,转换流包裹文件字节输入流和文件字节输出流
先读入originStream.txt内容到程序,再将内容写出到targetStream.txt:
package mypackage_输入流输出流;
//转换流:把字节流转成字符流:
//InputStreamReader:把字节输入流转成字符输入流.
//OutputStreamWriter:把字节输出流转成字符输出流.
//为什么有字节转字符流,没有字符转字节流.
// 字节流可以操作一切文件(纯文本文件/二进制文件).
// 字符流是用来操作中文纯文本使用的,本身是对字节流的增强.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
//先读入originStream.txt内容到程序,再将内容写出到targetStream.txt
public class Test {
public static void main(String[] args) throws Exception {
File originStream = new File("originStream.txt");
File targetStream = new File("targetStream.txt");
Reader reader = new InputStreamReader(new FileInputStream(originStream));
Writer writer = new OutputStreamWriter(new FileOutputStream(targetStream));
char[] buffer = new char[1024]; // 字节流用byte[1024]作为缓冲,字符流用char[1024]作为缓冲
// 注意,这个缓冲buffer数组大小是任意的,可以是5,可以是10,可以是1000,可以是1024 仅表示一次读写的字节数或字符数
int len = -1;
while ((len = reader.read(buffer)) != -1) {
writer.write(buffer, 0, len);
}
reader.close();
writer.close();
}
}
输入:
输出1:
小结1:上面的逻辑上没有特别之处,就是输入流+输出流,先读入originStream.txt内容到程序,再将内容写出到targetStream.txt。演示的意义在于加入了转换流,将字符操作变为字节操作,用于完成输入输出。
6.3 面试金手指:转换流,将字节流转换为字符流
Java BIO中的转换流,将字节流转换为字符流,为我们提供了一种字符操作变为字节操作,进而实现输入输出的方式。
代码演示的逻辑上没有特别之处,就是输入流+输出流,先读入originStream.txt内容到程序,再将内容写出到targetStream.txt。演示的意义在于加入了转换流,将字符操作变为字节操作,用于完成输入输出。
七、内存流/数组流/字符串流
7.1 概述:内存流
JavaIO流——内存流,内存流实际是数组流/字符串流
内存流(数组流):适配器模式:
1):字节内存流: ByteArrayInputStream/ByteArrayOutputStream 先将数据先临时存在byte数组中,待会再从byte数组中获取出来.
2):字符内存流: CharArrayReader/CharArrayWriter 先将数据先临时存在char数组中,待会再从char数组中获取出来.
3):字符串流:StringReader/StringWriter 先将数据(字符串)从程序写出到stringwriter中,即临时存储到字符串中,然后将stringwriter中的内容读入程序并打印出来。
7.2 代码:内存流,在内存中呆一会,三段代码,单独使用,ByteArrayXxx CharArrayXxx,StringXxx
7.2.1 字节内存流
package mypackage_字节数组流;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
//内存流(数组流):适配器模式:
// 把数据先临时存在数组中,待会再从数组中获取出来.
// 1):字节内存流: ByteArrayInputStream/ByteArrayOutputStream 数据临时存放到数组中
// 2):字符内存流: CharArrayReader/CharArrayWriter 数据临时存放到数组中
// 3):字符串流:StringReader/StringWriter(把数据临时存储到字符串中)
//字节内存流——字节数组流 内存流实际是数组流,字节内存流和字符内存流都是将数据存放到数组中,字符串流将数据存放到字符串中。
public class Test {
public static void main(String[] args) throws Exception {
// 数据从程序写出到内存(即数组) 内存字节输出流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.write("Java is the best language".getBytes());
byte[] buffer = byteArrayOutputStream.toByteArray();
byteArrayOutputStream.close();
// 数据从内存(即数组)读入到程序 内存字节输入流
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buffer);
byte[] _bytes = new byte[1024];// 字节缓冲为byte数组
int len = -1;
while ((len = byteArrayInputStream.read(_bytes)) != -1) {
System.out.println(new String(_bytes, 0, len));
}
byteArrayInputStream.close();
}
}
输出1:
Java is the best language
小结1:这里演示字节内存流,先将“Java is the best language”从程序写出到内存数组buffer中,然后将buffer数组中的内容读入程序并打印出来。
7.2.2 字符内存流
package mypackage_字符数组流;
import java.io.CharArrayReader;
import java.io.CharArrayWriter;
public class Test {
public static void main(String[] args) throws Exception {
// 数据从程序写出到内存(即数组)
CharArrayWriter charArrayWriter = new CharArrayWriter();
charArrayWriter.write("Java程序员就业前景好,薪资高!一起来学习Java吧!");
char[] buffer = charArrayWriter.toCharArray();
charArrayWriter.close();
// 数据从内存(即数组)读入到程序
CharArrayReader charArrayReader = new CharArrayReader(buffer);
char[] _chars = new char[1024];// 字节缓冲为byte数组
int len = -1;
while ((len = charArrayReader.read(_chars)) != -1) {
System.out.println(new String(_chars, 0, len));
}
charArrayReader.close();
}
}
输出2:
Java程序员就业前景好,薪资高!一起来学习Java吧!
小结2:这里演示字符内存流,先将“Java程序员就业前景好,薪资高!一起来学习Java吧!”从程序写出到内存数组buffer中,然后将buffer数组中的内容读入程序并打印出来。不同的是,字节内存流用byte数组,字符内存流用char数组。
7.2.3 字符串流
package 字符串流;
import java.io.StringReader;
import java.io.StringWriter;
public class Test {
public static void main(String[] args) throws Exception {
// 数据从程序写出到内存(即数组)
StringWriter stringWriter = new StringWriter();
stringWriter.write("Java程序员就业前景好,薪资高!一起来学习Java吧!");
// 数据从内存(即数组)读入到程序
StringReader stringReader = new StringReader(stringWriter.toString());
char[] _chars = new char[1024];// 字节缓冲为byte数组
int len = -1;
while ((len = stringReader.read(_chars)) != -1) {
System.out.println(new String(_chars, 0, len));
}
stringReader.close();
stringWriter.close();
}
}
输出3:
Java程序员就业前景好,薪资高!一起来学习Java吧!
小结3:这里演示字符串流,先将“Java程序员就业前景好,薪资高!一起来学习Java吧!”从程序写出到stringwriter中,然后将stringwriter中的内容读入程序并打印出来。
7.3 面试金手指:内存流/数组流/字符串流
Java内存流分为三种字节内存流、字符内存流、字符串流,都分别有输入流和输出流,
1):字节内存流: ByteArrayInputStream/ByteArrayOutputStream 先将数据先临时存在byte数组中,待会再从byte数组中获取出来.
2):字符内存流: CharArrayReader/CharArrayWriter 先将数据先临时存在char数组中,待会再从char数组中获取出来.
3):字符串流:StringReader/StringWriter 先将数据(字符串)从程序写出到stringwriter中,即临时存储到字符串中,然后将stringwriter中的内容读入程序并打印出来。
八、面试金手指
8.1 文件字节输入流 + 文件字节输出流
Java中,凡是涉及到Java程序的输入输出,一般都逃不过IO流,Java中的IO包括BIO和NIO,其中BIO只要是以四大基流基础的各种各样的阻塞流。BIO的四大基流是:InputStream OutputStream Reader Writer,但是它们都是抽象类,不能实例化对象来完成输入输出操作,直接使用的是它们的子类,本部分中,使用FileInputStream和FileOutputStream就可以完成输入输出。
BIO的四大基流
输入流 | 输出流 | |
---|---|---|
字节流 | 字节输入流InputStream | 字节输出流OutputStream |
字符流 | 字符输入流Reader | 字符输出流Writer |
使用BIO流的四个步骤:
1):创建源或者目标对象(挖井).
输入操作: 把文件中的数据流向到程序中,此时文件是源,程序是目标.
输出操作: 把程序中的数据流向到文件中,此时文件是目标,程序是源.
2):创建IO流对象(水管).
输入操作: 创建输入流对象.
输出操作: 创建输出流对象.
3):具体的IO操作.
输入操作: 输入流对象的read方法.
输出操作: 输出流对象的write方法.
4):关闭资源(勿忘). 一旦资源关闭之后,就不能使用流对象了,否则报错.
输入操作: 输入流对象.close();
输出操作: 输出流对象.close().
关于BIO流的方向:
读进来,写出去。
读进来是指:从文件、网络、压缩包或其他数据源到Java程序;
写出去是指:从Java程序到文件、网络、压缩包或其他输出目标。
8.2 文件字符输入流 + 文件字符输出流
JavaIO流——文件字符流,包括文件字符输入流FileReader,文件字符输出流FileWriter,这两种流联合起来完成最基本的字符操作。
8.3 提高IO效率:缓冲流 + byte数组
缓冲流和byte数组(字节流byte数组,字符流char数组)都可以加速IO流读写速度,本程序(代码1、代码2、代码3、代码4)中由于stream.txt文本不够大,所以效果不是很明显。实际上,第四种方式,同时使用缓冲流和byte数组,速度是最快的,读者知道就好。
(1)不使用缓冲流不使用byte数组:直接使用文件字节输入和文件字节输出;
(2)使用缓冲流包一层:缓冲流包裹文件字节输入和文件字节输出;
(3)使用byte数组:文件字节读取和文件字节写出都是用byte数组;
(4)同时使用缓冲流和byte数组:缓冲流包一层,然后得到的缓冲流的读入和写出都用byte数组.
8.4 编码解码
字符编码:只要记住两条,
第一,编码和解码的字符要相同,否则乱码;
第二,不管前面编码解码多么复杂,只要反过来操作就可以还原内容,打印出来。
2.1 字符串编码为byte数组,byte数组解码为字符串;
2.2 困境:字符串UTF-8编码为byte数组,byte数组GBK解码为字符串;
2.3 解决:字符串UTF-8编码为byte数组,byte数组GBK解码为字符串,然后,字符串再次GBK编码一次得到byte数组,最后byte数组UTF-8解码一次得到字符串,打印出来。
8.5 转换流,字节输入输出转换为字符输入输出
JavaIO流——转换流,将字节流转换为字符流。
InputStreamReader:把字节输入流转成字符输入流.
OutputStreamWriter:把字节输出流转成字符输出流.
为什么有字节转字符流,没有字符转字节流?
字节流可以操作一切文件(纯文本文件/二进制文件).字符流是用来操作中文纯文本使用的,本身是对字节流的增强.所以字节流转换为字符流是安全的,字符流转换为字节流不一定安全,所以没有字符流转换为字节流,个人理解,非官方解释,皮!
字符流是接口,转化流是字符流的非抽象子类,可以实例化对象,但是使用字节流对象作为构造器参数,然后文件字符流和是转换流的子类,可以单独使用
Java BIO中的转换流,将字节流转换为字符流,为我们提供了一种字符操作变为字节操作,进而实现输入输出的方式。
代码演示的逻辑上没有特别之处,就是输入流+输出流,先读入originStream.txt内容到程序,再将内容写出到targetStream.txt。演示的意义在于加入了转换流,将字符操作变为字节操作,用于完成输入输出。
8.6 内存流,让数据在内存中呆一会,内存字节输入输出 + 内存字符输入输出 + 字符串输入输出
Java内存流就是让数据在内存中呆一会,分为三种字节内存流、字符内存流、字符串流,都分别有输入流和输出流,
1):字节内存流: ByteArrayInputStream/ByteArrayOutputStream 先将数据先临时存在byte数组中,待会再从byte数组中获取出来.
2):字符内存流: CharArrayReader/CharArrayWriter 先将数据先临时存在char数组中,待会再从char数组中获取出来.
3):字符串流:StringReader/StringWriter 先将数据(字符串)从程序写出到stringwriter中,即临时存储到字符串中,然后将stringwriter中的内容读入程序并打印出来。
九、尾声
IO,对象传输的基石(一),完成了。
天天打码,天天进步!!!