1/* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.common.io; 18 19import static com.google.common.base.Preconditions.checkNotNull; 20 21import java.io.IOException; 22import java.io.InputStream; 23import java.util.Iterator; 24 25import javax.annotation.Nullable; 26 27/** 28 * An {@link InputStream} that concatenates multiple substreams. At most 29 * one stream will be open at a time. 30 * 31 * @author Chris Nokleberg 32 * @since 1.0 33 */ 34final class MultiInputStream extends InputStream { 35 36 private Iterator<? extends ByteSource> it; 37 private InputStream in; 38 39 /** 40 * Creates a new instance. 41 * 42 * @param it an iterator of I/O suppliers that will provide each substream 43 */ 44 public MultiInputStream( 45 Iterator<? extends ByteSource> it) throws IOException { 46 this.it = checkNotNull(it); 47 advance(); 48 } 49 50 @Override public void close() throws IOException { 51 if (in != null) { 52 try { 53 in.close(); 54 } finally { 55 in = null; 56 } 57 } 58 } 59 60 /** 61 * Closes the current input stream and opens the next one, if any. 62 */ 63 private void advance() throws IOException { 64 close(); 65 if (it.hasNext()) { 66 in = it.next().openStream(); 67 } 68 } 69 70 @Override public int available() throws IOException { 71 if (in == null) { 72 return 0; 73 } 74 return in.available(); 75 } 76 77 @Override public boolean markSupported() { 78 return false; 79 } 80 81 @Override public int read() throws IOException { 82 if (in == null) { 83 return -1; 84 } 85 int result = in.read(); 86 if (result == -1) { 87 advance(); 88 return read(); 89 } 90 return result; 91 } 92 93 @Override public int read(@Nullable byte[] b, int off, int len) throws IOException { 94 if (in == null) { 95 return -1; 96 } 97 int result = in.read(b, off, len); 98 if (result == -1) { 99 advance(); 100 return read(b, off, len); 101 } 102 return result; 103 } 104 105 @Override public long skip(long n) throws IOException { 106 if (in == null || n <= 0) { 107 return 0; 108 } 109 long result = in.skip(n); 110 if (result != 0) { 111 return result; 112 } 113 if (read() == -1) { 114 return 0; 115 } 116 return 1 + in.skip(n - 1); 117 } 118} 119