DataInputStream
来源:互联网 发布:2017年淘宝客市场规模 编辑:程序博客网 时间:2024/05/29 09:15
DataInputStream 用途
DataInputStream 与 BufferedInputStream 一样,继承自 FilterInputStream ,它提供了对流进行数据读写的功能:支持从流中直接读出 int ,long , double ,utf8 等等功能。下面谈一下它的一些实现细节。
读取 int , long
无论32位还是64位机器/编译器下,int 都是32位,long 都是 64 位,那么从流中读取一个 int ,一个 long 应该会这样实现:
对于 readInt 的实现是没有问题的,但是 readLong 呢?主要有两个问题:
1.缺陷:循环内部,每个 b 都是一个字节,八位;而 b&0xffff表示取 b 的低 16 位(如果有多于或等于 16 位的话)。因此,这里使用 b & 0xff 就足够了,不需要使用 0xffff。
2.错误:(b&0xffff)<<(leftBits-=8)这句表示将 b 的低八位左移 leftBits-8 位,而编译器并不知这个值应该被保存为 long 型。实际上,此值被编译器默认为保存为 int ,所以当左移后对应的值超出了 int 表示范围则无法得到正确的值,故正确的写法应该是:
读取 utf
DataInputStream 读取 utf8 流(方法 readUTF)是这样实现的:
1.读取流开头的两个字节作为无符号整数,此值表示后面有效的 utf 字节流总个数;
2.继续往后读 utf 字节流,按 utf-8 编码规则反解析得到字符;
这里可能会觉得很奇怪,readUTF 为什么取出开头两字节作为流长度呢?这其实是 DataOutputStream.writeUTF 决定的:
在写入字符串时,先取出每个字符,根据每个字符的编码值大小求得需要几个字节存储该编码值(如 [0 ,127] 需要一个字节,[128 , 0x07FF] 两字节,(0x07FF , ?) 三字节),累计得到需要写入的 utf8 字节流的长度,作为两个字节写入。再边转化每个字符边写入。摘录代码如下:
所以,DataInputStream 与 DataOutputStream 配套使用才能保证正确性。
这里有几个问题:
1).2 字节保存字节流长度是否显得不够 ?
2). 为什么写 utf8 字节流需要保存长度?这样做的动机是什么?
3). 上面 DataOutputStream 的 writeUTF 的实现中,为什么不直接使用 String.getByte 方法获得 utf8 字节流呢?
一一回答之:
1). 2 字节保存字节流长度确实略显不够,但是 writeUTF 的实现中已经限制了写入的 utf8 字节流的长度不大于65535。这是两个字节表示无符号整数的范围。所以程序的逻辑是没有问题的。那么,如果我非要写入长度大于 65535 的 utf8 字节流呢?那就可以连续多次调用 writeUTF ,分多次写入,这样就能写入任意长度的 utf8 字节流。这有一个意想不到的好处:隔离字节流。
2). 实际上,在 1) 中已经回答了这个问题,保存长度有一个作用,就是当往流存储器(如文件)写入多次 utf8 流时这就相当有用了:可以分多次读出这些流。由于每次写入字节流时都在前面附加了字节流的长度,所以每次读出时使用这个长度往后读字节流能够保证正确性。另外,还有一个好处,设想,有一个流存储器无法很快速地得到它里面存放的字节流的总长度:可以通过遍历字节流取得总长度,然而,更快的做法是读出流最前面的两个字节即是!
3). 主要是性能问题没有使用 String.getByte 方法。String.getByte 是一个"综合性"的方法,它可以取出任意编码的字符串的字节流,它使用了很多的类,如 StringCoding,StringEncoder,CharBuffer,ByteBuffer,等等,而且实现的比较复杂。而 writeUTF 中使用最本质最底层的方法,可以预计 String.getByte 方法获得 utf8 字符串的字节流的最底层必然也会有这样的方法,writeUTF 使用的方法必然要比层层包裹下的实现更为高效。
读一行 readLine
该方法是从字节流中读出一行,返回字符串。该方法已经被 deprecated。我们先看它的实现:
遍历读(read)字节流中的每一个字节放入缓存数组 buf,如果 buf 满了,则对 buf 扩充 128 个字节,再拷入原 buf 数组。对当前读入的字节做如下处理:
1). 判断如果是 \n 则直接将读到的字节流构成 String 并返回。
2). 如果是 \r 则读下一个字节,如果是 \n 按 1) 方式返回;否则将读到的这个非 \n 字节压入字节流(PushbackInputStream.unread)以期望下次继续读。
该实现有两个问题:
1).比较低效:一次一次地调用 read 方法:对于读文件而言,每一个 read 就是一个系统调用,十分耗费时间。上面的实现使用了128 作为缓存长度,其实可以每次读128个字节流,判断这个流里面有没有 \r 或者 \n:
如果有,则直接返回 \r\n 或 \r 或 \n 前面的字节流,且移动流读取指针的位置指向 \r\n 或 \r 或 \n 的后面一个字节。如果没有则继续向后读 128 个字节流。如此循环。
2). 实现有错误:没有兼顾字节流的编码,对于非 asscii 编码的字节流无法正确解析。如 UTF8 编码下,一个字符可能占三个字节,而 readLine 的处理方式是一个字节一个字节地将原三个字节读散了,于是这三个字节代表的语义被充分误解了:原来代表一个字符,结果现在强行被代表三个字符,这显然是不正确的!因为这一点,该方法被抛弃了。在实现的源代码里面,作了这样的注释:尽量使用 BufferedReader 的 readLine 方法。此类此方法待时再作分析。
- DataInputStream
- DataInputStream
- DataInputStream
- DataInputStream
- BufferedReader、DataInputStream
- DataOutputStream、DataInputStream
- DataInputStream/DataOutputStream
- DataInputStream api
- DataInputStream 的readInt 算法
- DataInputStream读取二进制文件
- DataInputStream/DataOutStream增加读写
- DataInputStream和DataOutputStream类
- DataInputStream和DataOutputStream
- DataInputStream和DataOutputStream
- InputStream与DataInputStream区别
- DataInputStream与DataOutputStream类
- InputStream与DataInputStream区别
- DataOutputStream与DataInputStream
- MySQL分片水很深
- 快速漂亮的找出Linux下的大文件
- java synchronized的理解以及内置锁和对象锁
- c#之字符串的不可变性
- 【C#之值类型vs引用类型】
- DataInputStream
- 欢迎使用CSDN-markdown编辑器
- 用Unity3d的maxtrix实现的WolrdToScreen
- 时序约束之相关概念
- 使用 @RequestMapping 映射请求
- 不允许连续点击()两种方法()
- OPENGL 纹理贴图 过滤 mipmaps (shader)
- javascript
- 使用FileZilla Ftp 客户端工具上传vxWorks镜像的注意事项