zoukankan      html  css  js  c++  java
  • 理解IO_InputStream我们到底能走多远系列(16)

    我们到底能走多远系列(16)

    扯淡: 

      我觉得不断的重复学习基础才是成长的关键。可能有一天我们拥有几十个框架的经验,可是却一个组件也无法设计一下,应该算不是很好吧。

    主题:

    知识点:

    1.byte 类型

    Java byte 类型的取值范围是-128~127

      byte是1个字节,也就是8位

      最高位是符号位,其它七位来表示它的值

      最大的应该是0111 1111,因为第一位是符号位,0表示正数。0111 1111即127

      负数部分是由补码体现的,补码的是绝对值,取反,加上符号位,加1。

      -1表示:1000 0001 它的补码是:1111 1111。

      1000 0000 也就是数字-128


    2,java的IO中衍生出这么多类,主要是因为使用了装饰模式,这种模式是在调用对象的构造函数把被装饰对象传入,利用这样的方式实现的。

    具体可以参照:简单的装饰模式解释

    3,IO结构可以参照:容易理解的IO图

    IO是java基础

    来自《learning java》的图:

    java源码中涉及都IO的有很多类,可能是学习的障碍,有时候我会烦恼到底用哪个stream才是正确的呢?这也是本文需要解决的问题:如何去学习IO类呢?

    我们来看下IO的基本类图:

    我需要牢牢抓住的就是4个主类:InputStream,OutputStream,Reader,Writer,这里我只学习下InputStream,这样OutputStream也可以解决了。

    所有在InputStream下面的类都是为了配合一种流,也就可以理解为什么要衍生出这么多类了,毕竟数据流的类型太多了。

    来看下InputStream的三个read方法源码:

    有一点好记,所有的read方法返回-1就算读完啦。

    InputStream 中的read()方法:一个抽象方法,让子类实现去了。

    public abstract int read() throws IOException;

    read(byte b[])方法:

    public int read(byte b[]) throws IOException {
        // 调用了read(byte b[], int off, int len)
        return read(b, 0, b.length);
    }

    read(byte b[], int off, int len)方法:

    看下它的API:

    将输入流中最多 len 个数据字节读入字节数组。尝试读取多达 len 字节,但可能读取较少数量。以整数形式返回实际读取的字节数。
    在输入数据可用、检测到流的末尾或者抛出异常前,此方法一直阻塞。
    如果 b 为 null,则抛出 NullPointerException。
    如果 off 为负,或 len 为负,或 off+len 大于数组 b 的长度,则抛出 IndexOutOfBoundsException。
    如果 len 为 0,则没有字节可读且返回 0;否则,要尝试读取至少一个字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;否则,至少可以读取一个字节并将其存储在 b 中。
    将读取的第一个字节存储在元素 b[off] 中,下一个存储在 b[off+1] 中,依次类推。读取的字节数最多等于 len。让 k 为实际读取的字节数;这些字节将存储在元素 b[off] 至 b[off+k-1] 之间,其余元素 b[off+k] 至 b[off+len-1] 不受影响。
    在任何情况下,元素 b[0] 至 b[off] 和元素 b[off+len] 至 b[b.length-1] 都不会受到影响。
    如果不是因为流位于文件末尾而无法读取第一个字节,则抛出 IOException。特别是,如果输入流已关闭,则抛出 IOException。

    public int read(byte b[], int off, int len) throws IOException {
        // 对参数进行check,写方法前要确定输入和输出,对于输入的限制是必要的
        if (b == null) {
            throw new NullPointerException();
        } else if ((off < 0) || (off > b.length) || (len < 0) ||
               ((off + len) > b.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }
        // 内部实现还是使用read()方法一个一个去读的
        int c = read();
        if (c == -1) { // 1
            return -1;
        }
        // 第一个放置的位置
        b[off] = (byte)c;
        int i = 1;
        try {
            for (; i < len ; i++) {
            c = read();
            if (c == -1) {// 2
                break;
            }
            if (b != null) {
                // 第二个以后的就在off后面进位
                b[off + i] = (byte)c;
            }
            }
        } catch (IOException ee) {
        }
        // 返回的是i,举个例子:比如我每次去1024个byte,那么到最后的时候剩下200个byte,
        // 取到201个的时候,上面的1处判断出来,break;后就返回了i
        // 需要再一次调用的时候,在1出判断返回-1,才通知没有数据了
        // 所以呢,如果数据可以分为5段byte数组取,就要进这个方法6次啦。
        return i;
        }

    FileInputStream类用来对付文件流的,可以这么想把它可以把一个文件变成InputStream。

    来看下它的read()方法:

    public native int read() throws IOException;

    好吧,都到native了,(native方法是指本地方法,当在方法中调用一些不是由java语言写的代码或者在方法中用java语言,直接操纵计算机硬件时要声明为native方法,java中,通过JNI(Java Native Interface,java本地接口)来实现本地化)
    据说是交给c库实现了...

    关于它的使用比较常见吧:

    以前写的拷贝的方法:

        private void copyFile(String fromPath, String toPath) throws IOException {
            // input
            File fromFile = new File(fromPath);
            InputStream is = new FileInputStream(fromFile);
            BufferedInputStream bis = new BufferedInputStream(is);
            // output
            File toFile = new File(toPath);
            OutputStream os = new FileOutputStream(toFile);
            BufferedOutputStream bos = new BufferedOutputStream(os);
            // transfer station
            byte b[] = new byte[(int) fromFile.length()];
            while (bis.read(b, 0, b.length) != -1) {
                bos.write(b, 0, b.length);
            }
            bis.close();
            bos.close();
        }

    DataInputStream类是来对付读取基本 Java 数据类型的。

    它有:

    readBoolean()
    readByte()
    readChar()
    readDouble()
    readFloat()
    

    FilterInputStream下面两个重要的派生类:

    ByteArrayInputStream是为了把内存中的数据读到字节数组中。

    网上共享的代码:是DataInputStream结合ByteArrayInputStream的使用

    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    
    public class ByteArrayTest {
        public static void main(String[] args) throws IOException {
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            DataOutputStream dout = new DataOutputStream(bout);
            String name = "dc";
            int age = 94;
            dout.writeUTF(name);
            dout.writeInt(age);
            byte[] buff = bout.toByteArray();// byte数组作为中间值了
            ByteArrayInputStream bin = new ByteArrayInputStream(buff);
            DataInputStream dis = new DataInputStream(bin);
            String newName = dis.readUTF();
            int newAge = dis.readInt();
            System.out.println(newName + ":" + newAge);
        }
    }

    类似上面一层层包着的感觉提供张图更直观:

    我们甚至可以一层层的装饰下去。

    BufferedInputStream 可以说是装饰了内存缓存的功能。详细可以点我

    总结:

    1,通过查看他们的源码,我渐渐明白其实也不是那么复杂,各自的类都有自己的使命,我们只要可以理解他们各自的作用,使用起来就不那么迷茫了。

    2,对装饰模式的理解,可以设计出灵活的东西

    ------------------------------------------------


    偶然选了首《掌声响起来》听,“孤独站在这舞台...”,

       打开记忆大门钥匙也许是一首歌,也许是一句话,也许是一个人。

       歌声伴随我们成长,也许那些甜蜜的情歌早被遗忘,而那些曾经塑造过我们的歌曲将伴随你我更久。

       时光弹指,请珍惜,请把握,请坚持。

    让我们继续前行

    ----------------------------------------------------------------------

    努力不一定成功,但不努力肯定不会成功。
    共勉。

    1000 0000代表的就是-1
  • 相关阅读:
    几个新角色:数据科学家、数据分析师、数据(算法)工程师
    人类投资经理再也无法击败电脑的时代终将到来了...
    Action Results in Web API 2
    Multiple actions were found that match the request in Web Api
    Routing in ASP.NET Web API
    how to create an asp.net web api project in visual studio 2017
    网站漏洞扫描工具
    How does asp.net web api work?
    asp.net web api history and how does it work?
    What is the difference between a web API and a web service?
  • 原文地址:https://www.cnblogs.com/killbug/p/2776384.html
Copyright © 2011-2022 走看看