InputStream 与 OutputStream的实现

图片来自https://blog.csdn.net/huaweitman/article/details/50546459



FileInputStream与FileOutputStream

    用于处理文件输入流:

        

只测试简单使用:将文件内容读出

public class TestFileInputStream {

    public static void main(String[] args) {
        File file = new File("C:\\Users\\Administrator\\Desktop\\123.txt");

        InputStream inputStream = null ;
        try {
            inputStream = new FileInputStream(file);
            byte[] b = new byte[1024];
            int length;
            while(-1!=(length= inputStream.read(b))) {
                System.out.println(length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }   
        }
    }
}

测试文件写入:


public class TestFileOutputStream {

    public static void main(String[] args) {
        File infile = new File("C:\\Users\\Administrator\\Desktop\\123.txt");
        File outfile = new File("C:\\Users\\Administrator\\Desktop\\1234.txt");
        
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            inputStream = new FileInputStream(infile);
            outputStream = new FileOutputStream(outfile);
            int data = -1;
            while(-1 != (data = inputStream.read())) {
                outputStream.write(data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(inputStream!=null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outputStream!=null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

ByteArrayInputStream与ByteArrayOutputStream

    传入一个字节数组:

        

扫描二维码关注公众号,回复: 1652641 查看本文章

测试ByteArrayInputStream


public class TestByteArrayInputStream {
    public static void main(String[] args) {
        byte[] b = {'1','2','3','4','5','6','7','8','9'};
        InputStream inputStream = new ByteArrayInputStream(b,2, 4);
        try {
            inputStream.mark(10);
            inputStream.skip(5l);
            System.out.println(inputStream.available());
            inputStream.reset();
            System.out.println(inputStream.available());
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //关闭流
        }
    }
}

测试ByteArrayOutputStream

                

public class TestByteArrayOutputStream {
    public static void main(String[] args) {
        //从文件中读出,然后放入输出流数组中
        
        File file = new File("C:\\Users\\Administrator\\Desktop\\123.txt");
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally{
            //关闭流
        }
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
        int b;
        try {
            while(-1 != ( b = fileInputStream.read())) {
                arrayOutputStream.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //关闭流
        }
        System.out.println(arrayOutputStream.size());  //11780
         System.out.println(new String(arrayOutputStream.toByteArray()));
    }
    
}

这两个用于将对象序列化为流或者从流中读出。其中的方法众多,下面只是简单地写入文件与读取对象。

SerializableObject存储的对象


public class SerializableObject implements Serializable{

    /**
     * 序列化值
     */
    private static final long serialVersionUID = 3935244087027019945L;

    private String column1;
    
    private Integer column2;
    
    private transient int cloumn3;

    public int getCloumn3() {
        return cloumn3;
    }

    public void setCloumn3(int cloumn3) {
        this.cloumn3 = cloumn3;
    }

    public Integer getColumn2() {
        return column2;
    }

    public void setColumn2(Integer column2) {
        this.column2 = column2;
    }

    public String getColumn1() {
        return column1;
    }

    public void setColumn1(String column1) {
        this.column1 = column1;
    }

    @Override
    public String toString() {
        return "SerializableObject [column1=" + column1 + ", column2=" + column2 + ",cloumn3=" + cloumn3 +"]";
    }
}

简单的测试方法:


public class TestObjectInputStream {

    public static void main(String[] args) {
        SerializableObject object = new SerializableObject();
        object.setCloumn3(3);
        object.setColumn1("test");
        object.setColumn2(2);
        System.out.println(object.toString());
        //SerializableObject [column1=test, column2=2,cloumn3=3]

        //首先对象流需要输入到哪里
        File file = new File("C:\\Users\\Administrator\\Desktop\\123.txt");
        FileOutputStream fileOutputStream = null;
        ObjectOutputStream objectOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(file);
            objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(object);
            objectOutputStream.flush();
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                objectOutputStream.close();
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        FileInputStream fileInputStream = null;
        ObjectInputStream objIputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            objIputStream = new ObjectInputStream(fileInputStream);
            SerializableObject object1 = (SerializableObject) objIputStream.readObject();
            System.out.println(object1.toString());
            //SerializableObject [column1=test, column2=2,cloumn3=0]
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fileInputStream.close();
                objIputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
    }
}


PipedInputStream与PipedOutputStream

我们在线程A中向PipedOutputStream中写入数据,这些数据会自动的发送到与PipedOutputStream对应的PipedInputStream中,进而存储在PipedInputStream的缓冲中;此时,线程B通过读取PipedInputStream中的数据。就可以实现,线程A和线程B的通信。

​ 在PipedInputStream中维护了一个数组,该数组用于存放输入流中写入的数据,但是默认大小为1024,当缓冲区写满后,没有去读取,此时就会阻塞写入,所以当需要读取全部数据时,我感觉应该是个循环读。当缓存区没有数据时,此时去读会阻塞读,直到有数据写入。


/**
 * 用于两个线程间数据通信
 * @author zt
 *
 */
public class TestPipedStream {

    public static void main(String[] args) throws IOException {
        TestPipedStream pipedStream = new TestPipedStream();
        pipedStream.method2();
    }
    public void method2() throws IOException {
        //使用构造函数的方式连接输入与输出
        PipedInputStream inputStream = new PipedInputStream();
        PipedOutputStream outputStream = new PipedOutputStream(inputStream);
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println(inputStream.read());
                    //读不到数据时会一直等待
                    System.out.println(inputStream.read());
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    try {
                        outputStream.write(23);
                        Thread.sleep(2000);
                        outputStream.write(24);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
    
    /**
     * 从pipedOutputStream 写入 pipedOutputStream
     * @throws IOException
     */
    public void method1() throws IOException {
        PipedOutputStream pipedOutputStream = new PipedOutputStream();
        final PipedInputStream pipedInputStream = new PipedInputStream();
        //连接输入输出
        pipedOutputStream.connect(pipedInputStream);
        
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println(pipedInputStream.read());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    pipedOutputStream.write(22);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
    }
}

当同一个线程对管道进行读取和写入的时候可能会有问题,比如首先对管道进行读取,但是管道中此时没有数据,那么就会阻塞当前线程,之下的写入就无法执行了。例子如下:

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class TestPipedDeadLock {
    
    public static void main(String[] args) {
        PipedInputStream inputStream = new PipedInputStream();
        PipedOutputStream outputStream = new PipedOutputStream();
        try {
            inputStream.connect(outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            inputStream.read();
            outputStream.write('a');
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

查看此时执行状态:



SequenceInputStream

SequenceInputStream会将与之相连接的流集组合成一个输入流并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末 尾为止。 合并流的作用是将多个源合并合一个源。

​ 下面代码将两个文件流合并到一个文件中。


public class TestSequenceInputStream {

    public static void main(String[] args) {
        File infile1 = new File("C:\\Users\\Administrator\\Desktop\\123.txt");
        File infile2 = new File("C:\\Users\\Administrator\\Desktop\\1234.txt");
        File outfile = new File("C:\\Users\\Administrator\\Desktop\\12345.txt");
        
        FileInputStream fileInputStream1 = null;
        FileInputStream fileInputStream2 = null;
        FileOutputStream fileOutputStream = null;
        try {
            fileInputStream1 = new FileInputStream(infile1);
            fileInputStream2 = new FileInputStream(infile2);
            fileOutputStream = new FileOutputStream(outfile);
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        }
        //注意 Enumeration 的创建
        Enumeration<InputStream> e = null;
        Vector<InputStream> vector = new Vector<InputStream>();
        vector.add(fileInputStream1);
        vector.add(fileInputStream2);
        e = vector.elements();
        SequenceInputStream sequenceInputStream = new SequenceInputStream(e);
        
        byte[] b = new byte[2];
        int len = -1;
        try {
            while(-1 != (len = sequenceInputStream.read(b))) {
                fileOutputStream.write(b, 0, len);
            }
        } catch (IOException e1) {
            e1.printStackTrace();
        }finally {
            try {
                sequenceInputStream.close();
                fileInputStream1.close();
                fileInputStream2.close();
                fileOutputStream.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }
}

​StringbufferInputStream

    在此处使用了@Deprecated进行标注,表明是可能废弃的类。

        


public class TestStringBufferInputStream {

    @SuppressWarnings("deprecation")
    public static void main(String[] args) {
        StringBufferInputStream bufferInputStream = new StringBufferInputStream("123456789");
        
        System.out.println(bufferInputStream.available()); //9
        bufferInputStream.read();
        bufferInputStream.read();
        System.out.println(bufferInputStream.markSupported()); //false
        System.out.println(bufferInputStream.available()); //7
        bufferInputStream.reset();
        System.out.println(bufferInputStream.available()); //9
    }
}

FilterInputStream与FileterOutputStream

    这个类继承自InputStream并且持有一个InputStream对象,在这个类中的方法分别去调用持有的in的方法。这个类不是为了直接使用,而是为了使用它的子类比如BufferedInputStream等为持有的in对象动态的添加一些方法。这是一种装饰者模式

                

BufferedInputStream与BufferedOutputStream

    为输入流添加markreset方法,该类是线程安全的,其中使用了AtomicReferenceFieldUpdater,具体的使用方式,希望可以在后面的多线程的使用中讲解



/**
 * A <code>BufferedInputStream</code> adds
 * functionality to another input stream-namely,
 * the ability to buffer the input and to
 * support the <code>mark</code> and <code>reset</code>
 * methods. When  the <code>BufferedInputStream</code>
 * is created, an internal buffer array is
 * created. As bytes  from the stream are read
 * or skipped, the internal buffer is refilled
 * as necessary  from the contained input stream,
 * many bytes at a time. The <code>mark</code>
 * operation  remembers a point in the input
 * stream and the <code>reset</code> operation
 * causes all the  bytes read since the most
 * recent <code>mark</code> operation to be
 * reread before new bytes are  taken from
 * the contained input stream.
 *
 * @author  Arthur van Hoff
 * @since   JDK1.0
 */
public
class BufferedInputStream extends FilterInputStream {
    .......
}

BufferedInputStream示例:


public class TestBufferedInputStream {
    
    public static void main(String[] args) {
        byte[] buf = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buf);
        
        BufferedInputStream bufferedInputStream = new BufferedInputStream(byteArrayInputStream, 5);
        
        System.out.println(bufferedInputStream.markSupported()); //true
        try {
//          bufferedInputStream.read();
//          bufferedInputStream.mark(4);
//          bufferedInputStream.skip(12);  //最大只能跳过当前可读的大小,也就是当前跳过了4个
//          System.out.println(bufferedInputStream.read());//5
//          System.out.println(bufferedInputStream.read());//6
//          bufferedInputStream.reset(); // java.io.IOException: Resetting to invalid mark

            bufferedInputStream.read();
            bufferedInputStream.mark(2);
            System.out.println(bufferedInputStream.read());//1
            System.out.println(bufferedInputStream.read());//2
            System.out.println(bufferedInputStream.read());//3
            bufferedInputStream.reset(); 
            System.out.println(bufferedInputStream.read());//1
            
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //关闭流
        }
        
    }
}

BufferedOutputStream


public class TestBufferedOutputStream {

    public static void main(String[] args) {
        
        byte[] in = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
        
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(arrayOutputStream);
        try {
            bufferedOutputStream.write(in);
            bufferedOutputStream.flush(); //此处需要调用,否则可能输出为空
            System.out.println(new String(arrayOutputStream.toByteArray(),"UTF-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //关闭流
        }
        
    }
}

      

DataInputStream与DataOutputStream

 允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。也就是说按照字节来读取,但是如果想要读取 int 类型,此时就读取4个字节,然后转换成 int 类型。如果是 long 那就读取8个字节。写入是一样的道理。

        

我在网上看到的感觉写的相当不错的关于这二者讲解:http://www.cnblogs.com/skywang12345/p/io_14.html


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

public class TestDataStream {

    public static void main(String[] args) {
        //先将一些东西写入字节数组中
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
        DataOutputStream dataOutputStream = new DataOutputStream(arrayOutputStream);
        try {
            dataOutputStream.writeInt(100);
            dataOutputStream.writeUTF("我");
            dataOutputStream.writeDouble(2.14d);
            dataOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //关闭流
        }
        byte[] btn = arrayOutputStream.toByteArray();
        
        System.out.println(btn.length);
        System.out.println(new String(btn));
        //从字节数组中获取然后输出
        ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(btn);
        DataInputStream dataInputStream = new DataInputStream(arrayInputStream);
        try {
            System.out.println(dataInputStream.readInt());  //100
            System.out.println(dataInputStream.readUTF()); //我
            System.out.println(dataInputStream.readDouble()); //2.14
            System.out.println(dataInputStream.readDouble()); //java.io.EOFException
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            //关闭流
        }
        
    }
}

LineNumberInputStream

可以获取当前的行号。开始read时多去读取一个字符,将这个字符存起来,判断这个字符是否到了行尾部。也是标注为被废弃。

            

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.LineNumberInputStream;O

public class TestLineNumberInputStream {

    public static void main(String[] args) {
        File file = new File("C:\\Users\\Administrator\\Desktop\\123.txt");
        
        byte[] buf = new byte[4096];
        FileInputStream fileInputStream = null;
        LineNumberInputStream lineNumberInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            lineNumberInputStream = new LineNumberInputStream(fileInputStream);
            lineNumberInputStream.read(buf);
            System.out.println(lineNumberInputStream.getLineNumber());
        } catch (IOException e1) {
            e1.printStackTrace();
        }finally {
            if(null != fileInputStream) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null != lineNumberInputStream) {
                try {
                    lineNumberInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
        }
        
    }
}

PushBackInputStream

        回退流,在JAVA中提供了一种回退输入流(PushbackInputStream、PushbackReader),维护了一个数组,将数据缓存在数组中,读取过某个位置的数据后,可以在那个位置回设数据。

                    

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PushbackInputStream;

public class TestPullBackInputStream {

    public static void main(String[] args) {
        byte[] buf = {1,2,3,4,5,6,7,8,9};
        ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(buf);
        
        PushbackInputStream pushbackInputStream = new PushbackInputStream(arrayInputStream, 3);
        
        try {
            //读取7个byte
            pushbackInputStream.read();
            pushbackInputStream.read();
            pushbackInputStream.read();
            pushbackInputStream.read();
            pushbackInputStream.read();
            pushbackInputStream.read();
            pushbackInputStream.read();
            //回设3个
            pushbackInputStream.unread(10);
            pushbackInputStream.unread(11);
            pushbackInputStream.unread(12);
            
            System.out.println(pushbackInputStream.read()); //12
            System.out.println(pushbackInputStream.read()); //11
            System.out.println(pushbackInputStream.read()); //10
            System.out.println(pushbackInputStream.read()); //8
            
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //关闭流
        }
    }
}

PrintStream

PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,可以创建一个 PrintStream;这意味着可在写入byte 数组之后自动调用 flush 方法,可调用其中一个 println 方法,或写入一个换行符或字节 ('\n')。 PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。

我认为PrintStream相当于一种转换,将字节转换为字符。比如当前输出流是字节流,但是我想要在其中插入一个浮点型数字,此时就需要找到这个字符对应的字节码然后写入,有了PrintStream之后就可以直接写入了。        

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;

public class TestPrintStream {

    public static void main(String[] args) {
        PrintStream printStream = null;
        FileInputStream fileInputStream = null;
        int b = -1;
        try {
            FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\1234.txt");
            fileInputStream = new FileInputStream("C:\\Users\\Administrator\\Desktop\\123.txt");
            printStream = new PrintStream(fileOutputStream);
            while(-1 != (b=fileInputStream.read())) {
                printStream.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭流
        }
        printStream.println();
        printStream.println("123");
        printStream.println(12.123f);
        printStream.println(13.2d);
        printStream.println(14);
        
    }
}

输出结果:

        

猜你喜欢

转载自blog.csdn.net/baidu_14922873/article/details/80643543