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