可隨機讀取的文件行迭代器

可隨機讀取的文件行迭代器
    由於項目需要先前的時候,根據commons-io中的行迭代器,基於RandomAccessFile做了一個可隨機讀取的行迭代器
    但在讀過RandomAccessFile的源碼後發現,RandomAccessFile在每次讀取的時候都會對硬盤進行一次IO操作
    經過百度,發現網上有一種 BufferedRandomAccessFile 可以解決RandomAccessFile讀取大文件時效率低的問題
    【參考http://blog.csdn.net/manerfan/article/details/22827231
    現將迭代器中RandomAccessFile替換爲BufferedRandomAccessFile,並將源碼貼與此處

/*
 * 文件名:LineIterator.java
 * 描述:文件行迭代器
 * 修改人: ManerFan
 *
 */
package maner.fan;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.NoSuchElementException;

import org.apache.log4j.Logger;

/**
 * <p>在commons-io的基礎上進行改進,支持從第pos字節處讀取
 *
 * @author ManerFan
 */
public class LineIterator implements Iterator<String> {

    /** The reader that is being read. */
    private final BufferedRandomAccessFile randomReader;
    /** The current line. */
    private String cachedLine;
    private long cachedOffset = 0;
    /** 當前指針 */
    private long currentOffset = 0;
    /** A flag indicating if the iterator has been fully read. */
    private boolean finished = false;
    /** 默認編碼 */
    private String charSet = "UTF-8";
    /** 起始字節數 */
    private long offset;
    /** log4j */
    private static final Logger LOGGER = Logger.getLogger(LineIterator.class);

    /**
     * Constructs an iterator of the lines for a <code>Reader</code>.
     *
     * @param reader the <code>Reader</code> to read from, not null
     * @throws IllegalArgumentException if the reader is null
     */
    public LineIterator(final File reader, String charSet, final long offset)
            throws IllegalArgumentException {
        if (reader == null) {
            throw new IllegalArgumentException("Reader must not be null");
        }

        if (!reader.exists() || !reader.isFile()) {
            throw new IllegalArgumentException();
        }

        if (null != charSet && !charSet.trim().isEmpty()) {
            this.charSet = charSet;
        }

        if (offset < 0) {
            throw new IllegalArgumentException();
        }

        try {
            randomReader = new BufferedRandomAccessFile(reader, "r");
            this.offset = offset;
            randomReader.seek(offset);
            currentOffset = offset;
        } catch (IOException e) {
            throw new IllegalArgumentException(e);
        }
    }

    //-----------------------------------------------------------------------
    /**
     * Indicates whether the <code>Reader</code> has more lines.
     * If there is an <code>IOException</code> then {@link #close()} will
     * be called on this instance.
     *
     * @return {@code true} if the Reader has more lines
     * @throws IllegalStateException if an IO exception occurs
     */
    public boolean hasNext() {
        try {
            if (cachedLine != null) {
                return true;
            } else if (finished) {
                return false;
            } else if (randomReader.length() < offset) {
                return false;
            } else {
                while (true) {
                    String line = randomReader.readLine();
                    if (line == null) {
                        finished = true;
                        return false;
                    } else {
                        String transLine = transcoding(line);
                        if (null != transLine) {
                            cachedLine = transLine;
                            cachedOffset = randomReader.getFilePointer();
                            return true;
                        }
                    }
                }
            }
        } catch (IOException ioe) {
            close();
            throw new IllegalStateException(ioe);
        }
    }

    /**
     * Overridable method to validate each line that is returned.
     * This implementation always returns true.
     * @param line  the line that is to be validated
     * @return true if valid, false to remove from the iterator
     */
    protected String transcoding(String line) {
        String transString = null;
        try {
            if (null != line && !line.isEmpty()) {
                transString = new String(line.getBytes("8859_1"), charSet); // 做一次轉碼
            }
        } catch (UnsupportedEncodingException e) {
            return null;
        }
        return transString;
    }

    /**
     * Returns the next line in the wrapped <code>Reader</code>.
     *
     * @return the next line from the input
     * @throws NoSuchElementException if there is no line to return
     */
    public String next() {
        return nextLine();
    }

    /**
     * Returns the next line in the wrapped <code>Reader</code>.
     *
     * @return the next line from the input
     * @throws NoSuchElementException if there is no line to return
     */
    private String nextLine() {
        if (!hasNext()) {
            throw new NoSuchElementException("No more lines");
        }
        String currentLine = cachedLine;
        cachedLine = null;
        currentOffset = cachedOffset;
        return currentLine;
    }

    public long currentOffset() {
        return currentOffset;
    }

    /**
     * Closes the underlying <code>Reader</code> quietly.
     * This method is useful if you only want to process the first few
     * lines of a larger file. If you do not close the iterator
     * then the <code>Reader</code> remains open.
     * This method can safely be called multiple times.
     * @throws IOException 
     */
    public void close() {
        finished = true;
        try {
            randomReader.close();
        } catch (IOException e) {
            LOGGER.error("Cannot close randonReader.", e);
        }
        cachedLine = null;
    }

    /**
     * Unsupported.
     *
     * @throws UnsupportedOperationException always
     */
    public void remove() {
        throw new UnsupportedOperationException("Remove unsupported on LineIterator");
    }

    //-----------------------------------------------------------------------
    /**
     * Closes the iterator, handling null and ignoring exceptions.
     *
     * @param iterator  the iterator to close
     */
    public static void closeQuietly(LineIterator iterator) {
        if (iterator != null) {
            iterator.close();
        }
    }

}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章