InputStream:(字节流)
public abstract class InputStream:该抽象类是所有的类 表示字节输入流的父类
构造:
//FileInputStream(String name):通过字符串找路径(隐含 着创建了一个File对象)
InputStream fis = new FileInputStream("b.txt");
注:直接就把文件的绝对路径写下去就行,直接创建流对象
读取数据:
1.int read():从此输入流中读取一个数据字节。
举例:
while(( by = fis.read()) != -1) {
System.out.print((char)by); //因为返回的是 一个字节数的整数,所以我们需要转换成字符 变 成我们看的懂的东东西
}
注:
1.字节流把数据转码为字节数,编码后存储起来。因此返回 的是byte类型数据,我们需要转化为char类型(码表)
2.read()一次读取一个字节的数据,如果没有读取到就返 回-1
3.记得关闭流 .close()
4.目前只能读取英文字母(AScll码内),不能读取中文
2.int read(byte[] b):一次读取一个字节数组
//创建输入流
InputStream fis = new FileInputStream("b.txt");
//String(byte[] value, int offset, int count)
//根据指定数组,提取其内容返回一个新的String类型 的数据,从指定位置开始到指定位置的读取
System.out.println(new String(bys,0,len));
此句话把输出的内容转化为字符串
byte[] bys = new byte[1024]; //通常默认为 1024
int len = 0; //计算长度,并做为循环条件
while((len = fis.read(bys)) != -1) {
System.out.println(new String(bys,0,len));//一次读取1024个字节,如果没 有就返回-1,
}
注:
在写入数据时,最好把范围规定在[0,len],以防写入 过多的空格
OutputStream:(字节流)
这个OutputStream是一个抽象类,我们不能实例 根据抽象 类如何实例 我们之前学过,使用多态的方式
所以我们需要找他的子类:FileOutputStream
1.eOutputStream的构造方法:
FileOutputStream(File file): 创建一个向指定 File 对象 表示的文件中写入数据的文件输出流。
FileOutputStream(String name):创建一个向具有指定名称 的文件中写入数据的输出文件流。
注:
io流负责输入输出,但是依附于文件,因此需要找到那个 文 件才能进行输入输出吧,因此需要创建一个文件对象(File 对象)。可以显性创建一个File对象,也可以直接用字符 串,源码会帮我们在自动创建一个File对象
字节流输出的步骤:
a.创建输出流
b.写出数据
c.资源释放(一定要记得) //.close()避免很多问题
/方式一
// File file = new File("demo.txt");
// OutputStream fos = new fileOutputStream(file);
//方式二
// OutputStream fos = new fleOutputStream(new File("a.txt"));
关闭流
/*
所有的流一定要记得关闭
否则这个流会在内存中占用空间
关闭流其实不是立即关闭,只是通知系统这个资 被释放。
可以在合适的时候去进行回收
*/
// fos.close();
2.写入数据
void write(byte[] b):写一个字节数组的数据
void write(byte[] b, int off, int len):写一个字节数组 的数据,从指定位置开始到指定位置结束
void write(int b):写一个int类型的数据
举例:
FileOutputStream fos = new FileOutputStream("a.txt");
// fos.write(97);//二进制 -- 转码 -- 找 到97对应的字符(a),而不 是97的整数
// fos.write(98);
byte[] bys = {97,98,99,100,101,102,103};
fos.write(bys);
fos.write(bys, 1, 4);//bcde
fos.close();
注:
1. 如果我们需要使用输出流进行换行的操作,你直接写 println是无效的,因为这个跟写出本质上是没有关系
所以,我们可以使用\n的转义字符明确的告知需要进行换 行但是,我们用过高级记事本发现确实换行了,但是记事 本确没有进行换行针对这个问题,我们需要了解一些。
每一个操作系统对于转义字符的识别是不一致的,而大多 高级记事本是能够自己进行转义和识别
Windows:\r\n
linux:\n
Mac os:\n
而Windows自带的记事本是基于Windows平台来写的,所以他 只能够识别\r\n是换行的意思
举例:
OutputStream fos = new FileOutputStream("b.txt");
for (int i = 1; i < 6; i++) {
fos.write(("toobug"+i+"\r\n").getBytes());
//字符串转为一般数组
//参数如果有true,就代表写入位置为文件末尾处开始,而不是文件开始处(追加的写法)
OutputStream fos2 = new FileOutputStream("b.txt",true); //是在创建io流对象时 写true
for (int i = 1; i < 6; i++) {
fos2.write(("java"+i+"\r\n").getBytes());
//必须转化为字节才能进行写入
//fos.write("\n".getBytes());
}
ileInputStream fis = new FileInputStream("F:\\seehope_edu\\Java_20180420\\javase_day16\\课堂笔记\\img\\1.png");
FileOutputStream fos = new FileOutputStream("F:\\seehope_edu\\Java_20180420\\javase_day16\\课堂笔记\\img\\2.png");
int by = 0;
while((by = fis.read())!=-1) {
fos.write(by);
} //读一个 写一个 避免多出 少了 一个字节(很 慢)
byte[] bys = new byte[2048];
int len = 0;//计数,并做循环条件
while((len = fis.read(bys))!= -1) {//28 = -1
fos.write(bys);//2048(有数据) 0 - 28
}
long e = System.currentTimeMillis();
System.out.println("共计:"+(e-s)+"毫秒");
注:
1.如果字符数组长度不够,len返回数组最大数;
如果字符数组够长,返回实际装载数据的长度;
最后一次肯定是获取不到字符(结尾)返回1
实际长度: 帮助写入数据 -1: 循环条件
2.如果是用数组读取,系统会开一个缓冲区,并一次读取 1024个字节数,速度很快(基本去到300多兆每秒,下一个真 正的缓冲区更快,可以去到400多兆,跟固态有的一拼,不会 超过固态,不可能超过最大物理性能,不然无法进行写入写 出了)
buffered_IO:(带缓冲区的字节流)
我们上午通过创建一个数组的方式来读取数据确实比之前一 个字节一个字节的读,效率很明显要快很多。
既然,带上缓存区的数据读取效率这么高,那么在Java设计 之初,其实已经为我们设计了一个带缓冲区的输入和输出流
这种类也就是我们俗称的:缓冲区流
缓冲区输入流:BufferedInputStream
缓冲区输出流:BufferedOutputSteam
注:
之前的创建数组是模拟缓冲区,而这个是正统的缓冲区
BufferedOutputSteam构造方法:
BufferedOutputStream(OutputStream out):创建一个缓冲区 输出流
BufferedOutputStream(OutputStream out, int size):创建 一个缓冲区输出流,并且指定缓冲区大小(一般不用,有默认 的缓冲区)
注:
1.BufferedOutputStream不是虚类,可以直接new一个对象
2.BufferedOutputStream没有具体功能,只是开一个缓冲 区,具体功能只能通过FileOutputStream对象来实现
3.OutStream不能创建对象, 必须用FileOutputStream
4.OutStream是所有输入类的父类(多态)
5.输出时记得要.flush()刷新,然后再推出
Test:
四种流的对比:
要求,将一个大小为41M的视频进行拷贝来对比速度
method01(一个个读):基本的字节流 耗时:2分钟左右
method2(开数组);带数组的字节流 耗时:0.3秒
method03(一个个读):字节缓冲区流的字节读取 1.5秒
method04():带数组的缓冲区字节流:0.1秒
InputStreamReader:
字节流,无论是输出,输入都只能以字节的方式。现在介绍 一种以字符形式输出,输入的方式(只是字符转换流)
字节流读取中文出现的问题
while((by = fis.read())!=-1) {
//????¤?????¤??°??????????
System.out.print((char)by);
}*/
byte [] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys))!= -1) {
//浠婂ぉ鐨勫ぉ姘旂壒鍒ソ
System.out.println(new String(bys,0,len,"utf-8"));
}
//读取笔记本的中文时,输出一堆看不懂的
InputStreamReader(InputStream in):使用默认的字符集编 码来进行内容的读取
InputStreamReader(InputStream in, Charset cs):使用指 定的字符集编码进行内容读取
1.eclipse默认的是GBK格式,记事本的不一定,不同要转
3.InputStreamReader不是虚类,可以new自己
4.InputStreamReader也只是提供解码的方法,具体输入输出 还是需要FileOutputStream来完成,而FileOutputStream又 需要File对象来找到指定的文件。(一级套一级)
5.InputStreamReader只是以字符来读取,但是read返回的是 int类型(某种编码,用char转换后可输出。如果是同一种编 码格式,会输出我们想要的,如果不是就会输出不同)
6.只是针对文字,如果是字母,都一样,不存在编码转换
7.在输入流内,解码类型一定要与java文件的默认类型相 同,因为是想要输入到我们的程序中
注:
UTF-8 格式 可以兼容任何格式,但是eclipse默认为 “GBK”,GBK不能解码UTF-8,因此在输入流中,要以编译器 为准,这样子编译器才知道进来的是什么。当然如果文本文 件是UTF-8就会出错,因此要把文件转为ANSI就不会有错
字符转换流:
OutputStreamWriter:
void write(char[] cbuf, int off, int len):写入字 符数组的某一部分。
void write(int c):写入单个字符。
void write(String str, int off, int len):写入一 个字符串的一部分
举例:
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));
osw.write(97);//自动转为字符
osw.write('a');
osw.flush();//刷新流,可能写入的数据不会被及时 刷新,所以不会有显示 一般在写入数据之后,记得刷新
char [] ch = {'h','a','b'};
osw.write(ch);
osw.flush();
osw.write("我爱橘梨纱");
osw.flush();
osw.close();
注:
与字节流不同的是,它可以直接写入字符与字符串,而字节 流必须写入byte类型,然后它才会去找表把其变为字符
String(byte[] bytes, String charsetName):通过制定的字 符集编码解码字节数组
byte[] getBytes(String charsetName):使用指定的字符集 编码生成字节数组
编码:把看的懂的文字变成乱码形式(看不懂的)
String -- byte[]
解码:看不懂的东西解码成看的东西
byte[] -- String
在解码的过程当中,一定要注意一个问题,就是两个码的字 符集编码平台是否能够兼容,
如果不能够兼容就需要手动来声明解码的平台应该是哪一种
String s = "龙哥";
byte [] bys = s.getBytes();
//编码的过程
System.out.println(Arrays.toString(bys));
//解码的过程
// String str = new String(bys);
String str = new String(bys,"GBK");
System.out.println(str);
注:
字符串最后变为二进制存储起来
BufferedReader br = new BufferedReader(new FileReader("InputStreamDemo01.java"));
//int read() 读取单个字符
// int a = br.read();
// System.out.println(a);
//br.readLine(); 读取一整行
// String line = br.readLine();
// System.out.println(line);
String line = null;
// while ((line = br.readLine())!= null) {
// System.out.println(line);
// }
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
while ((line = br.readLine())!= null) {
bw.write(line);//写入数据
bw.newLine();//执行新行
bw.flush();//刷新缓冲区
}
总结:
1.IO流分类:
流向:
输出流:写出数据
输入流:读取数据
类型:
字节:
输出流:写出数据 OutputStream
输入流:读取数据 InputStream
字符:
输出流:写出数据 Writer
输入流:读取数据 Reader
2.看不懂的(图片,视频)就用字节流
看得懂的(文本文件,中文,英文)就用字符流
3.转义字符:不是真的字符,是一个功能
4.要养成关闭流的习惯(.close()),先创建的后关闭
如果是输出流要养成.flush(更新的习惯)。