java IO系统

13 篇文章 0 订阅
11 篇文章 0 订阅

        java编程中有一个板块很让人头疼,但同时它又很重要,因为我们几乎每次做软件都会用到它,它就是IO系统。IO系统一开始学可能觉得没什么,因为接触的不多,但是在后面的学习中就会出现越来越多的类,每个类都有自己的特点,以及与其他类的相同点和异同点。这个时候整个IO系统就会变得复杂了,这个时候就需要这地掌握IO系统了,因为这种状态表明对于IO系统的学习已经到达一个需要突破的地步。

        这里需要区分一个概念,就是在解析XML文件不是IO的,因为IO仅仅只是将数据原封不动的进行传输,而解析XML文件则是对XML文件进行分析操作。就是说,解析,IO是两个不同的概念,根据这点区分使用的场合。

        java的IO系统基础为InputStream,OutputStream,Writer,Reader。这是其他的IO系统类的基类,其他类都是由他们改装来的,改装采用的是装饰设计模式。其中InputStream,OutputStream是抽象类,即read()以及write()方法为抽象方法。Writer类,Reader类都是抽象类,Writer的抽象方法为flush(),write(),close(),Reader类的抽象方法为read(),close()。flush()方法的理解较为重要,用于清空输出通道。关键点就是基类都是抽象类,而抽象类是不能被实例化的,只能被继承的子类间接使用,如多态。

        掌握IO系统就应该明白各种类的作用,明白各种IO概念。流概念,缓冲区概念,二进制流,字节流,字符流,java内存储字符使用unicode编码存储。字符流一次操作比字节流效率更高,因为字符流一次操作一个缓冲区,而不是一个字节。缓冲区事实上在这里是在类的内部建立了一个字节数组,通过该字节数组进行字节数据的存储从而达到缓冲数据的目的。

        对于作用,InputStream,OutputStream处理的是字节流,即字节以及字节数组。Writer,Reader处理的是字符流,即处理文本以及字符串等。(在此期间有出现一个较为特别的类,FileterInputStream,它的作用是对InputStream的方法进行一些简单的处理,以便后面的子类重写方便,差不多跟空实现一样,只是为了子类所以才有的这个类,所以Filter开头的IO系统的类都是为了其子类而进行过一些简单加载的类而已)

        常用的IO系统的类有很多,但是不能死记硬背,可以通过名称知道其相比积累所添加的功能,即在使用装饰设计模式中知道,被适配者就是就是积累,而目标则是名称上较之积累添加上的那部分名称。现在说说目标名称,常用的有,buffered,data,file,print以及联通基类之间的OutputStreamWriter,InputStreamReader(关键作用在于转换字节流和字符流)。含有Buffered就是存在缓冲区的类,含有Data的就是为了实现基本数据类型的操作的类,含有File的为操作文件的类,一般参数为文件或文件路径的字符串,PrintWriter,PrintStream中的print表示需要按格式输出。这些基本上是IO系统的类的内部机制,但是不仅仅是这样的,作为一个类,关键的还是他的方法,这才是最麻烦最难掌握的。(同时还应该注意两个比较容易混淆的类,BufferedInputStream,ByteArrayInputStream,两个类都有缓冲区,但是不同的是,BufferedInputStream是内置的,且内置的缓冲区字节数组大小是可以变的,而ByteArrayInputStream的缓冲区则是在实例化的时候加进去的,且大小是不可变的。同时由于这个原因,导致读取数据超过数据大小时,ByteArrayInputStream返回-1,而BufferedInputStream则由于大小可变因此会去底层的InputStream进行数据读取。总的来说其实从Bufrered与ByteArray这两个名字就基本可以知道其作用了,分别为缓冲和数组!)

        PrintStream,PrintWriter这两个按格式输出的类较为特别,他们两个分别是OutputStream与Writer的子类,作用几乎是一样的,只是操作的分别为字节流和字符流,但是对于print我们应该清楚,必定会存在两种方法,print()以及println(),其实明白调用方式就可以知道实现过程了,PrintWriter实现了所有的PrintStream的print()方法,而PrintWriter的调用机制和PrintStream一样。PrintStream的println()调用的是print()方法,print()调用的是write()方法,加上PrintStream本身还实现了BufferedWriter使得write()的数据得以缓存,所以,就能实现print(),println()方法了。故而明白按格式输出是指的按字符串或字符行输出。

        另外需要注意的是android的IO系统是有区别于java的IO系统的,因为android的IO基于手机,所以用到this.openInputStream(),this.openOutputStream(),得到可操作的刘之后,再进行java的流操作。

        IO系统的类的特性都体现在方法上的不同。应该通过方法掌握IO系统,注意,其实IO的类基本上一直都围绕着write()以及read()进行,所有的方法都是为其服务的,因此关键掌握这两点,围绕其展开方法的掌握即可。


        注意:对于IO系统,其实应该注意,系统发送数据时只有内存占满才发送,而使用IO的相关类时,经常是写入的数据并未将内存占满,这个时候就需要强制输出,通常的方法有三种,1、使用flush()2、使用close()3、类自身有自带自动刷新,将数据输出,例如PrintWriter的第二个参数autoFlash,就是为这种情况设计的。


        对于IO类中,对于xxwriter的由于是处理字符,所以存在字符集的设定,就像PrintWriter,OutputStreamWriter就有对字符集进行控制的参数。而Filexx的IO类,则是可以对文件进行追加操作的类,事实上除了FileOutputStream,FileWriter,RandomAccessFile之外,其他的类使用写操作就是将原先的内容删除,加入写入的内容。



三种基本介质流ByteArrayInputStream,StringBufferInputStream,FileInputStream。

在于公用的线程管道中读取数据PipedInputStream。

两种装饰流ObjectInputStream,FilterInputStream。

关于IO流操作的基本单元:IO流操作最终只有两种形式,write(int)与write(byte[])。其他的操作都是基于这两种形式上进行封装的。(应该以bit去理解,而不应该以java的Byte去理解,其实write(int)写入的是int的低八位,也就是说写入的是一个字节)(同时注意,文件操作的基本单元是bit,而java的基本单元是Byte,因此文件操作时,应该注意理解基本单元)



其实在编程时有两个很重要但是很容易被忽略的类,System.in,System.out,使用它们可以实现读取计算机的输入流,写计算机的输出流。

(xx.class.getResourceAsStream()是用于获取项目资源的,只能用于获取bin文件夹的,bin文件夹在java工程中是隐藏的,但是打开硬盘中项目所在位置可以找到,这里获得的资源可以分为两种,一种是加了“/”的加了之后代表路径是到项目根目录下的,这是需要使用“/com/xx/xx/xx.xxx”进行资源寻址,另一种是不加“/”的,这时,系统自动寻址到xx.class文件所在文件夹,即bin文件夹里面的最后一个文件夹。)

(在IO中还会涉及到另一个概念,那就是LITTLE-ENDIAN(LE),BIG-ENDIAN(BE),这两个概念是基于RAM的,一串数据的读取时从左到右的,数据的存储也是,但是数据的大小却是从右到左的,即最高位在最左边。如果存储和书写一样就是BE,否则就是LE。就是说加入数据是65,43,21,存储是65,43,21,则是BE,若是21,34,56则是LE。但是要明确一点,那就是LE,BE的概念是针对RAM,IO,net等需要传输的概念上的,而对于一个已经存在的文件,往往就是只需要我们从文件头读到文件尾即可,并未LE,BE的概念。但这里往往涉及到编码解码,进制等问题)

(编码解码问题一般都是发生在字节和字符之间的,所以一般使用InputStreamReader,OutputStreamWriter进行解码编码,就是在参数的第二位输入所需编码格式,诸如UTF-8,UTF-16,GBK等,其实InputStream,OutputStream使用的是字节,Reader,Writer使用的是字符,所以一般使用InputStreamReader,OutputStreamWriter进行解码编码)

(其实InputStreamReader,OutputStreamWriter在IO时会自动调用StreamDecoder进行编码解码,以连接InputStream与Reader,OutputStream与Writer。而StreamDecoder会调用Charset,同时Charset有默认形式,当我们没传送自定义Charset时,使用默认的,而当我们需要改变编码方式时可以使用自定义的Charset传入,进行编码格式更改。而编码解码一般都是发生在磁盘IO,网络IO上。同时对于编码解码,还有String及其相关类可以进行相关操作。)


(在使用BufferedReader.read(char[ ])进行读取时,虽然可以指定所用的char[ ]的大小,但是实际上BufferedReader里面的字节流被读取的个数是多于我们所设置的大小的。也就是说,使用read()进行的读取虽可以得到所需字符数组,但是会多读取一些字节,而这在对于字节数要求较高的读取上是不允许的,所以一旦遇到这种情况,应考虑其他方法进行读取,而不是使用BufferedReader。)



(未完成)




        

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值