关于张老师java视频的学习(十四)

Java高级视频:

输入与输出I/O :

一、知识点:

 (4)、流的概念:InputStream 、OutputStream ; FileInputStream、FileOutputStream类 ; Reader、Write类 ; PipedInputStream、PipedOutputStream类。
   ByteArrayInputStream、ByteArrayOutputStream类。代码的复用性。
  · 流是字节序列的抽象概念,流提供了用一种统一的从各种设备读写数据的机制。
  · 流与文件的区别: 文件是数据的静态存储形式,而流是指数据传输时的形态。文件流、网络流、内存流等流……
  · Java中流分为两大类: 节点流 和 过滤流(也称处理流)。
   节点流:用于直接处理操作目标设备的流类称为节点流类,节点流类所对应的I/O源或者网络称为流节点。譬如将一个类和某个文件或者网络直接
    相关联,那么这个流类就叫做节点流类,这个文件或者网络就称为流节点。程序也可以通过一个间接的流类来调用节点流类,来达到更
    加灵活的读写各种数据。
   过滤流:
  · InputStream类: 程序可以从该流中读取字节的对象叫输入流,在Java中,用InputStream类来描述所有输入流的抽象概念。
                   该流是一个抽象流类,并没有对应到具体的I/O设备,只描述了所有的流设备的共性,
   方法:int read(),读取流,并返回读取的字节数,如果读到了流末尾,则返回-1;如果通过中没有数据,则发生阻塞,直到通道中传来数据。
   流中没有数据可读的情况(阻塞):通道未关闭,但是通道中没有数据传递,则使用read()方法的时候,会发生阻塞。虽然,该方法返回int类
   型表示读取的字节数,但是该方法只从流中读取了一个字节。
   int read(byte[] b):用于从字节流中读取若干个字节到数组b中,读取的最多字节个数为字节数组b的长度,尽可能的读取字节流中字节,直到
    读完或者填满数组b。返回值表示read方法读取到的字节数,如果没有读取到字节数组b的长度个字节,那么尽可能的读取字节流中的字节
    ,然后立即返回值,如果一个字节都读取不到,那么read方法发生阻塞。
   int read(byte[]b, int off, int len): 从字节流中读取len个字节,从数组b的off位置开始依次存放,返回值为实际读入的字节数。
   long skip(long n): 跳过输入流中的n个字节,并返回实际跳过的字节数。主要应用于包装类流中的数据,而非底层流中。
   int available():返回字节流中可读取的字节数,如果程序只是偶尔的读取流中的数据,首先用该方法检查流中确实有字节可读,之后再去调用
    read方法去读取数据,这样就可以避免程序发生阻塞。如果程序要不断的从字节流中实时的读取数据,那么我们就需要不停的用该方法
    检查流中是否有数据,有的话就读取,没有的话就继续检查,直到有数据,这样做会消耗较多的CPU资源,不如在一个单独的线程中直接
    循环的调用read方法,当流中没有数据的时候,read方法处于阻塞状态,这样几乎不占用CPU资源,但是流中的数据一来,就可以马上读
    取流中的数据,这便是循环read方法的好处。available的另外一个用处:如果我们想读取8个字节,但是read只读取了3个,那么我们可
    以使用available方法检查流中是否还有字节,如果有,那么继续读取5个,然后返回。
   void mark(int readlimit): 用于在输入流中建立一个标记,当建立mark标记之后,该方法接受参数readlimit,即从mark标记开始所能读取的最
    多的字节数。
   void reset(): 和mark方法配合使用,当在A建立标记之后,从该标记读取到B位置之后,此时调用reset方法,那么下次再读取的时候,又将从A
    位置开始读取数据,即reset方法使下次读取回到最近一次建立的标记开始读取。
   boolean markSupported():返回当前流对象是否支持mark和reset方法。
   void close():在完成流对象读取之后,不再需要该流,此时需要调用该方法来关闭流即与流相关的资源。
  · InputStream类是抽象类,程序中使用的实际是InputStream的各种子类,子类中并不都支持InputStream中定义的某些的方法,比如reset()和mark()方法
   ,他们对节点流不适用,只使用于包装流类。
  · OutputStream类:程序可以向其中连续写入字节的对象叫输出流,在java中,使用OutputStream来描述所有输出流的抽象概念。也没有对应到具体的流设
   备,只是描述了这种输出流设备所具有的共性,描述了这种流类写入数据的时候所具有的通用的方法。
   方法:
   void write(int b):将一个int整数b的最低的字节写入输出流中,即最后8位,写入输出流中。
   void write(byte[] b):将字节数组b中的所有的字节写入输出流中。
   void write(byte[] b, int off, int len):将字节数组b中,从off位置开始,len个字节写入输出流中。
   void flush():将内存缓冲区中的内容彻底的清空,并输出到目标IO设备中。应用程序与I/O设备之间有内存缓冲区相隔,这是由于设备速度不一致
     导致的,只有当内存缓冲区全部载满之后,才会一起写到I/O设备之中。使用内存缓冲区有作用:
   void close():关闭输出流对象,
     1、提高了CPU的使用率,
     2、write方法因此而没有真正的写入到I/O设备中,从而程序还有机会撤消写入。
     3、使用内存缓冲区,能整体的提高计算机的效率,但是也会降低单个程序自身执行的效率。
     4、由程序调用的读写,每次读写少量数据; 由系统自动完成的读写,每次读写大量的数据。
     5、即使缓冲区没有载满,应用程序也可以调用相关方法(如flush方法)来强制将缓冲区内容读写到设备中,这个过程,习惯上
        称为 刷新!不是所有的流类都支持flush方法,只有相关的涉及到缓冲区的流类才支持。
     6、当调用close方法来关闭输出流的时候,缓冲区的内容也会被刷新到目标设备上。
     7、内存缓冲区:在程序将数据写入设备的时候,并不是立即写入设备的,而是先写入缓冲区,当缓冲区载满之后,才一并写入
        到设备上,这样,如果日志文件在缓冲区中,在程序崩溃的时候,程序还没来得及写入设备,日志文件便被清除,故日志文件
        根本未记录到程序真正崩溃时的动作。


 (5)、FileInputStream 与 FileOutputStream类:  都是用来处理字节的
  分别用来创建磁盘文件的输入流和输出流对象,通过它们的构造函数来制定文件路径和文件名。
  · 创建FileInputStream类对应的对象时,指定的文件必须是存在可读的
    创建FileOutputStream类对应的对象时,指定的文件如果存在,这个文件中原来的内容将被覆盖清除。如果不存在,则创建这个文件,并写入数据。
  ·  对于同一个磁盘文件创建FileInputStream类对象时支持两种方式:
   1、FileInputStream inFile = new FileInputStream("完整文件名(包括路径)");
   2、File file = new File("完整文件名(包括路径)");
      FileInputStream infile = new FileInputStream(file);
   其中,第二种方法支持对文件对象file的一系列操作,如:文件存在性的检查、文件是否为目录、文件是否可写……
  · 创建FileOutputStream类对象的时候,可以指定不存在的文件名,但是不能指定一个已经被其他程序打开的文件,因为其他程序打开了该文件之后,会给
   文件上锁,从而无法创建FileOutputStream对象。
  
  Reader和Writer类的区别联系: Java中单独的类,用来直接处理字符的读写,而不需要通过转换成字节,用Stream的字节方法来处理。
    是所有字符流类的抽象基类,用于简化对字符串的输入与输出编程,即用于读写文本数据。
   · 在不考虑正负数的情况下,每个字节中的数据可以是0~255间的值,他们在内存中都是以二进制的形式存放的。通常所说的文件就是由内存复制
     到硬盘上的数据的一种存储形式,文件中的每个字节数据也都是二进制形式,所以严格的说,文件系统中的文件都是二进制文件,文本字符都是
     又一个或多个字节组成的。其中每个字节的数据不能是任意的,它不能像而二进制数据一样,从0~255都可以,而这些表示成字符的字节,它的
     只能是0~255间的一些特殊的值,而其他的是在任何的字符中都不能出现的,即不是0~255间的数值都会对应到字符。如果一个文件中的每个字节
     或者每相邻的几个字节都可以表示成某个字符,则称之为文本文件。可见文本文件是二进制文件的一种特例。为了区别于二进制文件,把文本文
     件以外的文件称为二进制文件。由于很难区分它们,可以简单的认为: 如果一个文件除了文本字符而不包括其他字符,则认为它是文本文件,
     其他的文件则称之为二进制文件。
   · Reader 和 Writer类主要用于读写文本文件的内容,而OutputStream和InputStream则用于读写二进制文件。
   · 在对比FileOutputStream和FileWriter对象之后,可以知道:
    1、FileOutputStream中的write(byte b)方法,写入单个的字节的时候,不会调用flush方法来讲数据直接刷新硬盘的文件上。
    但是,在写入write(byte[] b)字节数组的时候,会自动调用flush方法来讲数据直接刷新到硬盘的文件上。
    2、而FileWrite()方法,则不会直接讲字符串写入硬盘,除非关闭该流。 

 (6)、PipedInputStream 类 和PipedOutputStream 类: 主要应用于程序中的创建管道通信。
  · 一个PipedInputStream类对象必须和一个PipedOutputStream类对象相对应,产生一个通信管道。
    PipedOutputStream对象可以向该管道中写入数据,PipedInputStream可以像该管道中读取由PipedOutputStream对象写入的数据。
    这两个类主要用于完成线程之间的通信,一个线程的PipedInputStream对象可以从另外一个线程的PipedOutputStream对象读取数据。
  · PipedWriter和PipedReader类:用来处理字符文本的管道通信
  · 管道流类的优点:
    1、使用管道流类,可以实现各个程序模块间的松耦合通信。
       这样,在程序中可以灵活的将多个模块的输出流和出入流相连,然后拼装成满足各种应用的程序,而不需要对各种模块的内部进行修改。
       就像家庭的供水系统一样: 各个模块间的水流供应通过管道来实现,而不影响其他模块,也方便扩展其他的水处理模块。这些都只需要各
       模块具有水流管道。
    2、使用管道流类的程序模块,具有强内聚,弱耦合的特性。
       一个模块被替换或者被拆卸,不会影响其他的模块。假设有一个使用管道流的压缩或者加密模块,调用程序只需向该模块中的输入流中写入数据,
       然后从该模块的输出流中读取数据,这样就完成了改模块的加密和压缩,该模块就向一个黑夹子一样,编程人员不需要了解其中的具体实现。

    、ByteArrayInputStream类 和 ByteArrayOutputStream类:
  · 内存虚拟文件或者内存映像文件,其实就是把内存的一块数据存储缓冲区虚拟成一个文件,原来该写入到硬盘的内容,可以先写入该内存中。原来该
    从一个硬盘文件上读取的数据,可以从该内存中读取。
  · 要在程序中需要定义一个大的数据存储缓冲区,该缓冲区通常是一个字节数组。在Java中定义了两个专门的类,如上,用于以I/O流的方式来完成对
    字节数组内容的读写,从而实现类似于虚拟文件或内存映像文件的功能。
  · ByteArrayInputStream类有两个构造函数:
   1、ByteArrayInputStream(byte[] buf):将字节数组当中的所有的数据作为数据源
   2、ByteArrayInputStream(byte[] buf, int offset, int length):将字节数组当中的,从offset开始,length个元素作为数据源。
  · ByteArrayOutputStream类也有两个构造函数:
   1、ByteArrayOutputStream():将创建一个32个字节的缓冲区,
   2、ByteArrayOutputStream(int):根据实参来创建缓冲区。
    这两个构造函数创建的缓冲区在字节过多的时候,都会自动增长以适应要存储的数据。创建这些对象之后,流就可以像写入虚拟文件一样向他们写入
    数据。
  · 为何要以I/O方法来读取字节数组中的数据,而不是直接读取?
    若程序在运行过程中需要产生临时的文件,那么访问内存中的虚拟对象,那么程序就不用访问硬盘。因为访问虚拟文件归根到底还是要访问硬盘。
    因此,建立一个如上的类,就不再需要访问硬盘了,从而加快了运行速度。
  · 实例:编写一个把输入流中所有英文字母变成大写字母,然后将结果写入到一个输出流对象。用这个函数来将一个字符串中所有的字符转换成大写。
  · 字符串,其实就相当于一个字符数组,即字符类缓冲区。
    Java中提供了StringReader类和StringWriter类,来以字符I/O的形式来处理字符串。


  · 重视I/O程序代码的复用:
    1、System.in是对应着键盘,是InputStream类型的实例对象。 可以使用之读取键盘上的数据。键盘,被当做一个特殊的输入文件。
    2、Sytem.out对应着显示器,是PrintStream类的实例对象。可以使用之输出到显示器上。 显示器本当做一个特殊的输出文件处理。
    3、不论是文件流还是网络流,他们都需要有一个结束标记来表示底层物理设备中的终止点,
    4、不论是各种底层物理设备用什么方式实现数据的终止点,InputStream 类的read方法总是返回-1来表示输入流的结束。
    5、在Windows 下,可以按住 Ctrl + Z 组合键产生输入流的结束标记,
       在Linux 下,则是按住 Ctrl + D 组合键来产生输入流的标记。
  
  · 建议:要编程从键盘上读取一大段数据时,应尽量将读取数据的过程放在函数中完成,使用 -1 来作为键盘输入的结束点。 在该函数中编写的程序
          代码中不应直接使用 System.in 读取数据,而是作为一个InuputStream 类型的形式参数对象来读取数据,然后将 System.in 作为实参传递
   给InputStream 类型的形参来调用该函数。如:(即并不是直接把System.in作为一个对象来使用,而是将之复制给InputStream对象来使用
   ,这样,以后如果需要从文件读取的时候,不需要修改太多的代码。)
   BufferString str = new StringBuffer(new InputStream(System.in))
  
 (7)、字符编码: 字符,字符文本,
  一个程序要读取另外一个程序所产生的文本文件,首先要了解该程序所用的编码方法,然后用相应的解码方法来读取文件。
  
  · 字符编码的概念:
    1、计算机中只有数字,计算机软件里的一切都是用数字来表示的,屏幕上显示的一个个字符也一样。
       在8位字符编码中,一开始一个字符为一个字节:
   ASCII编码:美国信息交换标准码(=American Standard Code for Information Interchange)
   它的最高bit位编码为0,也就是说,ASCII编码字符值在 0~127之间。
       随着计算机的发展,多国将自己的字符引入计算机,从而字符集得以扩展,0~127个字符不能表示他们的字符。
       在我国,0~127是远远不能表示中文字符的,因而,我们将一个中文字符用2个字节来表示,即16个bit位。中文字符的每个字节的最高位bit都为1,
       中国大陆为每个中文字符指定的编码规则称为GB2312(国标码),后来在此基础上,又增加了更多的中文字符,如繁体字,新的编码规则称为GBK。
       在中国大陆使用的计算机系统上,GBK和GB2312就被称为该系统的本地字符集。
       · 当我们使用某些软件打开一些文本文件的时候,显示的一个个字符,其实就是软件使用某个编码规则将文本反编译出来显示的结果。
       · 对于同一个文本,使用不同的编码规则编译的时候,得到的结果可能是不同的字符。
       · 随着各国的交流,不同的字符编码规则,使得交流难以进行,因而,ISO定义了通用的字符集:Unicode(统一码(采用双字节对字符进行编码)
   ) Unicode 是基于通用字符集(Universal Character Set)的标准来发展,并且同时也以书本的形式(The Unicode Standard。
       · 由于Unicode占用两个字节,故在全世界范围内所表示的字符个数不会超过2的16次方(65536),实际上,Unicode编码中还保留了两千多个数值
         没用用于编码。这些字符中,并不包括那些少见的字符(如少数民族、康熙大辞典等的字符…)
       · 在相当长的一段时期内,本地化字符编码与 Unicode编码共存。
    2、Java中的字符使用的是Unicode编码,Java在通过Unicode保证跨平台特性的前提下,也支持本地平台字符集。
    3、UTF-8编码:UCS Transformation Format-8,UCS 转换格式-8。是UNICODE的一种变长字符编码,由Ken Thompson于1992年创建。
       对于不同的字符,使用不同的编码。如果是ASCII字符,仍然使用1个字节的编码,如果是中文,则使用2个字节的编码,其他国家的字符则使用2个
       或者3个字节表示。使用UTF-8编码的文件,通常都要用EF BB BF作为文件开头的三个字节数据。
    4、字符的UTF-8编码与Unicode编码之间的转换关系:
   · /u0001和/u0007之间的字符c,UTF-8编码为一个字节:(byte)c。
   · /u000或其范围在/u0080和/u07ff之间的字符c,UTF-8编码为2个字节:
    高字节部分:(byte)(0xc0|(0x1f&(c>>6))),低字节部分:(byte)(0x80|(0x3f&c))。
   · /u0800和/uffff之间的字符c,UTF-8编码为3个字节:
    最高字节:(byte)(0xe0|(0x0f&(c>>12))),中间字节:(byte)(0x80|(0x3f&(c>>6))),低字节:(byte)(0x80|(0x3f&c)).
   · UTF-8的编码优点:
     不出现内容为0x00字节;便于应用程序检测数据在传输过程中是否发生了错误。直接处理使用ASCII码的英文文档。某些字符需要用到3个字节。
   · UTF-8的缺点:
     通常需要用EE BB BF作为UTF-8字符开头3字节的数据,只是一个标记,表示文件中的其余部分为UTF-8编码,应用软件不能完全依赖文件开头的
     标记信息,也应该根据文件的特征来猜测文件的编码规则。
     5、UTF-16字符编码:
   由于Unicode字符编码使用为2个字节,故不能包含世界上所有的字符,包括藏文、康熙大辞典等字符。而UTF-16在Unicode的基础上进行了一些细
   节上的扩充,增加了对Unicode编码没有包括的那些字符的表示方式。是Unicode编码的一个包含。一个Unicode字符就是一个UTF-16字符,但是一
   UTF-16字符却不一定是Unicode字符。UTF-16字符占用4个字节,这便是UTF-16中的16的由来。
   · Unicode编码将0xD800~0xDFFF区间的数值保留下来,该区间称为代理区间(2048个)。UTF-16扩充的字符,占用四个字节,代理区间前面连个
     字节的数值为0xD800~0xD8FF之间(高半代理区间),后面两个字节的数值为0xDC00~0xDFFF之间(低半代理区间)。UTF-16是Unicode字符的基
     础上,利用代理区间来扩充字符编码的机制。扩充了1024*1024个字符。故UTF-16字符要么为2个字节,要么为4个字节;如果两个字节不在上述
     之间,则表示为基本的Unicode字符,否则,为需要代理的扩展字符。
   · 不同的体系结构的计算机中,UTF-16编码的Unicode字符在内存中的字节存储顺序是不同的。
     在Intel的CPU中,是以低字节在前,高字节在后存储字符的。在其他的一些CPU中,则是以高字节在前,低字节在后的存储方式来存储的。
   · 如果文件以0xFE 0xFF这两个字节开头,则表明文本的其余部分采用Big-Endian(高位在前)的Unicode编码;如果以0xFF 0xFE这两个字节开头
     ,则表明文本其余部分以Little-Endian的UTF-16编码。


二、问题与收获:

 (1)、至今没弄明白I/O中的RandomAccessFile的实例的原理: 关键词:本地字符ASCII、Unicode字符。
  

 (2)、既然有了垃圾回收器,为何还需要调用流的close()方法呢?
  一个对象在没有变量指向它的时候,它就变成了垃圾,最终会被垃圾回收器从内存中清除。既然这样,那么我们是否还需要调用close方法来释放流对象
  的相关资源? 那么,这个相关资源是又指什么呢 ? 在程序中创建的对象,都是用来描述现实中有形无形的事物抽象,而计算机当中产生的对象,当然
  也是现实中的事物,即流就是计算机所产生的一种资源,当程序创建了I/O流的时候,也会创建一个叫流的事物。此时,计算机内存中实际上产生了两个
  事物,一个是Java程序的类实例对象,一个是系统本身产生的某种相关资源。 那么,Java垃圾回收器只会回收Java程序的类实例对象,而对于系统本身
  产生的相关资源,则需要程序自己调用close方法来释放。

 (3)、在网络程序中,网络程序崩溃的原因众多,要找出相关原因,最好的方法是将程序的每一个动作都记录到日志中,从而在程序崩溃的时候,可以查找崩溃
  前的日志从而分析其原因。

 (4)、并不需要死记硬背一些知识,而是需要多开拓自己的知识面,这样在遇到问题的时候,可以从多个方面来思考解决问题。

 (5)、文件、文档、二进制、文本、非文本:
  文件:是计算机中所用的数据在硬盘中的存储形式,是在电脑里看见的东西都叫文件.
  文档:在操作系统中,文档是文件夹
  二进制文件:基于机器码编码的文件,常见的后缀有bin、dll、exe、com及图片格式的文件…
  文本文件:基于字符编码的文件,文本文件是一种典型的顺序文件,其文件的逻辑结构又属于流式文件。 常见的后缀有txt,doc等……
  非文本文件:存储声音、动画、图像、视频等非文本信息的文件,常见后缀有,AVI、FLASH、SWF……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值