Java IO

javaIO使用最多的就是 装饰模式:《java与模式》-13 装饰模式
java.io.InputStream

/**
 * java字节输入流的顶级抽象
 */
public abstract class InputStream implements Closeable {
    //skip()最大可以跳过的字节数
    private static final int MAX_SKIP_BUFFER_SIZE = 2048;
    //读一个字节并以int格式返回
    public abstract int read() throws IOException;
    //读满一个数组并返回读取到的个数
    public int read(byte b[]) throws IOException;
    //读取
    public int read(byte b[], int off, int len) throws IOException;
    //跳过n个字节
    public long skip(long n) throws IOException;
    //返回能读取的字节数
    public int available() throws IOException;
    //关闭流
    public void close() throws IOException;
    //做标记 读取readlimit个字节后失效
    public synchronized void mark(int readlimit);
    //回到标记的地方
    public synchronized void reset();
    // 是否允许做标记回到原来的地方
    public boolean markSupported();
}

java.io.OutputStream

//java字节流输出流顶级抽象
public abstract class OutputStream implements Closeable, Flushable {
    //从内存写一个字节到流中
    public abstract void write(int b) throws IOException;
    //从内存写一个字节数组到流中
    public void write(byte b[]) throws IOException;
    //从内存写一个字节数组到流中 从off开始写len个
    public void write(byte b[], int off, int len) throws IOException ;
    //将缓冲区的数据刷新到流中
    public void flush() throws IOException ;
    //关闭输出流
    public void close() throws IOException {
    }
}

java.io.Reader

//字符流顶级抽象
public abstract class Reader implements Readable, Closeable {
    //锁
    protected Object lock;
    //构造
    protected Reader();
    //构造
    protected Reader(Object lock);
    //读取字符到CharBuffer并返回读到的字符个数
    public int read(java.nio.CharBuffer target) throws IOException ;
    //读取一个字符并转为int返回
    public int read() throws IOException;
    //读满一个字符数组
    public int read(char cbuf[]) throws IOException ;
    //读取len个字符存在数组中 从off开始存,返回读取到的数量
    abstract public int read(char cbuf[], int off, int len) throws IOException;
    /** skip()最大可以跳过的字符数 */
    private static final int maxSkipBufferSize = 8192;
    //skip()跳过的这段放在skipBuffer数组中
    private char skipBuffer[] = null;
    //跳过n个字符
    public long skip(long n) throws IOException{}
    //告知此流是否已准备就绪。
    public boolean ready() throws IOException{}
    //当前类是否可以做标记
    public boolean markSupported() ;
    // 做标记 在读取readAheadLimit个字符之前标记有效
    public void mark(int readAheadLimit) throws IOException;
    //回到做标记的位置
    public void reset() throws IOException ;
    //关闭流
     abstract public void close() throws IOException;
}

java.io.Writer

//字符输出流顶级抽象
public abstract class Writer implements Appendable, Closeable, Flushable {
    //用于保存字符串和单个字符的写入的临时缓冲区
    private char[] writeBuffer;
    //缓冲区的大小, 必须 >= 1
    private static final int WRITE_BUFFER_SIZE = 1024;
    //锁
    protected Object lock;
    //构造
    protected Writer();
    //构造
    protected Writer(Object lock);
    //写一个 int 转为字符 到流中
    public void write(int c) throws IOException;
    //写一个字符数组到流中
    public void write(char cbuf[]) throws IOException ;
    //写一个字符串到流中,如果缓冲区不够保存这个str会以str的长度新建一个数组
    public void write(String str) throws IOException;
    //写一个字符串到流中,从str的off开始写len个字符
    public void write(String str, int off, int len) throws IOException ;
    //追加字符序列到流中
    public Writer append(CharSequence csq) throws IOException;
    //追加字符序列到流中
    public Writer append(CharSequence csq, int start, int end) throws IOException;
    //追加字符到流中
    public Writer append(char c) throws IOException;
    //刷新缓冲区,将缓冲区的数据写入流中
    abstract public void flush() throws IOException;
    //关闭流
    abstract public void close() throws IOException;
}

源文章
* InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
* OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
这里写图片描述
输出流一定记得 flush();
finalize
java.lang.Object#finalize 这个方法是垃圾回收的时候调用的方法;
java.io.FileOutputStream#finalize和java.io.FileInputStream#finalize重写了这个方法,所以如果你忘记关闭,最终垃圾回收的时候也会关闭资源,但是垃圾回收的时间不确定

    // FileOutputStream的源码
    protected void finalize() throws IOException {
        if (fd != null) {
            if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
            //如果是标志输出流,或错误输出流就调用flush
                flush();
            } else {
                //其它流就关闭
                close();
            }
        }
    }

java IO 的使用
java7还有一种写法 try-with-resources

        /**
         * try-with-resources java7支持,
         * 当执行离开测试块时,这两种资源将自动关闭。
         * 可以不用写catch 和 finally
         * 但是必须在 try( 这里 ) 定义变量并为变量赋值
         */
        try (OutputStream o1 = new BufferedOutputStream(new FileOutputStream(outpath));
             InputStream in1 = new BufferedInputStream(new FileInputStream(outpath))) {
            DataOutputStream dos = new DataOutputStream(o1);
            dos.writeBoolean(true);
            dos.writeFloat(0.1F);
            dos.flush(); //将缓存中的数据写入流中
            DataInputStream din = new DataInputStream(in1);
            System.out.println(din.readBoolean());
            System.out.println(din.readFloat());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //因为正常关闭流比较恶心
        OutputStream o = null;
        InputStream in = null;
        try {
            o = new BufferedOutputStream(new FileOutputStream(outpath));
            DataOutputStream dos = new DataOutputStream(o);
            dos.writeBoolean(true);
            dos.writeFloat(0.1F);
            dos.flush();
            in = new BufferedInputStream(new FileInputStream(outpath));
            DataInputStream din = new DataInputStream(in);
            System.out.println(din.readBoolean());
            System.out.println(din.readFloat());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (o != null)
                    o.close();
                if (in != null)
                    in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
       /**
         * 将对象序列化后写入管道,另一个线程来读取管道中的数据
         * PipedOutputStream(数据从这里写入管道) ---(管道)---> PipedInputStream(读取管道中的数据)
         * 实际上PipedOutputStream的write是写入了PipedInputStream缓存中(字节数组buffer[])
         * 这样反序列化出来的对象是一个新的对象
         */
        PipedOutputStream po = new PipedOutputStream();
        PipedInputStream pi = new PipedInputStream(po);
        Thread to = new Thread(new Runnable() {
            @Override
            public void run() {
                try (ObjectOutputStream o = new ObjectOutputStream(po)){
                    User s = new User();
                    o.writeObject(s);
                    o.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread ti = new Thread(new Runnable() {
            @Override
            public void run() {
                try(ObjectInputStream i = new ObjectInputStream(pi)) {
                    // 这里会阻塞直到有数据传过来
                    User s = (User) i.readObject();
                    System.out.println(s);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        });
        to.start();
        ti.start();
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        //写入到ByteArrayOutputStream的缓存中
        bs.write("hfdjasdhkfja".getBytes("UTF-8"));
        byte[] b = bs.toByteArray();
        ByteArrayInputStream bi = new ByteArrayInputStream(b);
        int i = -1;
        while ((i = bi.read()) > 0) {
            System.out.print((char) i);
        }
        bs.close();
        bi.close();

句柄

Java IO Stream句柄泄露分析
java.io.FileDescriptor
  是一个用于表述指向文件的引用的抽象化概念。在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。
  基于上面filedescriptor在java中,是当应用程序打开一个文件或者建立一个socket连接的时候,内核返回给应用程序一个非负的整数(In,out,err,分别为0,1,2),使用这个称之为filedescriptor的东西来实现对文件或者socket的操作。
   打开文件或者socket之后给你一个fd,然后你可以拿着fd去操作文件或者socket,也可以把这个fd做为参数传来传去。你不能把文件或者socket“本身”作为一个参数传给一个函数吧,传fd就可以,因为它就是一个类似指针的东西。函数里面就根据这个fd对这同一个文件或者已经建立的socket连接进行操作。
之所以socket和文件都有fd的原因是都可以在上面做打开,关闭,读,写等等操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值