001: /* IoUtils
002: *
003: * Created on Dec 8, 2004
004: *
005: * Copyright (C) 2004 Internet Archive.
006: *
007: * This file is part of the Heritrix web crawler (crawler.archive.org).
008: *
009: * Heritrix is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU Lesser Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * any later version.
013: *
014: * Heritrix is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
017: * GNU Lesser Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser Public License
020: * along with Heritrix; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022: */
023: package org.archive.util;
024:
025: import it.unimi.dsi.fastutil.io.FastBufferedOutputStream;
026:
027: import java.io.BufferedInputStream;
028: import java.io.BufferedOutputStream;
029: import java.io.ByteArrayInputStream;
030: import java.io.ByteArrayOutputStream;
031: import java.io.EOFException;
032: import java.io.File;
033: import java.io.FileInputStream;
034: import java.io.FileOutputStream;
035: import java.io.IOException;
036: import java.io.InputStream;
037: import java.io.ObjectInputStream;
038: import java.io.ObjectOutputStream;
039: import java.io.OutputStream;
040: import java.nio.charset.Charset;
041: import java.util.Iterator;
042: import java.util.List;
043: import java.util.logging.Level;
044: import java.util.logging.Logger;
045:
046: /**
047: * I/O Utility methods.
048: * @author stack
049: * @version $Date: 2007-02-20 23:25:20 +0000 (Tue, 20 Feb 2007) $, $Revision: 4919 $
050: */
051: public class IoUtils {
052: protected static Logger logger = Logger.getLogger(IoUtils.class
053: .getName());
054:
055: /**
056: * @param file File to operate on.
057: * @return Path suitable for use getting resources off the CLASSPATH
058: * (CLASSPATH resources always use '/' as path separator, even on
059: * windows).
060: */
061: public static String getClasspathPath(File file) {
062: String path = file.getPath();
063: if (File.separatorChar != '/') {
064: // OK. We're probably on a windows system. Strip
065: // drive if its present and convert '\' to '/'.
066: path = path.replace(File.separatorChar, '/');
067: int index = path.indexOf(':');
068: if (index > 0 && index < 3) {
069: path = path.substring(index + 1);
070: }
071: }
072: return path;
073: }
074:
075: /**
076: * Ensure writeable directory.
077: *
078: * If doesn't exist, we attempt creation.
079: *
080: * @param dir Directory to test for exitence and is writeable.
081: *
082: * @return The passed <code>dir</code>.
083: *
084: * @exception IOException If passed directory does not exist and is not
085: * createable, or directory is not writeable or is not a directory.
086: */
087: public static File ensureWriteableDirectory(String dir)
088: throws IOException {
089: return ensureWriteableDirectory(new File(dir));
090: }
091:
092: /**
093: * Ensure writeable directories.
094: *
095: * If doesn't exist, we attempt creation.
096: *
097: * @param dirs List of Files to test.
098: *
099: * @return The passed <code>dirs</code>.
100: *
101: * @exception IOException If passed directory does not exist and is not
102: * createable, or directory is not writeable or is not a directory.
103: */
104: public static List ensureWriteableDirectory(List<File> dirs)
105: throws IOException {
106: for (Iterator<File> i = dirs.iterator(); i.hasNext();) {
107: ensureWriteableDirectory(i.next());
108: }
109: return dirs;
110: }
111:
112: /**
113: * Ensure writeable directory.
114: *
115: * If doesn't exist, we attempt creation.
116: *
117: * @param dir Directory to test for exitence and is writeable.
118: *
119: * @return The passed <code>dir</code>.
120: *
121: * @exception IOException If passed directory does not exist and is not
122: * createable, or directory is not writeable or is not a directory.
123: */
124: public static File ensureWriteableDirectory(File dir)
125: throws IOException {
126: if (!dir.exists()) {
127: dir.mkdirs();
128: } else {
129: if (!dir.canWrite()) {
130: throw new IOException("Dir " + dir.getAbsolutePath()
131: + " not writeable.");
132: } else if (!dir.isDirectory()) {
133: throw new IOException("Dir " + dir.getAbsolutePath()
134: + " is not a directory.");
135: }
136: }
137:
138: return dir;
139: }
140:
141: /**
142: * Read the entire stream to EOF, returning what's read as a String.
143: *
144: * @param inputStream
145: * @return String of the whole inputStream's contents
146: * @throws IOException
147: */
148: public static String readFullyAsString(InputStream inputStream)
149: throws IOException {
150: StringBuffer sb = new StringBuffer();
151: int c;
152: while ((c = inputStream.read()) > -1) {
153: sb.append((char) c);
154: }
155: return sb.toString();
156: }
157:
158: /**
159: * Read the entire stream to EOF into the passed file.
160: * @param is
161: * @param toFile File to read into .
162: * @throws IOException
163: * @throws IOException
164: */
165: public static void readFullyToFile(InputStream is, File toFile)
166: throws IOException {
167: readFullyToFile(is, toFile, new byte[4096]);
168: }
169:
170: /**
171: * Read the entire stream to EOF into the passed file.
172: * Closes <code>is</code> when done or if an exception.
173: * @param is Stream to read.
174: * @param toFile File to read into .
175: * @param buffer Buffer to use reading.
176: * @return Count of bytes read.
177: * @throws IOException
178: */
179: public static long readFullyToFile(final InputStream is,
180: final File toFile, final byte[] buffer) throws IOException {
181: long totalcount = -1;
182: OutputStream os = new FastBufferedOutputStream(
183: new FileOutputStream(toFile));
184: InputStream localIs = (is instanceof BufferedInputStream) ? is
185: : new BufferedInputStream(is);
186: try {
187: for (int count = -1; (count = localIs.read(buffer, 0,
188: buffer.length)) != -1; totalcount += count) {
189: os.write(buffer, 0, count);
190: }
191: } finally {
192: os.close();
193: if (localIs != null) {
194: localIs.close();
195: }
196: }
197: return totalcount;
198: }
199:
200: /**
201: * Wrap generic Throwable as a checked IOException
202: * @param e wrapped exception
203: * @return IOException
204: */
205: public static IOException wrapAsIOException(Throwable e) {
206: IOException ioe = new IOException(e.toString());
207: ioe.initCause(e);
208: return ioe;
209: }
210:
211: public static void readFully(InputStream input, byte[] buf)
212: throws IOException {
213: int max = buf.length;
214: int ofs = 0;
215: while (ofs < max) {
216: int l = input.read(buf, ofs, max - ofs);
217: if (l == 0) {
218: throw new EOFException();
219: }
220: ofs += l;
221: }
222: }
223:
224: /**
225: * Return the maximum number of bytes per character in the named
226: * encoding, or 0 if encoding is invalid or unsupported.
227: *
228: * @param encoding Encoding to consider. For now, should be java
229: * canonical name for the encoding.
230: *
231: * @return True if multibyte encoding.
232: */
233: public static float encodingMaxBytesPerChar(String encoding) {
234: boolean isMultibyte = false;
235: final Charset cs;
236: try {
237: if (encoding != null && encoding.length() > 0) {
238: cs = Charset.forName(encoding);
239: if (cs.canEncode()) {
240: return cs.newEncoder().maxBytesPerChar();
241: } else {
242: logger.info("Encoding not fully supported: "
243: + encoding
244: + ". Defaulting to single byte.");
245: }
246: }
247: } catch (IllegalArgumentException e) {
248: // Unsupported encoding
249: logger.log(Level.INFO,
250: "Illegal encoding name: " + encoding, e);
251: }
252:
253: logger.fine("Encoding " + encoding + " is multibyte: "
254: + ((isMultibyte) ? Boolean.TRUE : Boolean.FALSE));
255: // default: return 0
256: return 0;
257: }
258:
259: /**
260: * Utility method to serialize an object to the given File.
261: *
262: * @param object Object to serialize
263: * @param file File to receive serialized copy
264: * @throws IOException
265: */
266: public static void serializeToFile(Object object, File file)
267: throws IOException {
268: ObjectOutputStream oos = new ObjectOutputStream(
269: new BufferedOutputStream(new FileOutputStream(file)));
270: oos.writeObject(object);
271: oos.close();
272: }
273:
274: /**
275: * Utility method to deserialize an Object from given File.
276: *
277: * @param file File source
278: * @return deserialized Object
279: * @throws IOException
280: */
281: public static Object deserializeFromFile(File file)
282: throws IOException {
283: ObjectInputStream ois = new ObjectInputStream(
284: new BufferedInputStream(new FileInputStream(file)));
285: Object object;
286: try {
287: object = ois.readObject();
288: } catch (ClassNotFoundException e) {
289: // TODO Auto-generated catch block
290: throw new RuntimeException(e);
291: }
292: ois.close();
293: return object;
294: }
295:
296: /**
297: * Utility method to serialize Object to byte[].
298: *
299: * @param object Object to be serialized
300: * @return byte[] serialized form
301: */
302: public static byte[] serializeToByteArray(Object object) {
303: ByteArrayOutputStream baos = new ByteArrayOutputStream();
304: try {
305: ObjectOutputStream oos = new ObjectOutputStream(baos);
306: oos.writeObject(object);
307: oos.close();
308: } catch (IOException e) {
309: // shouldn't be possible
310: throw new RuntimeException(e);
311: }
312: return baos.toByteArray();
313: }
314:
315: /**
316: * Utility method to deserialize Object from byte[].
317: *
318: * @param in byte[] source
319: * @return Object deserialized
320: */
321: public static Object deserializeFromByteArray(byte[] in) {
322: Object object;
323: try {
324: ObjectInputStream ois = new ObjectInputStream(
325: new ByteArrayInputStream(in));
326: try {
327: object = ois.readObject();
328: } catch (ClassNotFoundException e) {
329: // TODO Auto-generated catch block
330: throw new RuntimeException(e);
331: }
332: ois.close();
333: } catch (IOException e) {
334: // shouldn't be possible
335: throw new RuntimeException(e);
336: }
337: return object;
338: }
339: }
|