IO流 数据流; 设备包括硬盘和内存;
Java对数据的操作是通过流的方式;
处理数据流的对象都在IO包中;
流按操作数据分为两种:字节流与字符流;
按流向分为输入流和输出流;
早期IO包里出现的都是字节流,无论什么数据都是体现为字节形式即二进制的,称为字节流;字节流可以把所有的数据都可以搞定;但有一个数据是文本数据是比较常见的,为了方便处理,单独分为字符流;
GBK码表;ASCII码
国际标准化组织,
国际标准码表unicode表;这个表里,无论什么字符都用两个字节表示;utf-8码表等;
unicode的所有字符都用两个字节表示;16个二进制位;utf-8对unicode进行了优化;
字符流的出现可以在内部融合各种编码表;可以自定义指定编码表进行解析,避免使用字节流时出现码表不正确而成乱码,这样在处理文字字符时就变得方便;其他的数据都用字节流解决;
字符流继字节流;
IO流的常用基类(2个两类): 数据处理就两动作,读和写;
字节流的抽象基类:InPutStream(读),OutPutStream(写)
(记忆,短的读read,长的写write)
字符流的抽象积累:Reader,Writer
这四个基类都是抽象的,需要被子类分别实现;
IO流其实就是围绕读写去展开的;
一、字符流
(一)Writer;
protected 修饰构造方法,说明是给子类使用的,只有子类才能使用该方法;
学习体系的方法是,先看顶层,用底层
根据基类Writer的方法中append()方法可以得知,该方法底层数据操作应该是使用的StringBuilder或者StringBuffer,因为他们方法一样,而Writer就是调用的这两个类的方法,其实这也可以理解得明白,StringBuilder类本来就是描述字符串缓冲区的,所以用在这里再适合不过了;
既然IO流是用于操作数据的,那么数据的最常见的体现形式就是文件;
那么先以操作文件为主来演示;
1、需求:在硬盘上,创建文件,并写入一些文字数据;即操作数据;
找到一个子类后,只需要看构造方法就可以了,因为他的方法父类里都有了;
找到一个专门用于操作文件的Writer子类对象,FileWriter,后缀名为父类名,前缀名是该流对象的功能;
继承关系是Writer——OutputStreamWriter——FileWriter
该FileWriter流对象一被初始化,就必须要有被操作文件存在可以进行写入操作,所以这个文件里没有空参构造方法;
写入步骤:
File Writer = new FileWriter(地址文件名);
(1)创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件;
而且该文件会被创建到指定目录下,如果该目录下已有同名文件,将被覆盖;
new这个对象的目的就是在明确数据要存放的目的地;
一个完整的文件名,必须包含三部分,地址+标题+格式;不写地址就是默认当前路径;
注意,新建FileWriter会抛出IO异常;
(2)调用Write方法,是将字符串写入到流中,并没有直接写到目的地文件中;
(3)flush()方法;
可以通过刷新流当中的缓冲数据,将缓冲中的数据直接清空一次,然后把其刷到目的文件中;
(4)close()方法,关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据,将数据刷到目的地中,和flush的区别是,flush刷新后,流可以继续使用,close刷新后,会将流直接关闭,而不能在往内写入了,否则会报错;
其实,Java是不能写数据的,因为不同操作系统写入操作是不一样的,这个写入操作不是java自身在写入,而是调用的底层操作系统的流资源在进行写入;所以最后一定要有一个动作就是,关闭底层资源的调用动作以释放资源;
在IO体系上 IO异常是最常见的异常,一定要做处理动作;很多动作方法都有异常发生;
其实FileWriter构造函数中的是调用的操作系统底层的创建文件的方式创建了一个文件;
包括该类的所有的方法都是调用的底层操作系统的相关操作进行的;因为Java是没有这个能力的,它还要跨平台,所以只能够调用底层的操作来做;
2、IO异常的处理方式:throws肯定是不合适的;
凡是和设备上的数据发生关系和处理的,都会throw IO异常,无论读写和创建,因为都是调用底层资源来进行操作的;
写入数据都是写入到流里面了;流里面有内部缓冲;
(流里面的是有缓冲的,是基于字节流的;)
对于IO流的处理应该是直接抛RuntimeException(“异常描述”);
finally,一般的操作一般都是关闭资源,解锁等一定要被执行的应用;因此流的关闭操作放在finally块当中;
目录分隔符要注意写两个,因为是转义字符;
finally里面一定要对于if(fw!=null)的流进行关闭;要分别去关;不要搞与符号;
一个单独代码块的元素,其作用域只能是在本代码块当中,不能在别的代码块当中访问;
可以在外面建立引用filewrite fw=null;,这样在最后发finally块当中才能被访问得了fw声明,在代码块当中赋值即可;
3、对已有文件内容的数据进行续写:
传递true参数,代表不覆盖已有文件,并在已有文件的末尾处进行数据处理,
如果文件不存在就创建,存在就不创建了;(如果输入false是不是在开头写入?)
FileWriter(String fileName, boolean append)
创建一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行属性数据续写;
4、在window时 \n 和\r一起才表示换行,如果文本中不显示,会显示一个黑块;先r再n;
只有lincx\n才表示换行;\r表示回车,\n表示换行;只有这两个才表示成功换行;
(二)、Reader
Reader 也是抽象类;
这个类里面的close()不刷新;虽不刷新,但也要关闭;
读不用刷新,写的时候是需要刷新的,因为写要把流里面的东西保存下来;
流对象有一个特点就是基本都是对应的,有读的就肯定有写的;但不是全都这样;
流是已经把内容直接读出来了,所以不需要刷新,而写是要刷新的,因为他要写进去,然后还要按编码转换,中间肯定有一个缓冲的过程;
字符流是百分百都是有编码的;
步骤
(1)创建一个文件读取流对象,和指定名称的文件相关联,要保证该文件已经存在的,如果不存在,会发生异常 FileNotFoundException;
(2)调用读取流对象的read方法;
方法read();一次读一个字符,而且会自动往下读;当读到没有内容时,就返回-1;
Java在读文件的时候也是调用底层操作系统中的读取文件的方法来读文件内容的,Java本身是读不了的文件的;
在硬盘上,每一个数据文件读完之后,后面都有一个结束的标示;
(3)read(char[] cbuf) 通过字符数组进行读取;返回读取字符个数;
就要先定义一个字符数组,用于存储读到的字符;该read(char[])返回的是读到的字符个数;
(4)关闭资源,虽然不影响读取,但是关闭动作一定要有;
注意,IO流实际是调取了底层操作系统来完成数据操作处理的,读有一个特点就是只要没有关闭流,它读到哪里就停到哪里,下次不会从开头重新开始;其实硬盘就是磁头在读写,所以读到哪里就停到哪里了;
用数组读其实有一个特点就是他是用读入流当中的内容覆盖数组中原有的内容;
每一次read()都是从数组的0脚标开始读起,就和重复读一样,但是如果数组装满,就会停止读入;
如果数组的空间装满,则read动作将停止,表示该read语句执行结束,磁头停止在所读的最后一个字符的后面,直到关闭该流;
一般的通常情况下,数组的长度定位1024的整数倍;1024字节就是1kb,一个字符是两个字节;
用数组先缓冲一下,然后再读出来;比读一个打一个的更快捷方便;
练习:读取一个java文件,并打印在控制台上;
字符流,专门处理文本数据的对象;
注意,如果你的文档里面自己有换行,那么打印的时候他肯定也是打印换行的,因为有一个换行符在那里,所以连续打印最好;
练习2:将c盘的一个文本文件复制到d盘。
复制原理,其实就是将c盘下的文件数据存储到d盘的一个文件中,
步骤:
在d盘创建一个文件,用于存储c盘文件中的数据;
定义读取流和c盘文件关联;
通过不断的读写完成数据存储,
关闭资源;
两种方法;第一种读一个写一个,第二种,数组;
读写操作都进入流对象了;
复制动作要做重点掌握;
流对象的概念;其实流的底层都是调用的windows的底层资源的;
第二种方式:用数组临时存一下,提高读写性能;
局部变量定义时,最好养成一个习惯就是初始化一下,因为没赋值前就不能调用的;
把读到的内容写到流里面去,即流的缓冲区中;
字符流体系当中的缓冲技术;
读写失败之后,专业异常的处理动作应该是throwRuntimeException(“读写失败”)
读写完毕后,在finally块中,关闭两个流资源;
(三)字符流的缓冲区:
如何提高程序的读写效率呢?
水滴石穿坐食山空
其实很多软件里面都加入了自己的缓冲技术;先存在一个内存当中,读到一定内容后,再一次性写入到硬盘中;这样读写性能比较就会好些,磁头没有必要来回切换,提高读写速度;
缓冲区的出现提高了对数据的读写效率;
为提高读写效率,字符流也提供了相对应的缓冲区对象
具备缓冲技术的字符流对应的有BufferedWriter和BufferReader;缓冲区要结合流才可以使用;在流的基础上对流的功能进行了增强;
具备缓冲技术的字符流;
1、BufferedWriter
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
(磁头没有必要来回切换),这个缓冲区就是在比较方便的地方存入;比直接在目的文件里读入写出会性能更高,具体为什么,再研究;只知道,缓冲区是在内存里,比直接放在硬盘中读写速度会更快;
缓冲区是为了提高流的读写效率而出现,因此在创建缓冲区之前就应该先有流对象;即初始化创造对象时就要先有流对象,故没有空参的构造函数,就像蓄水池一样,建立之前必须要有水才流行;
步骤:
(1)创建一个字符写入流对象;
一般开发时都要开缓冲区,这样对性能就会有所提高;
(2)为了提高字符写入流效率,加入了缓冲技术,只要将需要被提高效率的流对象作为参数传递给缓冲对象的构造函数即可;(其实缓冲区最根本原理就是底层原理就是加了一个数组;)
把缓冲区与流对象相关联后就可以直接用缓冲区的操作方法了;而不再用流对象去操作了;
注意,只要用到缓冲区,就要记得刷新;flush();//字节流不需要刷新;
缓冲区的存在是为了提高效率的,而这个缓冲区的底层调用的就是对应的流对象在进行操作,其实操作缓冲区就在操作的流对象,只是定义了一些更多更好的方法在里面,所以关闭缓冲区其实就是在关闭流对象;这点从它的继承体系中就可以看到,他是继承Writer类的;
其实关闭缓冲区就是在关闭缓冲区中的流对象;所以不用在关闭流对象;缓冲区本是不存在关闭的;
缓冲区是在内存里面;一停电就肯定释放内存了;,所以为了安全可见,可以边写边刷;
该缓冲区当中,提供了跨平台的添加换行符newline()方法;
2、BufferedReader
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
读取流在建立对象时,也要有一个被缓冲的对象;故有一个含参的构造函数;
FileReader对象在读取的时候每次都是一个一个读的,所以比较低效;
(1)创建一个读取流对象和文件相关联;
(2)为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数。
(3)关闭缓冲流对象;
该缓冲区提供了一个一次读一行的方法readline();,方便于对文本数据的获取,当返回null时,读到文件的末尾;把这个作为循环的条件;String默认值为null;
文本都是一行一行存在的;
readline方法返回的字符串内容中不包含任何的行终止符;
练习:通过缓冲区复制一个java文件;
在建立缓冲区流对象后,完成所有的流操作后,都要对缓冲区流对象进行关闭,这样就释放了流对象占的内存空间;
其实对缓冲的流对象操作后,其中就把对目的文件的流操作封装在里面了,直接关闭这个流对象就把所有的流对象都关闭了。
注意readline方法返回的时候只返回回车符之前的数据内容,并不返回回车符;
两个流之间是需要中转站才能进行复制的;
3、readline方法的原理: 模拟缓冲区的原理;
无论是读一行,或者读取多个字符,其实最终都是在硬盘上一个一个读取,所以最终使用的还是read方法即一次读一个的方法;其底层是用的数组结构来干的;
所谓缓冲区的好处就是读的数据没有直接操作,而是先存下来,读到一定数量后就一起操作;这样就会相对高效很多;
练习:
明白了BufferedReader类中的特有方法readline的原理后,可以自定义一个类中包含一个功能和readline一致的方法;来模拟一下BufferedReader;可以读一行数据的方法;
临时容器可以用Stringbuilder来处理,因为长度没有限制并且最终还是打印成字符串;比定义数组方便;
因为不明确到底要多少个数据,所以用StringBuilder比较灵活;
像流当中,StringBuilder类应该是比较好用的一个类,因为他比数组灵活,而且最终也返回的是字符串;
定义功能工具类的时候,里面的会抛出异常的操作直接throws,让调用者去try;
4、装饰设计模式;用于类的功能加强;
readline方法其实就是在增强了读入的功能;
增强功能,将被增强的对象传给增强的类;
这种设计模式我们称为装饰设计模式;
装饰设计模式,是指当想要对已有的对象进行功能增强时,可以定义加强的类,将已有对象传入,基于已有对象的功能,并提供加强功能;
那么自定义的该类,就称为装饰类;
模式都是基于原有的东西不断优化出来的;
后期进行功能扩展增强时,不建议改源代码,改源代码是灾难,所以可以按这种模式类进行功能扩展;
该装饰设计模式可以用于功能扩展的应用,可以跟接口抢饭吃;
装饰完后一般都是同属于一个接口或者类,是同一个体系中的成员;
装饰类通常会通过构造方法接收被装饰对象,并基于被装对象的功能,提供更强的功能;
super.method(); 继承父类后,使用父类的方法;
装饰模式的设计方式:构造函数传递,进行功能增强;
装饰模式和继承的关系;
提高效率可以用缓冲技术;
装饰设计模式,将原子类的一一继承体系进行了优化后而产生的体系,而且扩展性比之前的也强很多;
装饰模式比继承要灵活,避免了继承的臃肿,扩展性也好了很多,而且降低了类与类之间的关系;
注意:装饰类因为增强已有对象,具备动能和已有的是相同的,只不过提供了更强功能,所以装饰类和被装饰类通常是都属于一个体系中;
从继承结构变成了组合结构;
继承要写,但是不要写得太多,可以通过装饰的功能来扩展已知类的功能,否则,继承的体系将会变得非常的复杂;装饰模型灵活性比继承更强;体系也变得更加简单;
装饰类的对象可以把构造函数的参数类变为父类,使用也更广,更灵活;
把每一个具体子类的继承变成了基类的继承,通过传入子类的对象来加强这一个大家族的功能;使体系更简单,扩展性也更强;这就是装饰类;
在实际开发中进行功能扩展时非常的适用;想进行升级的时候来一个装饰类继承一下基类进行功能增强,如果做的不好,再继续用你原来的即可;
一般地,装饰类基本都继承了基类,这样才能给更多子类加强,如果不是给更多子类加强只需要继承被装饰类即可;
继承基类时,要注意覆盖基类当中的抽象方法;因为抽象的类无法实例化;
继承,调用父类方法就用super,不继承就用对象调用都一样;
发现继承可以用直接把父类的对象传入构造函数替代,如果用继承,里面的方法直接super点方法即可,调用的时候只new一个子类的对象即可,如果不用继承,就必须还要new一个父类对象,同时new子类对象,把父类传入子类构造函数;
5、LineNumberReader类是BufferedReader的子类;
BufferedReader,功能增强的缓冲区;
LineNumberReader类也是一个包装类或者说装饰类;
先要有一个被包装的流对象;
跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。
流对文件读取的时候读一行加一个行号;
该类就是自定义了一个私有的行号属性而已;别无其他;
练习:模拟一个带行号的缓冲区的对象;
LineNumberReader的原理:读的时候加了一个计数器;
都是装饰类
---------------------------------------------------------------------------------------------------------------------------------
总结:
字符流中学到的几个重要的对象:
FileReader//FileWriter//BufferedReader//BufferedWriter
二、字节流:
操作的数据都是字节数据,其实字符流也是字节数据,只是它里面有默认码表在自动转换;
1、需求:想要操作图片数据,这时就要用到字节流;
图片是一文件,所以就要找到字节流体系当中能操作文件的对象;
InPutStream (短read读)OutPutString(长write写)
注意:字符流使用的是字符数组,字节流使用的是字节数组;
学习API的方法就是,找到抽象类之后,学到方法后,直接找一个子类用一下就搞定了,
流对象一创建,就马上在内存建立了一个文件的;
同样,流对象都是要抛异常的;
字符流其实也走的是字节,只是他要先在临时存储存入起来,比如一个中文两个字节,读一个字节不能立即操作,字符流底层也是用的字节流的缓冲区,字符缓冲区有一个数组是用来临时存储数据的,所以字符流需要一个刷新动作,如果直接使用字节流操作没有使用具体指定的缓冲区,是不需缓冲的,不管什么类型数据,都可以以字节来直接操作写入到目的文件中区,所以不需要刷新的,只有有缓冲才要刷新,字节流因为对字节最小单位操作,直接往目的地操作就行了,中间不需要做任何的转换,故不需要缓冲操作,因此也不需要刷新直接就可以写入文件;
但是close要写,因为调用的底层资源要关闭掉;
第19-11视频中打印成new String (buf,0,len);有些不是很了解,为什么要这么做,要转成字符串?哦 这个好像也是字符串的一种表达而已,直接表达不行么? 好像不行;试一下;
这个是把数组变成string;—————
—————————第二次看视频 看到了这个笔记——笑了一下————哈哈…………典型的看了后面的忘记前面的;.…………………………………………………………
FileInputStream中的方法
int available() 返回文件中的字节数;
可以用来定义读数据时建立数组时的定义的个数;
定义刚好的元素个数的数组就不需要循环了;
但是不能够用来定义读取超大文件的的数组的元素个数;
字节流可以操作很多的媒体元素;
虚拟机启动时,默认的内存空间是64m的。
如果处理的文件太大,就会出现内存溢出,这时候available()方法装不了这么大的文件,所以在定义数组的长度时用available方法时要慎重,还是以1024的整数倍比较好;因为是要new一个数组出来,内存开辟不了这么大的空间给你;因为后面的是,如果装不下,就直接打印,然后再重新读;
2、练习,拷贝图片
图片属于媒体文件;
思路:
(1)用字节读取流对象和图片关联;
(2)用字节写入流对象创建一个图片文件,用于存储获取到的图片数据;
(3)通过循环读写,完成数据的存储;
(4)关闭资源;
用字符流拷贝媒体文件的时候,如果有编码表不认识的代码就会就会变成默认替代不识别区的代码,这时里面的字节码就变化了;因为他已经通过编码表把码给改了,所以复制的媒体文件就看不了;
字节流的缓冲区演示:通过MP3的复制;BufferedOutputStream,BufferedInputStream
缓冲区是为了提高效率而出现的;
缓冲区里面是已经封装了数组的,所以就不需要再写数组了,他们都在内部操作;
模版方法设计来定义获取时间;System.currentTimeMillis();
3、自定义字节流缓冲区;
自定义字节流缓冲区来提高流的读写速度;
因为StringBuilder都会自动变成字符串,所以为了保证源码,自定义就用数组;
数组里面会有隐式的指针在指导操作;
这个代码的原理没有弄太明白
类 BufferedOutputStream 该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
read(byte[] b 数组操作的返回值是次数;
读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回 -1。
MP3里面的数据都是二进制数据;
小问题是因为mp3前面读到了8个1所以读成了-1,而造成无法复制;
outputsream中的Write方法总是在写最低的八个字节;不写其他类型;只写一个字节;write方法在写的时候总会强行向下强转为byte型的字节;
为什么read()方法一定要返回int而不是返回byte呢?
因为如果遇到-1的情形,byte无法处理,从而使得数据不安全,而返回int后可以&255,这样就可以避免非-1而变成了-1给返回了,而在write的时候再自动都转为byte写入就可以了;与上255后,就不会有负数出现了;write自动取int的最后八位就还原了;在byte范围内的数与上255后的数结果都没有变,只有负数才会变,正数都不会变;但是负数都是变成正数了,但其最后八位还是没有变;而write执行的时候,就只取最后八位;
———————————————————————————————————————
总结
字节流:FileInputStream FileOutputStream BufferedInputStream BufferedOutputStream
三、读取键盘录入
键盘录入的形式获取数据;
System.out :对应的是标准输出设备;对应的是控制台;
System.in: 对应的标准的输入设备;对应是键盘;
只要操作数据都要用到流对象;
InPutStream 字节读取流对象;
老师说这时候知道为什么read方法是int了 搞得我自以为懂了,这句话让我又迷惑了;
这里的read方法是阻塞式方法;如果没有输入没有读到数据就会停止等待;
需求:通过键盘录入数据,当录入一行数据后,就将改行数据进行打印,如果录入的数据是over,那么停止录入;
ctrl+c 其实返回的就是-1,输入是输入不进去的;
键盘录入的时候可以不用close,因为是系统录入,所以停止了就自动关闭了;
通过键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理,也就是readline方法;能不能直接使用readline方法来完成键盘录入的一行数据的读取呢?
readline方法是字符流BufferedReader类的方法,而键盘录入的read方法是字节流InPutStream的方法。
那么能不能将字节流转成字符流在使用字符流缓冲区的readline的方法呢?
步骤:
(1)获取键盘录入的对象;
(2)将字节流对象转换为字符流对象,使用转换流InputStreamReader
(3)为了提高效率,用缓冲流对象;
四、转换流对象;
InputStreamReader 专门用于操作字节流的字符流对象;InputStreamReader是字节流通向字符流的桥梁:
把键盘录入用readline方法来编写,采取InputStreamReader的方法;
如果把打印语句放在循环外面会有什么效果呢?
OutputStreamWriter 字符转字节流 录入字符,转成字节存取在硬盘上;
因为最终只有键盘录入的流在操作,所以用转换流之后,流对象关不关都可以;手上停止操作就关闭了;
键盘录入要么ctrl+C,要么自定义结束标记;
输出语句底层就是用的流对象;
键盘录入最常见写法:
BufferedReader bufr = new BufferedReader(newInputStreamReader(System.in))
String line = null;
while((line =bufr.readLine())!=null){
if(“over”.equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close;
1、源:键盘输入;目的:控制台;
2、需求:把键盘录入的数据存储到一个文件中;
源 键盘 目的:文件
3、需求:想要将一个文件的数据打印在控制台上;
源:文件,目的,控制台;
流操作的基本规律:
最痛苦的就是流对象有很多,不知道该用哪一个?
通过三个明确来完成;
1、明确源和目的;
源:输入流:InPutStream,Reader;
目的:输出流:outputstream;Writer;
2、明确操作的数据是否是纯文本;
是:字符流;不是:字节流;
3、当体系明确后,再明确要使用哪个具体的流对象;
通过设备来进行区分;
源设备:内存,硬盘,键盘
目的设备:内存;硬盘,控制台;
1、将一个文本文件中的数据存储在另一个文件中,即复制文件;
源:因为是源,所以使用读取流,InPutStream 或Reader
是不是操作文本文件,是,这是就可以选择Reader;
这样体系就明确了;
接下来,明天要使用的该体系中的哪个对象?
明确设备:硬盘,一个文件;
Reader体系中可以操作文件的对象是FileReader
是否需要提高效率:是,加入Reader体系中的缓冲区 BufferedReader;
FileReader fr = new FileReader(“a.txt”);
BufferedReader bufr = new BufferedReader;
目的:OutPutStream 或者Writer;
是否是纯文本;是,使用Writer;
设备:硬盘,一个文件;
Writer体系中可以操作文件的对象为FileWrite;
FileWrite fw = new FileWrite( “b。txt”);
是否需要提高效率:是,加入Writer体系中的缓冲区 BufferedWriter;
BufferedWriter bw = new BufferedWriter(fw);
练习:将一个图片文件中的数据存储到另一个文件中;复制文件,要按照以上格式完成三个明确;
2、需求:将键盘录入的数据保存到一个文件中;
这个需求中,有源和目的都存在;那么分别分析;
源:InPutStream或者Reader;
是不是纯文本,是,Reader; 因为键盘录入不了图片;
设备:键盘: 对应的对象是system.in;
而System。in对应的是字节流,怎么选择的是Reader呢?
为了操作键盘的文本数据方便,转成字符流按照字符串操作最方便;所以既然明确了Reader,那么就将System。in转换成了Reader。用了Reader体系中的转换流,InPutStreamReader。
InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率吗?需要!BufferedReader;
BufferedReader bufr = new BufferedReader(isr);
当需求只是只需要读取数据直接打印就可以了时,这时就没有什么必要再去加转换流了,不需要字节转字符了;
FileWrite fw = new FileWrite( “b。txt”);
是否需要提高效率:是,加入Writer体系中的缓冲区 BufferedWriter;
BufferedWriter bw = new BufferedWriter(fw);
扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存入到文件中;
默认编码表GBK;
要想指定编码用的就是转换流,他里面是可以指定编码表的;
其实进行字符转换,其实就用的转换流,里面根据了指定的编码表进行转换的;
转换流真正的的应用就是能够把字节转换过来,通过查指定的码表转换;
只有转换流才能指定编码表;
目的:OutPutStream 或者Writer;
是否是纯文本;是,使用Writer;
设备:硬盘,一个文件;
Writer体系中可以操作文件的对象为FileWrite;
但是FileWriter使用的是默认编码表GBK;
但是存储时,需要加入指定编码表UTF-8,而指定的编码表只有转换流可以指定;
所以要使用的对象是OutPutStreamWriter,
而该转换流对象要接受一个字节输出流,而且还可以操作的文件的字节输出流,fileoutputstream;
OutPutStreamWriter osw = newOutPutStreamWriter(new FileOutPutString(“d.txt”),“UTF-8”)
需要高效吗?需要
BufferedWriter bw = new BufferedWriter(osw);
转换流什么时候使用呢?字符和字节之间的桥梁,通常涉及到字符编码转换时,需要用到转换流;
练习:将一个文本数据打印在控制台上,要按照以上格式完成三个明确。
改变标准输入的设备和输出设备;System.setOut(); System.setIn();
log4j工具很方便,是专门帮助我们建立java日志信息;
打印系统信息;
目的的改变,流就是用来操作数据的;数据都已经封装成数据了;
总结:
1、其实流里面所有的功能就是解决这几种需求,其中每一种需求的方法模型和操作都是一模一样的;关键要理解流的对象的概念,以及每一个流操作的底层原理;
键盘录入——控制台;
键盘录入——文件;
文件——控制台;
文件——文件;
文件—内存—控制台;
2、装饰设计模式的加入,使得将功能进行了一些加强并进行了封装,提高了效率,成为装饰模式;在流这块知识点中,就是Buffered——,四种缓冲流对象;NumLineReader;