Java IO best practice

A StreamCopier class that copies data between two streams as quickly as possible. The method reads from the input stream and writes onto the output stream until the input stream is exhausted. A 1K buffer is used to try to make the reads more efficient.

class StreamCopier {
    public static void copy(InputStream in, OutputStream out) 
        throws IOException {
        byte[] buffer = new byte[1024];
        while (true) {
            int bytesRead = in.read(buffer);
            if (bytesRead == -1) break;
            out.write(buffer, 0, bytesRead);
        }
    }
}

Sun随后发布了NIO(Nonblocking I/O),它在处理大文件时(如大于1G的文件)性能有显著提高。下面使用NIO实现文件拷贝。

class FileCopier {
    public static void copy(String inFile, String outFile) {
        FileInputStream fis = new FileInputStream(inFile);
        FileOutputStream fos = new FileOutputStream(outFile);
        FileChannel inChannel = fis.getChannel();
        FileChannel outChannel = fos.getChannel();
        for (ByteBuffer buf = ByteBuffer.allocate(1024*1024);
             inChannel.read(buf) != -1;
             buf.clear()) {
            buf.flip();
            while (buf.hasRemaining())
                outChannel.write(buf);
        }

        inChannel.close();
        outChannel.close();
    }
}

前面两个拷贝的方法都存在一个bug,没有考虑到源文件和目标文件相同的情况。

下面的例子解决了该bug

class SafeFileCopier {
    public static void copy(File inFile, File outFile) throws IOException {
        if (inFile.getCanonicalPath().equals(outFile.getCanonicalPath( ))) {
            // inFile and outFile are the same, hence no copying is required
            return;
        }

        InputStream in = null;
        OutputStream out = null;
        try {
            in = new BufferedInputStream(new FileInputStream(inFile));
            out = new BufferedOutputStream(new FileOutputStream(outFile));
            for (int c = in.read(); c != -1; c = in.read( )) {
                out.write(c);
            }
        } finally {
            if (in != null) in.close();
            if (out != null) out.close();
        }
    }
}

getCanonicalPath()会将一些符号链接,快捷方式等解析为真正的目标文件,因此确定了文件的唯一性。

网络服务器对IO的处理
网络服务器会收到来自成千上百用户的请求,为了不阻塞用户,通常为每一个用户创建一个线程。如果创建非常多的线程,服务器性能会显著下降。NIO中一些新的API既解决了阻塞问题,又解决了性能问题。

public class Demo {
    private static byte[] data = new byte[256];
    
    public static void main(String[] args) throws IOException {
        for (int i = 0; i < data.length; i++)
            data[i] = (byte) i;
        
        ServerSocketChannel server = ServerSocketChannel.open();
        server.configureBlocking(false);
        server.socket().bind(new InetSocketAddress(9000));
        Selector selector = Selector.open();
        server.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            selector.select();
            Set readyKeys = selector.selectedKeys();
            Iterator iterator = readyKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = (SelectionKey) iterator.next();
                iterator.remove();
                try {
                    if (key.isAcceptable()) {
                        SocketChannel client = server.accept();
                        System.out.println("Accepted connection from " + client);
                        client.configureBlocking(false);
                        ByteBuffer source = ByteBuffer.wrap(data);
                        SelectionKey key2 = client.register(selector,
                                SelectionKey.OP_WRITE);
                        key2.attach(source);
                    } else if (key.isWritable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer output = (ByteBuffer) key.attachment();
                        if (!output.hasRemaining()) {
                            output.rewind();
                        }
                        client.write(output);
                    }
                } catch (IOException ex) {
                    key.cancel();
                    try {
                        key.channel().close();
                    } catch (IOException cex) {
                    }
                }
            }
        }
    }
}

转载于:https://www.cnblogs.com/RayLee/archive/2011/02/23/1962662.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值