字符char 输入输出流 和 NIO

来源:互联网 发布:java jar 日志输出 编辑:程序博客网 时间:2024/06/07 04:58

字符输入和输出很类似,只不过字符类处理的是字符,

字符流以char为最基本的单位,而字节流以byte为最基本的单位。

字符流 Reader 和 Writer 两个抽象类,字符输入和输出流的类都是继承自这两个类。
Java使用unicode来表示字符和字符串, 一个字符char 用两个字节表示,即一个字符占 16 位。 Java中一个字符 可以表示一个汉字。

OutputStreamWriter类: 用于在字符和字节流之间搭起一座桥, 从程序向文本写数据,从字符流转化为字节流
InputStreamReader类 : 从文本向程序中读数据,从字节流到字符流
这两个类经常被用到, In 和out 是输入和输出字节流对象,带参数的String 参数是 指定的编码格式(如果不指定,表示使用当前平台的编码方式)

这里写图片描述

其实字符流和字节流的使用大同小异,大家看一下下面的例子就好了

// 从程序向文件中写入信息,再从文件中读取出来public class FileWriterTest {    public static void main(String[] args) throws IOException {         //向文件中写入字符串, 加在文本文档的后面,而不是覆盖           FileWriter  out = new FileWriter("file.txt", true);           // 装饰模式把文件流变成一个带缓冲的文件流           BufferedWriter buffOut = new BufferedWriter(out);           String str = "hello world \n"; // \n 表示回车           out.write(str);           out.write(str);           out.write(str);           out.close();           // 从文件中读取字符串           FileReader in = new FileReader("file.txt");           BufferedReader buffIn = new BufferedReader(in);           String str2 = null;           while (null != (str2 = buffIn.readLine())){               System.out.println( str2);           }           buffIn.close();    }}

几种字符集的编码:
ASCII 码: 美国信息互换标准代码,基于英文字符的编码,包括英文字符,数字,每一个ASCII码和一个8为二进制数对应,数字的表示,最高位是0,能表示的数字是0-127, 最高位为1的表示一些制表符和其他符号。是通用的单字节编码系统。

GB2312: 中国汉字信息交换编码,为每一个中文字符指定相应的数字,一个中文字符 = 两个字节,每个字节的最高位置都为 1。

GBK : 国标扩展,一些生僻字也被加入到GBK编码中

Unicode : 全世界通用的字符集,由两个字节表示, 对于英文字符,一个字节就能表示,因此英文字符的Unicode码的高位字节都为 0。来实现等长兼容。等长的编码

UTF-8: Eight - bit UCS Transformation format, UCS 是一个通用的字符集,是所有其他字符集标准的一个超集,十分适合国际化,
它是不等长的编码方式,比如英文字母的UTF码用一个字节表示,而汉字的UTF码是3个字节。

一个重要的方法获取项目的配置信息

        // 获取项目的配置情况        Properties p = System.getProperties();        p.list(System.out);

另外一个重要的文件类:
随机访问文件类 : RandomAccessFile 该文件类既能对文件读也能写,同时提供了 write 和read方法,还能在文件中定位位置,跳到特定数据所在的位置。

RandomAccessFile的唯一父类是Object,与其他流父类不同。是用来访问那些保存数据记录的文件的,这样你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。
RandomAccessFile是不属于InputStream和OutputStream类系的。实际上,除了实现DataInput和DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫不相干,甚至都没有用InputStream和OutputStream已经准备好的功能;它是一个完全独立的类,所有方法(绝大多数都只属于它自己)都是从零开始写的。这可能是因为RandomAccessFile能在文件里面前后移动,使用seek( index) 方法, 可以跳到文件中指定的位置,所以它的行为与其它的I/O类有些根本性的不同。总而言之,它是一个直接继承Object的,独立的类。

NIO 新的I/O系统 , 和I/O 的区别
IO NIO
面向流 面向缓冲
阻塞IO 非阻塞IO
无 选择器

第一点: IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据

当程序从硬盘往内存读取数据的时候,操作系统使用了 2 个“小伎俩”来提高性能,那就是预读,如果我读取了第一扇区的第三磁道的内容,那么你很有可能也会使用第二磁道和第四磁道的内容,所以操作系统会把附近磁道的内容提前读取出来,放在内存中,即缓存

(PS:以上过程简化了)

通过上面可以看到,操作系统是按块 Block从硬盘拿数据,就如同一个大脸盆,一下子就放入了一盆水。但是,当 Java 使用的时候,旧的 IO 确实基于 流 Stream的,也就是虽然操作系统给我了一脸盆水,但是我得用吸管慢慢喝。

第二点: 在以前的 Java IO 中,都是阻塞式 IO,NIO 引入了非阻塞式 IO,
阻塞IO 我从硬盘读取数据,然后程序一直等,数据读完后,继续操作。这种方式是最简单的,叫阻塞IO,
非阻塞式 IO 我从硬盘读取数据,如果数据还没准备好,然后程序继续向下执行,等数据读取完后,通知当前程序(对硬件来说叫中断,对程序来说叫回调),然后此程序可以立即处理数据,也可以执行完当前操作在读取数据。

传统的IO操作,比如read(),当没有数据可读的时候,线程一直阻塞被占用,直到数据到来。NIO中没有数据可读时,read()会立即返回0,线程不会阻塞,该线程可以去帮助其他文件连接读取数据。

传统的I/O需要为每个连接创建一个线程,当并发的连接数量非常巨大时,线程所占用的栈内存和CPU线程切换的开销将非常巨大。使用NIO,不再需要为每个线程创建单独的线程,可以用一个含有限数量线程的线程池,甚至一个线程来为任意数量的连接服务。由于线程数量小于连接数量,所以每个线程进行IO操作时就不能阻塞,如果阻塞的话,有些连接就得不到处理,NIO提供了这种非阻塞的能力。

第三点: 选择器(Selectors)
NIO中,客户端创建一个连接后,先要将连接注册到Selector, Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

0 0
原创粉丝点击