001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.io.input; 018 019import static org.apache.commons.io.IOUtils.EOF; 020 021import java.io.IOException; 022import java.io.Reader; 023import java.util.Arrays; 024import java.util.Iterator; 025import java.util.Objects; 026 027/** 028 * Provides the contents of multiple Readers in sequence. 029 * 030 * @since 2.7 031 */ 032public class SequenceReader extends Reader { 033 034 private Reader reader; 035 private Iterator<? extends Reader> readers; 036 037 /** 038 * Construct a new instance with readers 039 * 040 * @param readers the readers to read 041 */ 042 public SequenceReader(final Iterable<? extends Reader> readers) { 043 this.readers = Objects.requireNonNull(readers, "readers").iterator(); 044 this.reader = nextReader(); 045 } 046 047 /** 048 * Construct a new instance with readers 049 * 050 * @param readers the readers to read 051 */ 052 public SequenceReader(final Reader... readers) { 053 this(Arrays.asList(readers)); 054 } 055 056 /* 057 * (non-Javadoc) 058 * 059 * @see java.io.Reader#close() 060 */ 061 @Override 062 public void close() throws IOException { 063 this.readers = null; 064 this.reader = null; 065 } 066 067 /** 068 * Returns the next available reader or null if done. 069 * 070 * @return the next available reader or null 071 */ 072 private Reader nextReader() { 073 return this.readers.hasNext() ? this.readers.next() : null; 074 } 075 076 /* 077 * (non-Javadoc) 078 * 079 * @see java.io.Reader#read(char[], int, int) 080 */ 081 @Override 082 public int read() throws IOException { 083 int c = EOF; 084 while (reader != null) { 085 c = reader.read(); 086 if (c == EOF) { 087 reader = nextReader(); 088 } else { 089 break; 090 } 091 } 092 return c; 093 } 094 095 /* 096 * (non-Javadoc) 097 * 098 * @see java.io.Reader#read() 099 */ 100 @Override 101 public int read(final char[] cbuf, int off, int len) throws IOException { 102 Objects.requireNonNull(cbuf, "cbuf"); 103 if (len < 0 || off < 0 || off + len > cbuf.length) { 104 throw new IndexOutOfBoundsException("Array Size=" + cbuf.length + ", offset=" + off + ", length=" + len); 105 } 106 int count = 0; 107 while (reader != null) { 108 final int readLen = reader.read(cbuf, off, len); 109 if (readLen == EOF) { 110 reader = nextReader(); 111 } else { 112 count += readLen; 113 off += readLen; 114 len -= readLen; 115 if (len <= 0) { 116 break; 117 } 118 } 119 } 120 if (count > 0) { 121 return count; 122 } 123 return EOF; 124 } 125}