Reads sequentially from multiple sources
/*
* Copyright (C) 2016 Stephen Ostermiller
* http://ostermiller.org/contact.pl?regarding=Java+Utilities
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* See COPYING.TXT for details.
*/
import java.io.*;
import java.util.ArrayList;
/**
* A reader which reads sequentially from multiple sources.
* More information about this class is available from <a target="_top" href=
* "http://ostermiller.org/utils/">ostermiller.org</a>.
*
* @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
* @since ostermillerutils 1.04.00
*/
public class ConcatReader extends Reader {
/**
* Current index to readerQueue
*
* @since ostermillerutils 1.04.01
*/
private int readerQueueIndex = 0;
/**
* Queue of readers that have yet to be read from.
*
* @since ostermillerutils 1.04.01
*/
private ArrayList<Reader> readerQueue = new ArrayList<Reader>();
/**
* A cache of the current reader from the readerQueue
* to avoid unneeded access to the queue which must
* be synchronized.
*
* @since ostermillerutils 1.04.01
*/
private Reader currentReader = null;
/**
* true iff the client may add more readers.
*
* @since ostermillerutils 1.04.01
*/
private boolean doneAddingReaders = false;
/**
* Causes the addReader method to throw IllegalStateException
* and read() methods to return -1 (end of stream)
* when there is no more available data.
* <p>
* Calling this method when this class is no longer accepting
* more readers has no effect.
*
* @since ostermillerutils 1.04.01
*/
public void lastReaderAdded(){
doneAddingReaders = true;
}
/**
* Add the given reader to the queue of readers from which to
* concatenate data.
*
* @param in Reader to add to the concatenation.
* @throws IllegalStateException if more readers can't be added because lastReaderAdded() has been called, close() has been called, or a constructor with reader parameters was used.
*
* @since ostermillerutils 1.04.01
*/
public void addReader(Reader in){
synchronized(readerQueue){
if (in == null) throw new NullPointerException();
if (closed) throw new IllegalStateException("ConcatReader has been closed");
if (doneAddingReaders) throw new IllegalStateException("Cannot add more readers - the last reader has already been added.");
readerQueue.add(in);
}
}
/**
* Add the given reader to the queue of readers from which to
* concatenate data.
*
* @param in Reader to add to the concatenation.
* @throws IllegalStateException if more readers can't be added because lastReaderAdded() has been called, close() has been called, or a constructor with reader parameters was used.
* @throws NullPointerException the array of readers, or any of the contents is null.
*
* @since ostermillerutils 1.04.01
*/
public void addReaders(Reader[] in){
for (Reader element: in) {
addReader(element);
}
}
/**
* Gets the current reader, looking at the next
* one in the list if the current one is null.
*
* @since ostermillerutils 1.04.01
*/
private Reader getCurrentReader(){
if (currentReader == null && readerQueueIndex < readerQueue.size()){
synchronized(readerQueue){
// reader queue index is advanced only by the nextReader()
// method. Don't do it here.
currentReader = readerQueue.get(readerQueueIndex);
}
}
return currentReader;
}
/**
* Indicate that we are done with the current reader and we should
* advance to the next reader.
*
* @since ostermillerutils 1.04.01
*/
private void advanceToNextReader(){
currentReader = null;
readerQueueIndex++;
}
/**
* True iff this the close() method has been called on this stream.
*
* @since ostermillerutils 1.04.00
*/
private boolean closed = false;
/**
* Create a new reader that can dynamically accept new sources.
* <p>
* New sources should be added using the addReader() method.
* When all sources have been added the lastReaderAdded() should
* be called so that read methods can return -1 (end of stream).
* <p>
* Adding new sources may by interleaved with read calls.
*
* @since ostermillerutils 1.04.01
*/
public ConcatReader(){
// Empty Constructor
}
/**
* Create a new reader with one source.
* <p>
* When using this constructor, more readers cannot
* be added later, and calling addReader() will
* throw an illegal state Exception.
*
* @param in reader to use as a source.
*
* @throws NullPointerException if in is null
*
* @since ostermillerutils 1.04.00
*/
public ConcatReader(Reader in){
addReader(in);
lastReaderAdded();
}
/**
* Create a new reader with two sources.
* <p>
* When using this constructor, more readers cannot
* be added later, and calling addReader() will
* throw an illegal state Exception.
*
* @param in1 first reader to use as a source.
* @param in2 second reader to use as a source.
*
* @throws NullPointerException if either source is null.
*
* @since ostermillerutils 1.04.00
*/
public ConcatReader(Reader in1, Reader in2){
addReader(in1);
addReader(in2);
lastReaderAdded();
}
/**
* Create a new reader with an arbitrary number of sources.
* <p>
* When using this constructor, more readers cannot
* be added later, and calling addReader() will
* throw an illegal state Exception.
*
* @param in readers to use as a sources.
*
* @throws NullPointerException if the input array on any element is null.
*
* @since ostermillerutils 1.04.00
*/
public ConcatReader(Reader[] in){
addReaders(in);
lastReaderAdded();
}
/**
* Read a single character. This method will block until a
* character is available, an I/O error occurs, or the end of all underlying
* streams are reached.
* <p>
* If this class in not done accepting readers and the end of the last known
* stream is reached, this method will block forever unless another thread
* adds a reader or interrupts.
*
* @return The character read, as an integer in the range 0 to 65535 (0x00-0xffff),
* or -1 if the end of the stream has been reached
*
* @throws IOException - If an I/O error occurs
*
* @since ostermillerutils 1.04.00
*/
@Override public int read() throws IOException {
if (closed) throw new IOException("Reader closed");
int r = -1;
while (r == -1){
Reader in = getCurrentReader();
if (in == null){
if (doneAddingReaders) return -1;
try {
Thread.sleep(100);
} catch (InterruptedException iox){
throw new IOException("Interrupted");
}
} else {
r = in.read();
if (r == -1) advanceToNextReader();
}
}
return r;
}
/**
* Read characters into an array. This method will block until some input is available, an
* I/O error occurs, or the end of all underlying
* streams are reached.
* <p>
* If this class in not done accepting readers and the end of the last known
* stream is reached, this method will block forever unless another thread
* adds a reader or interrupts.
*
* @param cbuf - Destination buffer
* @return The number of characters read, or -1 if the end of the stream has been reached
*
* @throws IOException - If an I/O error occurs
* @throws NullPointerException - If the buffer is null.
*
* @since ostermillerutils 1.04.00
*/
@Override public int read(char[] cbuf) throws IOException {
return read(cbuf, 0, cbuf.length);
}
/**
* Read characters into a portion of an array. This method will block until
* some input is available, an I/O error occurs, or the end of all underlying
* streams are reached.
* <p>
* If this class in not done accepting readers and the end of the last known
* stream is reached, this method will block forever unless another thread
* adds a reader or interrupts.
*
* @param cbuf Destination buffer
* @param off Offset at which to start storing characters
* @param len Maximum number of characters to read
* @return The number of characters read, or -1 if the end of the stream has been reached
*
* @throws IOException - If an I/O error occurs
* @throws NullPointerException - If the buffer is null.
* @throws IndexOutOfBoundsException - if length or offset are not possible.
*
* @since ostermillerutils 1.04.00
*/
@Override public int read(char[] cbuf, int off, int len) throws IOException {
if (off < 0 || len < 0 || off + len > cbuf.length) throw new IndexOutOfBoundsException();
if (closed) throw new IOException("Reader closed");
int r = -1;
while (r == -1){
Reader in = getCurrentReader();
if (in == null){
if (doneAddingReaders) return -1;
try {
Thread.sleep(100);
} catch (InterruptedException iox){
throw new IOException("Interrupted");
}
} else {
r = in.read(cbuf, off, len);
if (r == -1) advanceToNextReader();
}
}
return r;
}
/**
* Skip characters. This method will block until some characters are
* available, an I/O error occurs, or the end of the stream is reached.
* <p>
* If this class in not done accepting readers and the end of the last known
* stream is reached, this method will block forever unless another thread
* adds a reader or interrupts.
*
* @param n the number of characters to skip
* @return The number of characters actually skipped
*
* @throws IllegalArgumentException If n is negative.
* @throws IOException If an I/O error occurs
*
* @since ostermillerutils 1.04.00
*/
@Override public long skip(long n) throws IOException {
if (closed) throw new IOException("Reader closed");
if (n <= 0) return 0;
long s = -1;
while (s <= 0){
Reader in = getCurrentReader();
if (in == null){
if (doneAddingReaders) return 0;
try {
Thread.sleep(100);
} catch (InterruptedException iox){
throw new IOException("Interrupted");
}
} else {
s = in.skip(n);
// When nothing was skipped it is a bit of a puzzle.
// The most common cause is that the end of the underlying
// stream was reached. In which case calling skip on it
// will always return zero. If somebody were calling skip
// until it skipped everything they needed, there would
// be an infinite loop if we were to return zero here.
// If we get zero, let us try to read one character so
// we can see if we are at the end of the stream. If so,
// we will move to the next.
if (s <= 0) {
// read() will advance to the next stream for us, so don't do it again
s = ((read()==-1)?-1:1);
}
}
}
return s;
}
/**
* Tell whether this stream is ready to be read.
*
* @return True if the next read() is guaranteed not to block for input,
* false otherwise. Note that returning false does not guarantee that the next
* read will block.
*
* @throws IOException If an I/O error occurs
*
* @since ostermillerutils 1.04.00
*/
@Override public boolean ready() throws IOException {
if (closed) throw new IOException("Reader closed");
Reader in = getCurrentReader();
if (in == null) return false;
return in.ready();
}
/**
* Close the stream and any underlying streams.
* Once a stream has been closed, further read(), ready(), mark(), or reset()
* invocations will throw an IOException. Closing a previously-closed stream,
* however, has no effect.
*
* @throws IOException If an I/O error occurs
*
* @since ostermillerutils 1.04.00
*/
@Override public void close() throws IOException {
if (closed) return;
for (Reader reader: readerQueue) {
reader.close();
}
closed = true;
}
/**
* Mark not supported.
*
* @throws IOException because mark is not supported.
*
* @since ostermillerutils 1.04.00
*/
@Override public void mark(int readlimit) throws IOException {
throw new IOException("Mark not supported");
}
/**
* Reset not supported.
*
* @throws IOException because reset is not supported.
*
* @since ostermillerutils 1.04.00
*/
@Override public void reset() throws IOException {
throw new IOException("Reset not supported");
}
/**
* Mark not supported.
*
* @return false
*
* @since ostermillerutils 1.04.00
*/
@Override public boolean markSupported(){
return false;
}
}
Reads sequentially from multiple sources的更多相关文章
- jdk1.7升级到jdk1.8后出错: [ERROR] javadoc: warning - Multiple sources of package comments found for package
from: http://blog.joda.org/2014/02/turning-off-doclint-in-jdk-8-javadoc.html [ERROR] javadoc: warnin ...
- Sphinx 2.2.11-release reference manual
1. Introduction 1.1. About 1.2. Sphinx features 1.3. Where to get Sphinx 1.4. License 1.5. Credits 1 ...
- Flume NG Getting Started(Flume NG 新手入门指南)
Flume NG Getting Started(Flume NG 新手入门指南)翻译 新手入门 Flume NG是什么? 有什么改变? 获得Flume NG 从源码构建 配置 flume-ng全局选 ...
- TopHat
What is TopHat? TopHat is a program that aligns RNA-Seq reads to a genome in order to identify exon- ...
- 【转】 svn 错误 以及 中文翻译
直接Ctrl+F 搜索你要找的错 # # Simplified Chinese translation for subversion package # This file is distribute ...
- RAC的QA
RAC: Frequently Asked Questions [ID 220970.1] 修改时间 13-JAN-2011 类型 FAQ 状态 PUBLISHED Appli ...
- GATK-BWA-MEM handle GRCh38 alternate contig mappings
1. For the Impatient # Download bwakit (or from <http://sourceforge.net/projects/bio-bwa/files/bw ...
- [转] KVM Internals, code and more
KVM Kernel-based Virtual Machine Internals, code and more http://slides.com/braoru/kvm#/ What behind ...
- worker启动executor源码分析-executor.clj
在"supervisor启动worker源码分析-worker.clj"一文中,我们详细讲解了worker是如何初始化的.主要通过调用mk-worker函数实现的.在启动worke ...
随机推荐
- 怎么用PHP发送HTTP请求(转载)
本文转自:http://blog.snsgou.com/blog/161.html file_get_contents版本: /** * 发送post请求 * @param string $url ...
- 不会JS中的OOP,你也太菜了吧!(第二篇)
一.你必须知道的 1> 原型及原型链在继承中起到了关键的作用.所以你一定要理解他们.2> 不会JS中的OOP,你也太菜了吧!(第一篇) 二.继承的6种方法 1> 原型链继承 原型链继 ...
- POJ2676-Sudoku(数独)
想了好久没想到好的解决办法,参考了 http://user.qzone.qq.com/289065406/blog/1303713313 大致题意: 九宫格问题,也有人叫数独问题 把一个9行9列的网格 ...
- 请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
// test20.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include< ...
- boost之mutex scoped_lock
1.boost里的互斥量类型由mutex表示. 代码示例: #include <iostream> #include <string> #include <vector& ...
- 关于“无法定位程序输入点gzdirect于动态链接库zlib1.dll”的问题
费劲N多力气编译通过之后,最后启动程序过程中却突然得到“无法定位程序输入点gzdirect于动态链接库zlib1.dll”的问题, 分析究其原因是定位不到zlib1.dll,都知道,程序在找dll的时 ...
- Asp.net 自定义控件开发相关的几种嵌入资源解决方案
前提: 如下将要介绍的几种类型资源都要在其属性页窗口, 将 <生成操作> 属性, 设置为[嵌入的资源], 如图: ► 给自定义控件添加自定义图标的几种方案 方法一: 直接在自定义控 ...
- F.I.S本地环境的搭建教程
一.准备开发环境: 1.安装JRE 2.安装nodejs 最好是msi文件,比较省事. 3.(如果是PHP项目)安装php. 首先下载php(我的是5.5.15版本,win7 64位系统) zip,然 ...
- POJ 2001
#include<iostream> using namespace std; ; struct trienode { trienode * next[kind]; int branch; ...
- 定时每天执行前一天的数据导入oracle
#!/bin/bash export LANG="en_US.UTF-8" #设定时间变量,为前一天时间 log_date=`date +%Y-%m-%d -d "-1 ...