04.JavaIO流问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了04.JavaIO流问题相关的知识,希望对你有一定的参考价值。

目录介绍

  • 4.0.0.1 说一下Java IO里面的常见类,字节流,字符流、接口、实现类、方法阻塞?
  • 4.0.0.2 什么是比特(Bit),什么是字节(Byte),什么是字符(Char),它们长度是多少,各有什么区别?
  • 4.0.0.3 字符流和字节流有什么区别?如何选择字节流或者字符流?什么是缓冲区,有什么作用?
  • 4.0.0.4 IO流中用到哪些模式?谈一谈IO流中用到的适配器模式和装饰者模式的作用优势?
  • 4.0.0.5 说一下对NIO的理解?NIO和IO的主要区别?NIO和IO如何影响应用程序的设计?
  • 4.0.1.1 对字节流进行大量的从硬盘读取,要用那个流,为什么?

好消息

  • 博客笔记大汇总【15年10月到至今】,包括Java基础及深入知识点,android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计500篇[近100万字],将会陆续发表到网上,转载请注明出处,谢谢!
  • 链接地址:https://github.com/yangchong211/YCBlogs
  • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!所有博客将陆续开源到GitHub!

4.0.0.1 说一下Java IO里面的常见类,字节流,字符流、接口、实现类、方法阻塞?

  • 输出流和输入流
    • 输入流就是从外部文件输入到内存,输出流主要是从内存输出到文件。
  • IO里面常见的类
    • IO流中有很多类,IO流主要分为字符流和字节流。字符流中有抽象类InputStream和OutputStream,它们的子类FileInputStream,FileOutputStream,BufferedOutputStream等。字符流BufferedReader和Writer等。都实现了Closeable, Flushable, Appendable这些接口。程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。
  • IO流中方法阻塞
    • java中的阻塞式方法是指在程序调用改方法时,必须等待输入数据可用或者检测到输入结束或者抛出异常,否则程序会一直停留在该语句上,不会执行下面的语句。比如read()和readLine()方法。
    • 技术博客大总结

4.0.0.2 什么是比特(Bit),什么是字节(Byte),什么是字符(Char),它们长度是多少,各有什么区别?

  • 什么是比特(Bit)?
    • Bit最小的二进制单位 ,是计算机的操作部分 取值0或者1
  • 什么是字节
    • Byte是计算机操作数据的最小单位由8位bit组成 取值(-128-127)
  • 什么是字符
    • Char是用户的可读写的最小单位,在Java里面由16位bit组成 取值(0-65535)
  • 各有什么区别
    • Bit 是最小单位 计算机 只能认识 0或者1

4.0.0.3 字符流和字节流有什么区别?如何选择字节流或者字符流?什么是缓冲区,有什么作用?

  • 字符流和字节流区别
    • 把二进制数据数据逐一输出到某个设备中,或者从某个设备中逐一读取一片二进制数据,不管输入输出设备是什么,我们要用统一的方式来完成这些操作,用一种抽象的方式进行描述,这个抽象描述方式起名为IO流,对应的抽象类为OutputStream和InputStream ,不同的实现类就代表不同的输入和输出设备,它们都是针对字节进行操作的。
    • 在应用中,经常要完全是字符的一段文本输出去或读进来,用字节流可以吗?计算机中的一切最终都是二进制的字节形式存在。对于“中国”这些字符,首先要得到其对应的字节,然后将字节写入到输出流。读取时,首先读到的是字节,可是我们要把它显示为字符,我们需要将字节转换成字符。由于这样的需求很广泛,人家专门提供了字符流的包装类。
    • 底层设备永远只接受字节数据,有时候要写字符串到底层设备,需要将字符串转成字节再进行写入。字符流是字节流的包装,字符流则是直接接受字符串,它内部将串转成字节,再写入底层设备,这为我们向IO设别写入或读取字符串提供了一点点方便。
    • 技术博客大总结
    • 字符流和字节流的使用非常相似,但是实际上字节流的操作不会经过缓冲区(内存)而是直接操作文本本身的,而字符流的操作会先经过缓冲区(内存)然后通过缓冲区再操作文件。
  • 如何选择字节流或者字符流?
    • 字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的
    • 如果是音频文件、图片、歌曲,就用字节流好点(避免数据丢失)
    • 如果是关系到中文(文本)的,用字符流好点)
  • 什么是缓冲区,有什么作用?
    • 缓冲区就是一段特殊的内存区域,很多情况下当程序需要频繁地操作一个资源(如文件或数据库)则性能会很低,所以为了提升性能就可以将一部分数据暂时读写到缓存区,以后直接从此区域中读写数据即可,这样就显著提升了性能。
    • 对于 Java 字符流的操作都是在缓冲区操作的,所以如果我们想在字符流操作中主动将缓冲区刷新到文件则可以使用 flush() 方法操作。

4.0.0.4 IO流中用到哪些模式?谈一谈IO流中用到的适配器模式和装饰者模式的作用优势?

  • IO流中用到哪些模式
    • 大概有装饰者模式和适配器模式!
    • 要知道装饰者模式和适配器模式的作用;其次,可以自己举个例子把它的作用生动形象地讲出来;最后,简要说一下要完成这样的功能需要什么样的条件。
  • 谈一谈IO流中用到的适配器模式和装饰者模式的作用优势
    • 装饰器模式:就是动态地给一个对象添加一些额外的职责(对于原有功能的扩展)。
      //把InputStreamReader装饰成BufferedReader来成为具备缓冲能力的Reader。
      BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
      • 1.它必须持有一个被装饰的对象(作为成员变量)。
      • 2.它必须拥有与被装饰对象相同的接口(多态调用、扩展需要)。
      • 3.它可以给被装饰对象添加额外的功能。
      • 比如,在io流中,FilterInputStream类就是装饰角色,它实现了InputStream类的所有接口,并持有InputStream的对象实例的引用,BufferedInputStream是具体的装饰器实现者,这个装饰器类的作用就是使得InputStream读取的数据保存在内存中,而提高读取的性能。
    • 适配器模式:将一个类的接口转换成客户期望的另一个接口,让原本不兼容的接口可以合作无间。
      //把FileInputStream文件字节流适配成InputStreamReader字符流来操作文件字符串。
      FileInputStream fileInput = new FileInputStream(file); 
      InputStreamReader inputStreamReader = new InputStreamReader(fileInput);
      • 1.适配器对象实现原有接口
      • 2.适配器对象组合一个实现新接口的对象
      • 3.对适配器原有接口方法的调用被委托给新接口的实例的特定方法(重写旧接口方法来调用新接口功能。)
      • 比如,在io流中,InputStreamReader类继承了Reader接口,但要创建它必须在构造函数中传入一个InputStream的实例,InputStreamReader的作用也就是将InputStream适配到Reader。InputStreamReader实现了Reader接口,并且持有了InputStream的引用。这里,适配器就是InputStreamReader类,而源角色就是InputStream代表的实例对象,目标接口就是Reader类。
      • 适配器模式主要在于将一个接口转变成另一个接口,它的目的是通过改变接口来达到重复使用的目的;而装饰器模式不是要改变被装饰对象的接口,而是保持原有的接口,但是增强原有对象的功能,或改变原有对象的方法而提高性能。
  • 用到设计模式优势
    • 装饰者模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例(各种字符流间装饰,各种字节流间装饰)。
    • 技术博客大总结
    • 适配器模式就是将某个类的接口转换成我们期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题(字符流与字节流间互相适配)。

4.0.0.5 说一下对NIO的理解?NIO和IO的主要区别?NIO和IO如何影响应用程序的设计?

  • 说一下对NIO的理解?
    • 传统的IO流是阻塞式的,会一直监听一个ServerSocket,在调用read等方法时,它会一直等到数据到来或者缓冲区已满时才返回。调用accept也是一直阻塞到有客户端连接才会返回。每个客户端连接过来后,服务端都会启动一个线程去处理该客户端的请求。并且多线程处理多个连接。每个线程拥有自己的栈空间并且占用一些CPU时间。每个线程遇到外部未准备好的时候,都会阻塞掉。阻塞的结果就是会带来大量的进程上下文切换。
    • 对于NIO,它是非阻塞式,核心类:
      • 1.Buffer为所有的原始类型提供 (Buffer)缓存支持。
      • 2.Charset字符集编码解码解决方案
      • 3.Channel一个新的原始I/O抽象,用于读写Buffer类型,通道可以认为是一种连接,可以是到特定设备,程序或者是网络的连接。
  • NIO和IO的主要区别?
    • 主要区别
      IO  NIO
      面向流     面向缓冲
      阻塞IO    非阻塞IO
      无   选择器
    • 面向流与面向缓冲
      • Java IO和NIO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。JavaIO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。JavaNIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
    • 阻塞与非阻塞IO
      • Java IO的各种流是阻塞的。这意味着,当一个线程调用read()或write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。JavaNIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
    • 选择器
      • Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。
  • NIO和IO如何影响应用程序的设计?
    • 无论您选择IO或NIO工具箱,可能会影响您应用程序设计的以下几个方面:技术博客大总结
      • 1.对NIO或IO类的API调用。
      • 2.数据处理。
      • 3.用来处理数据的线程数。
    • API调用
      • 当然,使用NIO的API调用时看起来与使用IO时有所不同,但这并不意外,因为并不是仅从一个InputStream逐字节读取,而是数据必须先读入缓冲区再处理。
    • 数据处理
      • 使用纯粹的NIO设计相较IO设计,数据处理也受到影响。在IO设计中,我们从InputStream或 Reader逐字节读取数据。
      • 请注意处理状态由程序执行多久决定。换句话说,一旦reader.readLine()方法返回,你就知道肯定文本行就已读完, readline()阻塞直到整行读完,这就是原因。你也知道此行包含名称;同样,第二个readline()调用返回的时候,你知道这行包含年龄等。正如你可以看到,该处理程序仅在有新数据读入时运行,并知道每步的数据是什么。一旦正在运行的线程已处理过读入的某些数据,该线程不会再回退数据(大多如此)。

4.0.1.1 对字节流进行大量的从硬盘读取,要用那个流,为什么?

  • 对字节流进行大量的从硬盘读取,要用那个流,为什么?
    • 因为明确说了是对字节流的读取,所以肯定是inputstream或者他的子类,又因为要大量读取,肯定要考虑到高效的问题,自然想到缓冲流。技术博客大总结
    • 用BufferedInputStream,原因:BufferedInputStream是InputStream的缓冲流,使用它可以防止每次读取数据时进行实际的写操作,代表着使用缓冲区。不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!并且也可以减少对磁盘的损伤。

其他介绍

01.关于博客汇总链接

02.关于我的博客

以上是关于04.JavaIO流问题的主要内容,如果未能解决你的问题,请参考以下文章

java内存流:java.io.ByteArrayInputStreamjava.io.ByteArrayOutputStreamjava.io.CharArrayReaderjava.io(代码片段

java缓冲字符字节输入输出流:java.io.BufferedReaderjava.io.BufferedWriterjava.io.BufferedInputStreamjava.io.(代码片段

是否可以动态编译和执行 C# 代码片段?

从流输入中解析没有根元素的 XML 片段列表

如何清除片段中的参数?

条件片段和导航重用