轻松 Java IO

      android 文件 IO,当然也是 Java IO。廖廖几百字,来说清楚文件 IO 到底是什么。通过对一些基本概念的理解以及 Java IO 中其他的一些必要性知识的理解,来透彻的理解 Java IO.

1.字节,字符,与字符编码与文件编码的关系

字节:代码里表示就是 byte

字符:代码里单独表示就是 char,byte 不能表示一个字符。

字符编码:字符要用多少个字节表示,以包括如何表示。就是传说中的 utf-8,ansi,utf-16be,gbk 等

文件编码:也就是文件存储时采用何种字符编码。存储时采用何种编码,那读取时也必须采用相应的编码。否则在碰到非英文字符的时候,就会碰到不怀好意的乱码问题。

理解了上面的概念,也就是理解了,为什么 Java 的 IO 会区分字节流与字符流了。

2.一般的流

      可以这么说,最基本的字节流分别是 读 - FileInputStream(FileWriter) ,写 - FileOutputStream (FileReader)。这两个类可以理解是真正与 “文件 - File” 发生关系的。这两个类中包含了更底层的 IO 处理,例如调用 IoBridge.open(),IoBridge.read(),IoBrige.write()以及IoBridge.closeAndSignalBlockedThreads()等桥接方法调用。而这些底层的类又是通过更底层的 Posix 类,再通过 JNI 调用到 C 层实现(C 层并没有用 C语言的fread()等函数,而是直接调用的系统调用 read()),最后实现文件的读与写等文件相关的操作。所以流是对底层IO相关的系统调用的一个细节封装。

    Java中定义了流的概念,输入流或者输出流,且不可逆不可任意跳转,从源码上来看都是出于设计上的考量。参考 RandomAccessFile 的实现,其之所以能够随机访问文件,其实就是通过调用了 Libcore.os.lseek() 来实现。当然,普通的流也有调用到 Libcore.os.lseek(),就是 skip()方法,而没有像 RandomAccessFile 一样提供了上层的 seek() 方法。

3.装饰的流

    为了大家使用上的方便,如读一个 int 需要分成 4 个字节去读,并且做一次计算,Java中提供了 DataInputStream/DataOutputStream,其就是装饰了一下,底层的文件 IO 操作均是由 FileInputStream/FileOutStream 来实现的。

public final int readInt() throws IOException {
387        // b/30268192
388        // Android-changed: Use read(byte[], int, int) instead of read().
389        readFully(readBuffer, 0, 4);//读 4 个字节
390        return Memory.peekInt(readBuffer, 0, ByteOrder.BIG_ENDIAN);//将 4 个字节转换成 Int 值
391    }


/**
* 分大小端转成 Int
**/
public static int peekInt(byte[] src, int offset, ByteOrder order) {
46        if (order == ByteOrder.BIG_ENDIAN) {
47            return (((src[offset++] & 0xff) << 24) |
48                    ((src[offset++] & 0xff) << 16) |
49                    ((src[offset++] & 0xff) <<  8) |
50                    ((src[offset  ] & 0xff) <<  0));
51        } else {
52            return (((src[offset++] & 0xff) <<  0) |
53                    ((src[offset++] & 0xff) <<  8) |
54                    ((src[offset++] & 0xff) << 16) |
55                    ((src[offset  ] & 0xff) << 24));
56        }
57    }

BufferedInputStream/BufferedOutputStream 就更简单了,就是在 IO 前先将数据存入或者写出到byte[] buffer 中,外加一个 count 计数器记录下写入与写出的字节个数。而真正与文件发生 IO 的还是 FileInputStream/FileOutputStream

BufferedWriter/BufferedReader 是类似的,只不过它的 buf 是 char[] ,而不是 byte[]。同时,它也用了一个 pos 作为下标计数器。

4.PipedInputStream/PipedOutputStream

    管道流,单独放在最后讲,并不是因为它有多么的高大上,因为惭愧的是,我在实际编码当中从来没有用到过。但这两个类所涉及的设计思想非常值得我们学习。

作用:用于两个不同的线程之间进行通信

文件IO:这两个类是没有文件 IO 的。写入读出都是在同一个 byte[] buffer 内

封装:PipedOutputStream 封装了 PIpedInputStream,PipedInputStream 封装了 byte[] buffer

buffer:这是一个循环 buffer ,分别用了 in 表示下一个要写的位置,out 表示下一个要读的位置。读的最大范围为 [out,int) 左闭右开区间,写的最大范围为 [in,out)

    in 为 -1 表示空 buffer,读线程阻塞等待

    in == empty 表示 buffer 满,写线程阻塞等待

但需要注意的是,不管是读待还是写等待,最多只会等 3 秒钟,且是每隔一次一秒的。

小结

    Java 中还有一些其他相关的流,如 PrintStream/PrintWriter ,其也就是多了一些封装帮助我们更方便更快捷的完成代码编写,从而摒弃一些复杂的运算,专心处理业务逻辑即可。

    Java IO 的知识点还很多,上面都是一些最基础的东西,但掌握了上面这些比较基础的东西,那其他复杂的东西也就容易掌握了。

    Java 还有一类 IO 称为 NIO,其主要目的是为了超大文件,复用IO的异步读写。NIO 的三要素为 Channel,Buffer,Selector。先知道有这么几个东西吧。

 

 

转载于:https://my.oschina.net/u/217380/blog/1518968

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值