com.alibaba.otter.shared.common.utils.NioUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.alibaba.otter.shared.common.utils.NioUtils.java

Source

/*
 * Copyright (C) 2010-2101 Alibaba Group Holding Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.otter.shared.common.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * nio??stream?
 * 
 * @author jianghang 2011-10-9 ?06:28:44
 * @version 4.0.0
 */
public class NioUtils {

    private static final Logger logger = LoggerFactory.getLogger(NioUtils.class);
    private static final int DEFAULT_BUFFER_SIZE = 8 * 1024;
    private static final int timeWait = 1000;

    /**
     * ??copy
     */
    public static long copy(InputStream input, OutputStream output, long offset) throws IOException {
        long count = 0;
        long n = 0;
        if (input instanceof FileInputStream) {
            FileChannel inChannel = ((FileInputStream) input).getChannel();
            WritableByteChannel outChannel = Channels.newChannel(output);
            count = inChannel.transferTo(offset, inChannel.size() - offset, outChannel);
        } else if (output instanceof FileOutputStream) {
            FileChannel outChannel = ((FileOutputStream) output).getChannel();
            ReadableByteChannel inChannel = Channels.newChannel(input);
            do {
                n = outChannel.transferFrom(inChannel, offset + count, DEFAULT_BUFFER_SIZE);
                count += n;
            } while (n > 0);
        } else {
            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];

            input.skip(offset);
            while (-1 != (n = input.read(buffer))) {
                output.write(buffer, 0, (int) n);
                count += n;
            }
            // ReadableByteChannel inChannel = Channels.newChannel(input);
            // WritableByteChannel outChannel = Channels.newChannel(output);
            //            
            // //ByteBuffer buffer = new ByteBuffer(DEFAULT_BUFFER_SIZE);
            // ByteBuffer buffer = ByteBuffer.allocateDirect(DEFAULT_BUFFER_SIZE);
            // while (-1 != (n = inChannel.read(buffer))) {
            // outChannel.write(buffer);
            // count += n;
            // }
        }
        return count;
    }

    /**
     * ??copy
     */
    public static long copy(InputStream input, OutputStream output, long offset, long count) throws IOException {
        long rcount = 0;
        long n = 0;
        if (input instanceof FileInputStream) {
            FileChannel inChannel = ((FileInputStream) input).getChannel();
            WritableByteChannel outChannel = Channels.newChannel(output);
            rcount = inChannel.transferTo(offset, count, outChannel);
        } else if (output instanceof FileOutputStream) {
            FileChannel outChannel = ((FileOutputStream) output).getChannel();
            ReadableByteChannel inChannel = Channels.newChannel(input);
            do {
                if (count < DEFAULT_BUFFER_SIZE) {
                    n = outChannel.transferFrom(inChannel, offset + rcount, count);
                } else {
                    n = outChannel.transferFrom(inChannel, offset + rcount, DEFAULT_BUFFER_SIZE);
                }
                count -= n;
                rcount += n;
            } while (n > 0);
        } else {
            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];

            input.skip(offset);
            while (count > 0) {
                if (count < DEFAULT_BUFFER_SIZE) {
                    n = input.read(buffer, 0, (int) count);
                } else {
                    n = input.read(buffer, 0, DEFAULT_BUFFER_SIZE);
                }

                output.write(buffer, 0, (int) n);
                count -= n;
                rcount += n;
            }
            // ReadableByteChannel inChannel = Channels.newChannel(input);
            // WritableByteChannel outChannel = Channels.newChannel(output);
            //            
            // //ByteBuffer buffer = new ByteBuffer(DEFAULT_BUFFER_SIZE);
            // ByteBuffer buffer = ByteBuffer.allocateDirect(DEFAULT_BUFFER_SIZE);
            // while (-1 != (n = inChannel.read(buffer))) {
            // outChannel.write(buffer);
            // count += n;
            // }
        }
        return rcount;
    }

    /**
     * ??copy
     */
    public static long copy(InputStream input, OutputStream output) throws IOException {
        long count = 0;
        long n = 0;
        if (input instanceof FileInputStream) {
            FileChannel inChannel = ((FileInputStream) input).getChannel();
            WritableByteChannel outChannel = Channels.newChannel(output);
            count = inChannel.transferTo(0, inChannel.size(), outChannel);
        } else if (output instanceof FileOutputStream) {
            FileChannel outChannel = ((FileOutputStream) output).getChannel();
            ReadableByteChannel inChannel = Channels.newChannel(input);
            do {
                n = outChannel.transferFrom(inChannel, count, DEFAULT_BUFFER_SIZE);
                count += n;
            } while (n > 0);
        } else {
            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];

            while (-1 != (n = input.read(buffer))) {
                output.write(buffer, 0, (int) n);
                count += n;
            }
            // ReadableByteChannel inChannel = Channels.newChannel(input);
            // WritableByteChannel outChannel = Channels.newChannel(output);
            //            
            // //ByteBuffer buffer = new ByteBuffer(DEFAULT_BUFFER_SIZE);
            // ByteBuffer buffer = ByteBuffer.allocateDirect(DEFAULT_BUFFER_SIZE);
            // while (-1 != (n = inChannel.read(buffer))) {
            // outChannel.write(buffer);
            // count += n;
            // }
        }
        return count;
    }

    /**
     * byte[]??
     */
    public static void write(byte[] data, OutputStream output) throws IOException {
        ByteArrayInputStream input = null;
        try {
            input = new ByteArrayInputStream(data);
            copy(input, output);
            output.flush();
        } finally {
            IOUtils.closeQuietly(output);
        }
    }

    /**
     * byte
     */
    public static void write(final byte[] srcArray, File targetFile) throws IOException {
        write(srcArray, targetFile, true);
    }

    /**
     * byte
     */
    public static void write(final byte[] srcArray, File targetFile, final boolean overwrite) throws IOException {
        if (srcArray == null) {
            throw new IOException("Source must not be null");
        }

        if (targetFile == null) {
            throw new IOException("Target must not be null");
        }

        if (true == targetFile.exists()) {
            if (true == targetFile.isDirectory()) {
                throw new IOException("Target '" + targetFile.getAbsolutePath() + "' is directory!");
            } else if (true == targetFile.isFile()) {
                if (!overwrite) {
                    throw new IOException("Target file '" + targetFile.getAbsolutePath() + "' already exists!");
                }
            } else {
                throw new IOException("Invalid target object '" + targetFile.getAbsolutePath() + "'!");
            }
        } else {
            // create parent dir
            create(targetFile.getParentFile(), false, 3);
        }

        // ?inputStream
        ByteArrayInputStream input = null;
        FileOutputStream output = null;
        try {
            input = new ByteArrayInputStream(srcArray);
            output = new FileOutputStream(targetFile);
            copy(input, output);
            output.flush();
        } finally {
            IOUtils.closeQuietly(input);
            IOUtils.closeQuietly(output);
        }
    }

    /**
     * ?
     */
    public static byte[] read(File sourceFile) throws IOException {
        if (sourceFile == null) {
            throw new IOException("Source must not be null");
        }

        if (false == sourceFile.exists()) {
            throw new IOException("Source '" + sourceFile + "' does not exist");
        }

        if (true == sourceFile.isDirectory()) {
            throw new IOException("Source '" + sourceFile + "' exists but is a directory");
        }

        FileInputStream input = null;
        ByteArrayOutputStream output = null;

        try {
            input = new FileInputStream(sourceFile);
            output = new ByteArrayOutputStream();
            copy(input, output);
            output.flush();
            return output.toByteArray();
        } finally {
            IOUtils.closeQuietly(input);
            IOUtils.closeQuietly(output);
        }
    }

    /**
     * ??byte[]
     */
    public static byte[] read(InputStream input) throws IOException {
        ByteArrayOutputStream output = null;
        try {
            output = new ByteArrayOutputStream();
            copy(input, output);
            output.flush();
            return output.toByteArray();
        } finally {
            IOUtils.closeQuietly(output);
        }
    }

    /**
     * Copy file overwrite
     */
    public static void copy(final File src, File dest) throws IOException {
        copy(src, dest, 1);
    }

    /**
     * ??
     * 
     * @param src
     * @param dest
     * @param retryTimes
     * @throws IOException
     */
    public static boolean copy(final File src, File dest, final int retryTimes) throws IOException {
        int totalRetry = retryTimes;

        if (retryTimes < 1) {
            totalRetry = 1;
        }

        int retry = 0;
        while (retry++ < totalRetry) {
            try {
                copy(src, dest, true);
                return true;
            } catch (Exception ex) {
                // 
                int wait = (int) Math.pow(retry, retry) * timeWait;
                wait = (wait < timeWait) ? timeWait : wait;

                if (retry == totalRetry) {
                    if (ex instanceof IOException) {
                        throw (IOException) ex;
                    } else {
                        throw new IOException((ex == null) ? "unknow error" : ex.getMessage(), ex);
                    }
                } else {
                    try {
                        Thread.sleep(wait);
                    } catch (InterruptedException e) {
                        // ignore
                    }
                }
            }
        }

        return false;
    }

    /**
     * Copy source file to destination. If destination is a path then source file name is appended. If destination file
     * exists then: overwrite=true - destination file is replaced; overwite=false - exception is thrown
     */
    public static void copy(final File sourceFile, File targetFile, final boolean overwrite) throws IOException {
        if (sourceFile == null) {
            throw new IOException("Source must not be null");
        }

        if (targetFile == null) {
            throw new IOException("Target must not be null");
        }

        // checks
        if ((false == sourceFile.isFile()) || (false == sourceFile.exists())) {
            throw new IOException("Source file '" + sourceFile.getAbsolutePath() + "' not found!");
        }

        if (true == targetFile.exists()) {
            if (true == targetFile.isDirectory()) {

                // Directory? -> use source file name
                targetFile = new File(targetFile, sourceFile.getName());
            } else if (true == targetFile.isFile()) {
                if (false == overwrite) {
                    throw new IOException("Target file '" + targetFile.getAbsolutePath() + "' already exists!");
                }
            } else {
                throw new IOException("Invalid target object '" + targetFile.getAbsolutePath() + "'!");
            }
        } else {
            // create parent dir
            FileUtils.forceMkdir(targetFile.getParentFile());
        }

        FileInputStream input = null;
        FileOutputStream output = null;

        try {
            input = new FileInputStream(sourceFile);
            output = new FileOutputStream(targetFile);
            copy(input, output);
            output.flush();
        } finally {
            IOUtils.closeQuietly(input);
            IOUtils.closeQuietly(output);
        }
    }

    /**
     * 
     */
    public static boolean create(File dest) {
        return create(dest, true, 1);
    }

    /**
     * ?
     */
    public static boolean create(File dest, final boolean isFile, final int retryTimes) {
        if (dest == null) {
            return false;
        }

        int totalRetry = retryTimes;

        if (retryTimes < 0) {
            totalRetry = 1;
        }

        int retry = 0;
        while (retry++ < totalRetry) {
            try {
                if (true == isFile) {
                    if ((true == dest.exists()) || (true == dest.createNewFile())) {
                        return true;
                    }
                } else {
                    FileUtils.forceMkdir(dest);
                    return true;
                }
            } catch (Exception ex) {
                // 
                int wait = (int) Math.pow(retry, retry) * timeWait;
                wait = (wait < timeWait) ? timeWait : wait;

                // ?
                if (retry == totalRetry) {
                    return false;
                } else {

                    // 
                    logger.warn(String.format("[%s] create() - retry %s failed : wait [%s] ms , caused by %s",
                            dest.getAbsolutePath(), retry, wait, ex.getMessage()));
                    try {
                        Thread.sleep(wait);
                    } catch (InterruptedException e) {
                        return false;
                    }
                }
            }
        }

        return false;
    }

    /**
     * ?jvm
     * 
     * @param dest
     * @param retryTimes
     */
    public static boolean delete(File dest) {
        return delete(dest, 1);
    }

    /**
     * ??jvm
     * 
     * @param dest
     * @param retryTimes
     */
    public static boolean delete(File dest, final int retryTimes) {
        if (dest == null) {
            return false;
        }

        if (false == dest.exists()) {
            return true;
        }

        int totalRetry = retryTimes;
        if (retryTimes < 1) {
            totalRetry = 1;
        }

        int retry = 0;
        while (retry++ < totalRetry) {
            try {
                FileUtils.forceDelete(dest);
                return true;
            } catch (FileNotFoundException ex) {
                return true;
            } catch (Exception ex) {
                // 
                int wait = (int) Math.pow(retry, retry) * timeWait;
                wait = (wait < timeWait) ? timeWait : wait;
                if (retry == totalRetry) {
                    try {
                        FileUtils.forceDeleteOnExit(dest);
                        return false;
                    } catch (Exception e) {
                        // ignore
                    }
                } else {
                    // 
                    logger.warn(String.format("[%s] delete() - retry %s failed : wait [%s] ms , caused by %s",
                            dest.getAbsolutePath(), retry, wait, ex.getMessage()));
                    try {
                        Thread.sleep(wait);
                    } catch (InterruptedException e) {
                        // ignore
                    }
                }
            }
        }

        return false;
    }

    /**
     * Move file without retry
     */
    public static void move(final File src, File dest) throws IOException {
        move(src, dest, 1);
    }

    /**
     * Moves the source file to the destination. If the destination cannot be created or is a read-only file, the method
     * returns <code>false</code>. Otherwise, the contents of the source are copied to the destination, the source is
     * deleted, and <code>true</code> is returned.
     * 
     * @param src The source file to move.
     * @param dest The destination where to move the file.
     * @param retryTimes Move and delete retry times
     */
    public static void move(final File src, File dest, final int retryTimes) throws IOException {
        copy(src, dest, retryTimes);
        delete(src, retryTimes);
    }

}