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 019package org.apache.hadoop.io; 020 021import java.io.*; 022import java.net.Socket; 023 024import org.apache.commons.logging.Log; 025 026import org.apache.hadoop.classification.InterfaceAudience; 027import org.apache.hadoop.classification.InterfaceStability; 028import org.apache.hadoop.conf.Configuration; 029 030/** 031 * An utility class for I/O related functionality. 032 */ 033@InterfaceAudience.Public 034@InterfaceStability.Evolving 035public 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 long amt = len; 185 while (amt > 0) { 186 long ret = in.skip(amt); 187 if (ret == 0) { 188 // skip may return 0 even if we're not at EOF. Luckily, we can 189 // use the read() method to figure out if we're at the end. 190 int b = in.read(); 191 if (b == -1) { 192 throw new EOFException( "Premature EOF from inputStream after " + 193 "skipping " + (len - amt) + " byte(s)."); 194 } 195 ret = 1; 196 } 197 amt -= ret; 198 } 199 } 200 201 /** 202 * Close the Closeable objects and <b>ignore</b> any {@link IOException} or 203 * null pointers. Must only be used for cleanup in exception handlers. 204 * 205 * @param log the log to record problems to at debug level. Can be null. 206 * @param closeables the objects to close 207 */ 208 public static void cleanup(Log log, java.io.Closeable... closeables) { 209 for (java.io.Closeable c : closeables) { 210 if (c != null) { 211 try { 212 c.close(); 213 } catch(IOException e) { 214 if (log != null && log.isDebugEnabled()) { 215 log.debug("Exception in closing " + c, e); 216 } 217 } 218 } 219 } 220 } 221 222 /** 223 * Closes the stream ignoring {@link IOException}. 224 * Must only be called in cleaning up from exception handlers. 225 * 226 * @param stream the Stream to close 227 */ 228 public static void closeStream(java.io.Closeable stream) { 229 cleanup(null, stream); 230 } 231 232 /** 233 * Closes the socket ignoring {@link IOException} 234 * 235 * @param sock the Socket to close 236 */ 237 public static void closeSocket(Socket sock) { 238 if (sock != null) { 239 try { 240 sock.close(); 241 } catch (IOException ignored) { 242 } 243 } 244 } 245 246 /** 247 * The /dev/null of OutputStreams. 248 */ 249 public static class NullOutputStream extends OutputStream { 250 public void write(byte[] b, int off, int len) throws IOException { 251 } 252 253 public void write(int b) throws IOException { 254 } 255 } 256}