在JAVA中如何将输出流转为输入流的类的实现

问题背景

在实际应用中,我们会碰的一个功能的输出的字节流,是另一个功能输入字节流的情况。一般情况下,我们可以使用ByteArrayOutputStream和ByteArrayInputStream实现相应的功能。
来看下面的测试代码:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

public class ByteArrayTest {
    
    public static void main(String[] argv) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        
        PrintWriter ps = new PrintWriter(output);
        
        for (int i = 0; i < 1000; i++) {
            ps.printf("This is line %d\n", i);
        }
        ps.close();
        
        ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
        
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = input.read(buffer)) > 0) {
            System.out.write(buffer, 0, len);
        }
        input.close();
    }
}

在上面的代码中,我们通过ByteArrayOutputStream对象把输出转换为字节数组,在通过ByteArrayInputStream对象把字节数组转换为输入流。
当需要转换的字节流比较小时,上面的方法是一个简便的且行之有效的方法,然而当字符流比较大时,上面的代码会消耗大量的内存,甚至可能出现内存溢出的情况。

解决方法

为解决上一节提出的问题,本文实现一个字节流转换类,可以直接使用完成以上功能。基本原理是开辟一个缓冲区,通过对缓冲区并发的交互的读写操作实现内存复用和字节流的转换。
转换类代码如下:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class InputOutputTransferStream extends InputStream {
    private byte[] buffer = new byte[4096];
    private int byteLength = 0;
    private boolean writeOver = false;
    private boolean readOver = false;
    
    private InputOutputStream outputStream = new InputOutputStream();
    
    private Object lock = new Object();
    
    public class InputOutputStream extends OutputStream {

        @Override
        public void write(int c) throws IOException {
            synchronized(lock) {
                if (byteLength < 0)
                    return;
                while (byteLength >= buffer.length) {
                    try {
                        
                        lock.wait();
                    } catch (InterruptedException e) {
                        //e.printStackTrace();
                    }
                }
                
                if (byteLength < buffer.length) {
                    buffer[byteLength] = (byte)c;
                    byteLength++;
                } 
                lock.notify();
            }
        }
        @Override
        public void write(byte[] buf, int offset, int len) throws IOException {
            synchronized(lock) {
                if (readOver)
                    return;
                
                while (len > 0) {
                    if (byteLength >= buffer.length) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                        }
                    }
                    
                    int nLeft = buffer.length - byteLength;
                    int nLen = Math.min(nLeft, len);
                    
                    try {
                        System.arraycopy(buf, offset, buffer, byteLength, nLen);
                    } catch (Exception ex) {
                    }
                    
                    offset += nLen;
                    len -= nLen;
                    byteLength += nLen;
                    lock.notify();
                }
            }
        }
        
        @Override
        public void write(byte[] buffer) throws IOException {
            write(buffer, 0, buffer.length);
        }
        
        public void close() {
            synchronized(lock) {
                //byteLength = -1;
                writeOver = true;
                lock.notify();
            }
        }
    }
    
    public OutputStream getOutputStream() {
        return outputStream;
    }
    
    @Override
    public int read() throws IOException {
        synchronized(lock) {
            if (readOver)
                return -1;
            while (byteLength == 0) {
                if (writeOver) {
                    throw new IOException("closed");
                }
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    //e.printStackTrace();
                }
            }
            if (byteLength < 0) {
                return -1;
            } else {
                int nResult = buffer[0];
                for (int i = 0; i < byteLength-1; i++) {
                    buffer[i] = buffer[i+1];
                }
                byteLength -= 1;
                
                lock.notify();
                return nResult;
            }
        }
    }
    
    @Override
    public int read(byte[] buf, int offset, int len) throws IOException {
        synchronized(lock) {
            if (readOver)
                return -1;
            while (byteLength == 0) {
                if (writeOver) 
                    return -1;
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    //e.printStackTrace();
                }
            }
            if (byteLength < 0) {
                System.out.println("read -1");
                return -1;
            } else {
                int nLen = Math.min(byteLength, len);
                System.arraycopy(buffer, 0, buf, offset, nLen);
                
                for (int i = 0; i < byteLength-nLen; i++) {
                    buffer[i] = buffer[i+nLen];
                }
                byteLength -= nLen;
                
                lock.notify();
                
                return nLen;
            }
        }
    }
    
    @Override
    public int read(byte[] buffer) throws IOException {
        return read(buffer, 0, buffer.length);
    }
    
    @Override
    public void close() {
        synchronized(lock) {
            readOver = true;
            //byteLength = -1;
            lock.notify();
        }
    }
}

使用方法和测试

以下代码即可用于测试,也为该转换类使用方法的样例:

import java.io.IOException;
import java.io.PrintWriter;

public class InputOutputStreamTest {

    public static void main(String[] argv) throws IOException {
        final InputOutputTransferStream input = new InputOutputTransferStream();
        
        final PrintWriter ps = new PrintWriter(input.getOutputStream());
        
        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    ps.printf("This is line %d\n", i);
                }
                ps.close();
                try {
                    input.getOutputStream().close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }.start();
        
        
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = input.read(buffer)) >= 0) {
            System.out.write(buffer, 0, len);
        }
        input.close();
    }
}

运行该代码,与原始代码实现的结果相同,执行结果均为:

This is line 0
This is line 1
This is line 2
This is line 3
This is line 4
……
This is line 995
This is line 996
This is line 997
This is line 998
This is line 999

你可能感兴趣的:(在JAVA中如何将输出流转为输入流的类的实现)