黑马软件工程师-java基础-深入解析IO流,附相关面试题
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
IO流(掌握)
(1)IO用于在设备间进行数据传输的操作(2)分类:
A:流向
输入流 读入数据 InputStream
输出流 写出数据OutputStream
补充:这里的流向是相对于java程序来说的,从硬盘读取数据就是在往java上读入,输出到硬盘就是在写出。
B:数据类型
字节流
字节输入流 读入数据 InputStream
字节输出流 写出数据OutputStream
字符流
字符输入流 读入数据Reader
字符输出流 写出数据Writer
注意:
a:如果我们没有明确说明按照什么分,默认按照数据类型分。
b:除非文件用windows自带的记事本打开我们能够读懂,才采用字符流,否则建议使用字节流.
IO流分类
字节流:
InputStream
FileInputStream
BufferedInputStream
OutputStream
FileOutputStream
BufferedOutputStream
字符流:
Reader
FileReader
BufferedReader
Writer
FileWriter
BufferedWriter
(3)FileOutputStream写出数据
A:操作步骤
a:创建字节输出流对象
b:调用write()方法
c:释放资源
B:代码体现:
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write("hello".getBytes());
fos.close();//释放资源是为了关闭输出流,并释放与此流相关的所有系统资源
C:要注意的问题?
a:创建字节输出流对象做了几件事情?
1,调用系统功能去创建文件
2,创建输出流对象
3,把输出流对象指向这个文件
b:为什么要close()?
1,关闭输出流,让流对象作为垃圾回收
2,通知系统去释放相关资源
c:如何实现数据的追加写入?
FileOutputStream fos = new FileOutputStream("fos.txt",true);
//这里的参数true,代表再写数据是可以从结尾处追加,如果没有true说明是从开头写出的。
(4)FileInputStream读取数据
A:操作步骤
a:创建字节输入流对象
b:调用read()方法
c:释放资源
B:代码体现:
FileInputStream fis = new FileInputStream("fos.txt");
//读的文件必须存在,不存在就会报错
//方式1
int by = 0;
while((by=fis.read())!=-1) {
System.out.print((char)by);
}
//方式2
byte[] bys = new byte[1024];//每次读取1024个字节
int len = 0;
while((len=fis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
//获取每次读取的实际有用的字节后,转换成字符串输出到控制台
}
fis.close();
(5)案例:2种实现
A:复制文本文件
//封装读入和写出对象
FileInputStream fis=new FileInputStream("c:\\a.txt");
FileOutputStream fos=new FileOutputStream("d:\\b.txt");
// //复制数据方式一
// int by=0;
// while((by=fis.read())!=-1){
// fos.write(by);
// }
//复制方式二,通常使用方式二,因为方式二效率高。
byte[] bys=new byte[1024];
int len=0;
while((len=fis.read(bys))!=-1){
fos.write(bys, 0, len);
}
//关闭资源
fis.close();
fos.close();
B:复制视频
//创建输入输出流对象
FileInputStream fis=new FileInputStream("E:\\今年我们二十三四岁.mp4");
FileOutputStream fos=new FileOutputStream("D:\\二十三四岁.mp4");
//复制
byte[] bys=new byte[1024];
int len=0;
while((len=fis.read(bys))!=-1){
fos.write(bys, 0, len);
}
//关闭资源
fis.close();
fos.close();
(6):复制文本文件,复制视频的4种实现
1,基本字节流的单个读写。
2,基本字节流一次读写一个字节数组
3,高效字节流一次读写一个字节
4,高效字节流一次读写一个字节数组。
补充:计算机是如何识别什么时候该把两个字节转换为一个中文呢?
在计算机中中文的存储是两个字节,
当第一个字节为负数是,就会和后面的一个字节拼成一个中文。
(7)字节缓冲区流(缓冲区类---高效类)
A:BufferedOutputStream
BufferedOutputStream(OutputStream out)这里传入的是一个字节流对象
B:BufferedInputStream
BufferedInputStream(InputStream in)这里传入的是一个字节流对象
3:缓冲流实现复制文本文档
面试题:如把c:\\a.txt中的内容复制到D:\\copy.txt中
A:高效字节流来实现
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("c:\\a.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\copy.txt"));
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
bos.close();
bis.close();
B:高效字符流来实现。
//创建缓冲区读写对象
BufferedReader bfr=new BufferedReader(new FileReader("c:\\a.txt"));
BufferedWriter bfw=new BufferedWriter(new FileWriter("D:\\copy.txt"));
//复制
char[] chs=new char[1024];
int len=0;
while((len=bfr.read(chs))!=-1){
bfw.write(chs, 0, len);
}
//关闭资源
bfr.close();
bfw.close();
4,:字符流(掌握)
(1)字节流操作中文数据不是特别的方便,所以就出现了转换流。
转换流的作用就是把字节流转换字符流来使用。
(2)转换流其实是一个字符流
字符流 = 字节流 + 编码表
(3)编码表
A:就是由字符和对应的数值组成的一张表
B:常见的编码表
ASCII:单个字节,适合表示英文和数字。
ISO-8859-1 拉丁码表
GB2312中文编码表
GBK 中文编码表的升级
GB18030:GBK的替代版本
UTF-8:国际标准码,最多由三个字节表示一个字符
能用一个就用一个(兼容ASCII)
一个表示不了,用两个,两个表示不了才用三个。
C:字符串中的编码问题
编码
String -- byte[]
byte[] getBytes(String charsetName);使用指定的字符集合把字符串编码为字节数组。
解码
byte[] -- String
String(byte[] bytes,String charsetName):通过指定的字符集解码字节数组
例题:
//编码
String s="中文";
byte[] bys=s.getBytes("utf-8");
System.out.println("编码后:"+Arrays.toString(bys));
//解码
String ss=new String(bys,"utf-8");
System.out.println(ss);
(4)IO流中的编码问题
A:OutputStreamWriter的构造
OutputStreamWriter(OutputStream os):默认编码把字节流转成字符流,GBK
OutputStreamWriter(OutputStream os,String charsetName):指定编码把字节流转成字符流。
B:InputStreamReader的构造
InputStreamReader(InputStream is):默认编码,GBK
InputStreamReader(InputStream is,String charsetName):指定编码
C:OutputStreamWriter(字符流)的writer方法:写出数据的5中方式
1,void writer(int c):写一个字符
2,void writer(char[] chs):写一个字符数组
3,void writer(char[] chs,int off,int len):写一个字符数组指定的一部分
4,void writer(String str):写一个字符串
5,void writer(String str,int off,int len):写一个字符串指定的一部分,从off开始往后读len个
C:编码问题其实很简单
编码只要一致即可
D:面试题:close()和flush()的区别?
close();关闭流对象,但是先刷新一次缓冲区,关闭后,流对象就没法继续使用了。
flush():仅仅刷新缓冲区,刷新之后,流对象还可以使用。
(5)字符流
Reader
|--InputStreamReader(转换字符流)
|--FileReader
|--BufferedReader
Writer
|--OutputStreamWriter(转换字符流)
|--FileWriter
|--BufferedWriter
(6)复制文本文件(5种方式)
例题:把a.txt中的内容复制到b.txt中
1:用字符转换流InputStreamReader和OutputStreamWriter
//封装数据源
InputStreamReader isr=new InputStreamReader(new FileInputStream("a.txt") );
//封装目的地
OutputStreamWriter isw=new OutputStreamWriter(new FileOutputStream("b.txt"));
//复制方式一
/*int ch=0;
while((ch=isr.read())!=-1){
isw.write((char)ch);
}*/
//方式二:数组读写
char[] chs=new char[1024];
int len=0;
while((len=isr.read(chs))!=-1){
isw.write(chs, 0, len);
}
//关闭资源
isr.close();
isw.close();
2:转换流的名字较长,而我们常见的操作都是按照本地默认的编码是实现的,所以,为了简化我们的书写,转换流提供了对应的子类,
FileWriter和FileReader。
//封装数据源
FileReader fw=new FileReader("a.txt");
//封装目的地
FileWriter fw=new FileWriter("b.txt");
//复制,数组读写
char[] chs=new char[1024];
int len=0;
while((len=fr.read(chs))!=-1){
fw.write(chs, 0, len);
}
//关闭资源
fr.close();
fw.close();
补充:
//InputStreamReader isr=new InputStreamReader(new FileInputStream("a.txt"));
//OutputStreamWriter isw=new OutputStreamWriter(new FileOutputStream("b.txt"));
/*上面的代码和下面的代码时等效的*/
FileReader isr=new FileReader("a.txt");
FileWriter isw=new FileWriter("b.txt");
(五):字符缓冲流实现复制
一:高效字符流来复制
//创建缓冲区读写对象
BufferedReader bfr=new BufferedReader(new FileReader("c:\\a.txt"));
BufferedWriter bfw=new BufferedWriter(new FileWriter("D:\\copy.txt"));
//复制
char[] chs=new char[1024];
int len=0;
while((len=bfr.read(chs))!=-1){
bfw.write(chs, 0, len);
}
//关闭资源
bfr.close();
bfw.close();
二:缓冲流特有方法来复制
//创建缓冲流对象
BufferedReader br=new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw=new BufferedWriter(new FileWriter("copy.txt"));
//每次读写一行来复制
String str=null;
while((str=br.readLine())!=null){
bw.write(str);//写一行字符串
bw.newLine();
bw.flush();
}
//关闭资源
br.close();
bw.close();
补充:通常复制文本文件时用这种缓冲流特有方法来复制。
String readLine();一次读取一行数据
void newLine();写换行符
(六):IO流小结(掌握)
IO流
|--字节流
|--字节输入流
InputStream
int read():一次读取一个字节
int read(byte[] bys):一次读取一个字节数组
|--FileInputStream
|--BufferedInputStream
|--字节输出流
OutputStream
void write(int by):一次写一个字节
void write(byte[] bys,int index,int len):一次写一个字节数组的一部分
|--FileOutputStream
|--BufferedOutputStream
|--字符流
|--字符输入流
Reader
int read():一次读取一个字符
int read(char[] chs):一次读取一个字符数组
|--InputStreamReader
|--FileReader
|--BufferedReader
String readLine():一次读取一个字符串
|--字符输出流
Writer
void write(int ch):一次写一个字符
void write(char[] chs,int index,int len):一次写一个字符数组的一部分
|--OutputStreamWriter
|--FileWriter
|--BufferedWriter
void newLine():写一个换行符
void write(String line):一次写一行字符串
图片解析
补充:除了用Windows记事本打开能读懂的数据用字符流以外,其他的都用字节流来复制。
字节流复制数据:4种方式(基本的两种,高效缓冲流的两种)
字符流复制数据:5种方式(基本的两种,高效缓冲流的两种,缓冲流特有方法一种)
4:案例(理解 练习一遍)
A:复制文本文件 5种方式(掌握):代码如下。
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; /*A:复制文本文件 5种方式(掌握) */ public class Demo1 { public static void main(String[] args) throws IOException { //基本字节流的两种 String s1="a.txt"; String copy="b.txt"; bufferCopy5(s1,copy); } //基本字符流的每次读写一个字符 private static void basicCopy1(String s1, String copy) throws IOException { InputStreamReader isr=new InputStreamReader(new FileInputStream(s1)); OutputStreamWriter isw=new OutputStreamWriter(new FileOutputStream(copy)); int ch=0; while((ch=isr.read())!=-1){ isw.write(ch); } isr.close(); isw.close(); } //基本字符流的每次读写一个字符数组 private static void basicCopy2(String s1, String copy) throws IOException { InputStreamReader isr=new InputStreamReader(new FileInputStream(s1)); OutputStreamWriter isw=new OutputStreamWriter(new FileOutputStream(copy)); //上面的代码和线的代码时等效的,上面的代码可以写成下面 // FileReader isr=new FileReader(s1); // FileWriter isw=new FileWriter(copy); char[] chs=new char[1024]; int len=0; while((len=isr.read(chs))!=-1){ isw.write(chs,0,len); } isr.close(); isw.close(); } //缓冲流的高效每次读写一个字符数组 private static void bufferCopy3(String s1, String copy) throws IOException { BufferedReader isr=new BufferedReader(new FileReader(s1)); BufferedWriter isw=new BufferedWriter(new FileWriter(copy)); char[] chs=new char[1024]; int len=0; while((len=isr.read(chs))!=-1){ isw.write(chs,0,len); } isr.close(); isw.close(); } //缓冲字符流的每次读写一个字符 private static void bufferCopy4(String s1, String copy) throws IOException { BufferedReader isr=new BufferedReader(new FileReader(s1)); BufferedWriter isw=new BufferedWriter(new FileWriter(copy)); int ch=0; while((ch=isr.read())!=-1){ isw.write(ch); } isr.close(); isw.close(); } //缓冲字符流的的特有方法每次读写一行字符 private static void bufferCopy5(String s1, String copy) throws IOException { BufferedReader isr=new BufferedReader(new FileReader(s1)); BufferedWriter isw=new BufferedWriter(new FileWriter(copy)); String s=null; while((s=isr.readLine())!=null){ isw.write(s); isw.newLine(); isw.flush(); } isr.close(); isw.close(); } }
B:复制图片(二进制流数据) 4种方式(掌握):代码在如下
package cn.itcast_test; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /*B:复制图片(二进制流数据) 4种方式(掌握): * 通常使用第四种方式*/ public class Demo2 { public static void main(String[] args) throws IOException { String s1="a.jpg"; String s2="b.jpg"; copy4(s1,s2); } //基本字节流每次读写一个字节 private static void copy1(String s1, String s2) throws IOException { //封装读写对象 FileInputStream fis=new FileInputStream(s1); FileOutputStream fos=new FileOutputStream(s2); //复制 int by=0; while((by=fis.read())!=-1){ fos.write(by); } //关闭资源 fis.close(); fos.close(); } //基本字节流每次读写一个字节数组 private static void copy2(String s1, String s2) throws IOException { //封装读写对象 FileInputStream fis=new FileInputStream(s1); FileOutputStream fos=new FileOutputStream(s2); //复制 byte[] bys=new byte[1024]; int len=0; while((len=fis.read(bys))!=-1){ fos.write(bys, 0, len); } //关闭资源 fis.close(); fos.close(); } //缓冲区字节流每次读写一个字节 private static void copy3(String s1, String s2) throws IOException { //封装读写对象 BufferedInputStream bis=new BufferedInputStream(new FileInputStream(s1)); BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(s2)); //复制 int len=0; while((len=bis.read())!=-1){ bos.write(len); } //关闭资源 bis.close(); bos.close(); } //缓冲区字节流每次读写一个字节数组 private static void copy4(String s1, String s2) throws IOException { //封装读写对象 BufferedInputStream bis=new BufferedInputStream(new FileInputStream(s1)); BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(s2)); //复制 byte[] bys=new byte[1024]; int len=0; while((len=bis.read(bys))!=-1){ bos.write(bys,0,len); } //关闭资源 bis.close(); bos.close(); } }