001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.apache.hadoop.io;
020    
021    import java.io.*;
022    import java.net.Socket;
023    
024    import org.apache.commons.logging.Log;
025    
026    import org.apache.hadoop.classification.InterfaceAudience;
027    import org.apache.hadoop.classification.InterfaceStability;
028    import org.apache.hadoop.conf.Configuration;
029    
030    /**
031     * An utility class for I/O related functionality. 
032     */
033    @InterfaceAudience.Public
034    @InterfaceStability.Evolving
035    public class IOUtils {
036    
037      /**
038       * Copies from one stream to another.
039       *
040       * @param in InputStrem to read from
041       * @param out OutputStream to write to
042       * @param buffSize the size of the buffer 
043       * @param close whether or not close the InputStream and 
044       * OutputStream at the end. The streams are closed in the finally clause.  
045       */
046      public static void copyBytes(InputStream in, OutputStream out, int buffSize, boolean close) 
047        throws IOException {
048        try {
049          copyBytes(in, out, buffSize);
050          if(close) {
051            out.close();
052            out = null;
053            in.close();
054            in = null;
055          }
056        } finally {
057          if(close) {
058            closeStream(out);
059            closeStream(in);
060          }
061        }
062      }
063      
064      /**
065       * Copies from one stream to another.
066       * 
067       * @param in InputStrem to read from
068       * @param out OutputStream to write to
069       * @param buffSize the size of the buffer 
070       */
071      public static void copyBytes(InputStream in, OutputStream out, int buffSize) 
072        throws IOException {
073        PrintStream ps = out instanceof PrintStream ? (PrintStream)out : null;
074        byte buf[] = new byte[buffSize];
075        int bytesRead = in.read(buf);
076        while (bytesRead >= 0) {
077          out.write(buf, 0, bytesRead);
078          if ((ps != null) && ps.checkError()) {
079            throw new IOException("Unable to write to output stream.");
080          }
081          bytesRead = in.read(buf);
082        }
083      }
084    
085      /**
086       * Copies from one stream to another. <strong>closes the input and output streams 
087       * at the end</strong>.
088       *
089       * @param in InputStrem to read from
090       * @param out OutputStream to write to
091       * @param conf the Configuration object 
092       */
093      public static void copyBytes(InputStream in, OutputStream out, Configuration conf)
094        throws IOException {
095        copyBytes(in, out, conf.getInt("io.file.buffer.size", 4096), true);
096      }
097      
098      /**
099       * Copies from one stream to another.
100       *
101       * @param in InputStream to read from
102       * @param out OutputStream to write to
103       * @param conf the Configuration object
104       * @param close whether or not close the InputStream and 
105       * OutputStream at the end. The streams are closed in the finally clause.
106       */
107      public static void copyBytes(InputStream in, OutputStream out, Configuration conf, boolean close)
108        throws IOException {
109        copyBytes(in, out, conf.getInt("io.file.buffer.size", 4096),  close);
110      }
111    
112      /**
113       * Copies count bytes from one stream to another.
114       *
115       * @param in InputStream to read from
116       * @param out OutputStream to write to
117       * @param count number of bytes to copy
118       * @param close whether to close the streams
119       * @throws IOException if bytes can not be read or written
120       */
121      public static void copyBytes(InputStream in, OutputStream out, long count,
122          boolean close) throws IOException {
123        byte buf[] = new byte[4096];
124        long bytesRemaining = count;
125        int bytesRead;
126    
127        try {
128          while (bytesRemaining > 0) {
129            int bytesToRead = (int)
130              (bytesRemaining < buf.length ? bytesRemaining : buf.length);
131    
132            bytesRead = in.read(buf, 0, bytesToRead);
133            if (bytesRead == -1)
134              break;
135    
136            out.write(buf, 0, bytesRead);
137            bytesRemaining -= bytesRead;
138          }
139          if (close) {
140            out.close();
141            out = null;
142            in.close();
143            in = null;
144          }
145        } finally {
146          if (close) {
147            closeStream(out);
148            closeStream(in);
149          }
150        }
151      }
152      
153      /**
154       * Reads len bytes in a loop.
155       *
156       * @param in InputStream to read from
157       * @param buf The buffer to fill
158       * @param off offset from the buffer
159       * @param len the length of bytes to read
160       * @throws IOException if it could not read requested number of bytes 
161       * for any reason (including EOF)
162       */
163      public static void readFully(InputStream in, byte buf[],
164          int off, int len) throws IOException {
165        int toRead = len;
166        while (toRead > 0) {
167          int ret = in.read(buf, off, toRead);
168          if (ret < 0) {
169            throw new IOException( "Premature EOF from inputStream");
170          }
171          toRead -= ret;
172          off += ret;
173        }
174      }
175      
176      /**
177       * Similar to readFully(). Skips bytes in a loop.
178       * @param in The InputStream to skip bytes from
179       * @param len number of bytes to skip.
180       * @throws IOException if it could not skip requested number of bytes 
181       * for any reason (including EOF)
182       */
183      public static void skipFully(InputStream in, long len) throws IOException {
184        while (len > 0) {
185          long ret = in.skip(len);
186          if (ret < 0) {
187            throw new IOException( "Premature EOF from inputStream");
188          }
189          len -= ret;
190        }
191      }
192      
193      /**
194       * Close the Closeable objects and <b>ignore</b> any {@link IOException} or 
195       * null pointers. Must only be used for cleanup in exception handlers.
196       *
197       * @param log the log to record problems to at debug level. Can be null.
198       * @param closeables the objects to close
199       */
200      public static void cleanup(Log log, java.io.Closeable... closeables) {
201        for (java.io.Closeable c : closeables) {
202          if (c != null) {
203            try {
204              c.close();
205            } catch(IOException e) {
206              if (log != null && log.isDebugEnabled()) {
207                log.debug("Exception in closing " + c, e);
208              }
209            }
210          }
211        }
212      }
213    
214      /**
215       * Closes the stream ignoring {@link IOException}.
216       * Must only be called in cleaning up from exception handlers.
217       *
218       * @param stream the Stream to close
219       */
220      public static void closeStream(java.io.Closeable stream) {
221        cleanup(null, stream);
222      }
223      
224      /**
225       * Closes the socket ignoring {@link IOException}
226       *
227       * @param sock the Socket to close
228       */
229      public static void closeSocket(Socket sock) {
230        if (sock != null) {
231          try {
232            sock.close();
233          } catch (IOException ignored) {
234          }
235        }
236      }
237      
238      /**
239       * The /dev/null of OutputStreams.
240       */
241      public static class NullOutputStream extends OutputStream {
242        public void write(byte[] b, int off, int len) throws IOException {
243        }
244    
245        public void write(int b) throws IOException {
246        }
247      }  
248    }