All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.indeed.util.io.Files Maven / Gradle / Ivy

There is a newer version: 1.0.52-3042601
Show newest version
// $Id$
package com.indeed.util.io;

import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.hash.Hashing;
import com.google.common.io.ByteStreams;

import org.apache.log4j.Logger;

import javax.annotation.Nonnull;

import java.io.*;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

/**
 * @author ahudson
 */
public class Files {
    // you may wish to use this particular logger sparingly, as many times it can be more helpful
    // if you log stuff to a more specific (context-specific) logger than something in common-util
    private static final Logger LOGGER = Logger.getLogger(Files.class);

    private Files() {
    }

    public static String buildPath(String ... parts) {
        if (parts.length == 0) return null;
        if (parts.length == 1) return parts[0];
        File temp = new File(parts[0], parts[1]);
        for (int i = 2; i < parts.length; i++) {
            temp = new File(temp, parts[i]);
        }
        return temp.getPath();
    }

    /**
     * Serializes an object to a file, throws an exception if it fails
     *
     * @param obj object to write to a file
     * @param file path to save the object to
     * @throws java.io.IOException if the existing file could not be erased, or the file could not be written, flushed, synced, or closed
     */
    public static void writeObjectToFileOrDie(@Nonnull final Object obj, @Nonnull final String file) throws IOException {
        writeObjectToFileOrDie(obj, file, LOGGER);
    }

    /**
     * Serializes an object to a file, throws an exception if it fails
     * 
     * @param obj object to write to a file
     * @param file path to save the object to
     * @param log logger to use
     * @throws java.io.IOException if the existing file could not be erased, or the file could not be written, flushed, synced, or closed
     */
    public static void writeObjectToFileOrDie(@Nonnull final Object obj, @Nonnull final String file, @Nonnull final Logger log) throws IOException {
        Preconditions.checkNotNull(file, "file argument is required!");
        Preconditions.checkArgument(!file.isEmpty(), "file argument is required!");

        // todo: should 'obj' be required? do we ever WANT to write 'null' to an artifact?
        Preconditions.checkNotNull(obj, "cannot write a 'null' object");

        final File targetFile = new File(file);

        // write object to temporary file that is flushed, fsynced, and closed by the time it returns
        final ObjectOutputStreamCallback callback = new ObjectOutputStreamCallback(obj);
        final File tmpFile = writeDataToTempFileOrDie(callback, targetFile, log);
        final long checksumForWrittenData = callback.getChecksumValue();

        // verify that what we WROTE to the disk is then immediately READABLE before allowing the rename to happen
        final long checksumFound = computeFileChecksum(tmpFile, new CRC32());
        if (checksumForWrittenData != checksumFound) {
            throw new IOException("Data written to file is not what we expected, " + checksumFound + " != " + checksumForWrittenData + ": " + tmpFile);
        }

        if (!tmpFile.renameTo(targetFile)) {
            // failed to atomically rename from temp file to target file, so throw an exception, leaving the filesystem in
            // a sane state at all times
            throw new IOException("Could not rename '" + tmpFile + "' to '" + targetFile + "'.");
        }
    }
    private static class ObjectOutputStreamCallback implements OutputStreamCallback {
        private long checksumForWrittenData = 0L;
        @Nonnull
        private final Object obj;

        private ObjectOutputStreamCallback(@Nonnull Object obj) {
            this.obj = obj;
        }

        public long getChecksumValue() {
            return checksumForWrittenData;
        }

        @Override
        public void writeAndFlushData(@Nonnull OutputStream outputStream) throws IOException {
            final ChecksummingOutputStream checksummingOutputStream = new ChecksummingOutputStream(new BufferedOutputStream(outputStream));
            final ObjectOutputStream out = new ObjectOutputStream(checksummingOutputStream);

            // write the data
            out.writeObject(obj);
            // flush the various streams
            out.flush();

            checksumForWrittenData = checksummingOutputStream.getChecksumValue();
        }
    }
    
    private static class ChecksummingOutputStream extends FilterOutputStream {
        @Nonnull
        private final Checksum checksummer;

        private ChecksummingOutputStream(OutputStream out) {
            super(out);
            checksummer = new CRC32();
        }

        @Override
        public void write(int b) throws IOException {
            out.write(b);
            checksummer.update(b & 0xff);
        }

        @Override
        public void write(byte[] b) throws IOException {
            out.write(b);
            checksummer.update(b, 0, b.length);
        }

        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            out.write(b, off, len);
            checksummer.update(b, off, len);
        }

        /**
         * Returns the current checksum value.
         * @return the current checksum value
         */
        public long getChecksumValue() {
            return checksummer.getValue();
        }
    }

    private static interface OutputStreamCallback {
        void writeAndFlushData(@Nonnull final OutputStream outputStream) throws IOException;
    }

    // return a reference to a temp file that contains the written + flushed + fsynced + closed data
    @Nonnull
    private static File writeDataToTempFileOrDie(@Nonnull final OutputStreamCallback callback,
                                                 @Nonnull final File targetFile,
                                                 @Nonnull final Logger log) throws IOException {
        Preconditions.checkNotNull(callback, "callback argument is required!");
        Preconditions.checkNotNull(log, "log argument is required!");
        Preconditions.checkNotNull(targetFile, "targetFile argument is required!");

        FileOutputStream fileOut = null;
        FileChannel fileChannel = null;
        try {
            final String targetFinalName = targetFile.getName();
            final File targetDirectory = targetFile.getParentFile();

            // open temporary file
            final File tmpFile = File.createTempFile(targetFinalName, ".tmp", targetDirectory);

            fileOut = new FileOutputStream(tmpFile);
            fileChannel = fileOut.getChannel();

            // make sure to use an output stream that flows THROUGH the FileChannel, so that FileChannel.force(true)
            // can do what it's supposed to

            // write the data AND flush it
            callback.writeAndFlushData(Channels.newOutputStream(fileChannel));

            return tmpFile;
        } finally {
            try {
                // fsync to disk (both data AND length)
                if (fileChannel != null) {
                    fileChannel.force(true);
                }
            } finally {
                // close the open file (if during an EXC,
                if (fileOut != null) {
                    fileOut.close();
                }
            }
        }
    }

    @Nonnull
    private static File writeTextToTempFileOrDie(
            @Nonnull final String[] text,
            @Nonnull final File targetFile,
            @Nonnull final Logger log
    ) throws IOException {
        Preconditions.checkNotNull(text, "callback argument is required!");
        Preconditions.checkNotNull(log, "log argument is required!");
        Preconditions.checkNotNull(targetFile, "targetFile argument is required!");

        final String targetFinalName = targetFile.getName();
        final File targetDirectory = targetFile.getParentFile();

        // open temporary file
        final File tmpFile = File.createTempFile(targetFinalName, ".tmp", targetDirectory);

        FileOutputStream fileOut = new FileOutputStream(tmpFile);
        Writer writer = new PrintWriter(new OutputStreamWriter(fileOut, Charsets.UTF_8));
        FileChannel fileChannel = null;
        try {
            fileChannel = fileOut.getChannel();
            for (String line : text) {
                writer.write(line);
                writer.write('\n');
            }
            writer.flush();
            return tmpFile;
        } finally {
            try {
                // fsync to disk (both data AND length)
                if (fileChannel != null) {
                    fileChannel.force(true);
                }
            } finally {
                fileOut.close();
            }
        }
    }

    /**
     * Writes an object to a file only if it is different from the current
     * contents of the file, or if the file does not exist.  Note that you must
     * have enough heap to contain the entire contents of the object graph.
     *
     * @param obj object to write to a file
     * @param file path to save the object to
     * @return true if the file was actually written, false if the file was unchanged
     * @throws java.io.IOException if the existing file could not be read for comparison,
     *                             if the existing file could not be erased,
     *                             or if the new file could not be written, flushed, synced, or closed
     */
    public static boolean writeObjectIfChangedOrDie(@Nonnull final Object obj, @Nonnull final String file) throws IOException {
        return writeObjectIfChangedOrDie(obj, file, LOGGER);
    }

    /**
     * Writes an object to a file only if it is different from the current
     * contents of the file, or if the file does not exist.  Note that you must
     * have enough heap to contain the entire contents of the object graph.
     *
     * @param obj object to write to a file
     * @param file path to save the object to
     * @param log logger to use
     * @return true if the file was actually written, false if the file was unchanged
     * @throws java.io.IOException if the existing file could not be read for comparison,
     *                             if the existing file could not be erased, 
     *                             or if the new file could not be written, flushed, synced, or closed
     */
    public static boolean writeObjectIfChangedOrDie(@Nonnull final Object obj, @Nonnull final String file, @Nonnull final Logger log) throws IOException {
        Preconditions.checkNotNull(log, "log argument is required!");

        Preconditions.checkNotNull(file, "file argument is required!");
        Preconditions.checkArgument(!file.isEmpty(), "file argument is required!");

        // todo: should 'obj' be required? do we ever WANT to write 'null' to an artifact?
        Preconditions.checkNotNull(obj, "cannot write a 'null' object to file %s", file);

        // first serialize the object into a byte array, this should almost never fail
        final IndexableByteArrayOutputStream baos = new IndexableByteArrayOutputStream(524288);
        {
            final ObjectOutputStream out = new ObjectOutputStream(baos);
            out.writeObject(obj);
            out.close();
            baos.close();
        }

        if (isChanged(baos.unsafeByteArrayView(), baos.size(), file)) {
            // compute the checksum of what we intend on writing to disk
            final Checksum checksum = new CRC32();
            checksum.update(baos.unsafeByteArrayView(), 0, baos.size());
            final long checksumForWrittenData =  checksum.getValue();

            final File targetFile = new File(file);

            // write object to temporary file that is flushed, fsynced, and closed by the time it returns
            final File tmpFile = writeDataToTempFileOrDie(new OutputStreamCallback(){
                @Override
                public void writeAndFlushData(@Nonnull OutputStream outputStream) throws IOException {
                    // write the data
                    baos.writeTo(outputStream);
                    // flush it, so that the fsync() has everything it needs
                    outputStream.flush();
                }
            }, targetFile, log);

            // verify that what we WROTE to the disk is then immediately READABLE before allowing the rename to happen
            checksum.reset();
            final long checksumFound = computeFileChecksum(tmpFile, new CRC32());
            if (checksumForWrittenData != checksumFound) {
                throw new IOException("Data written to file is not what we expected, " + checksumFound + " != " + checksumForWrittenData + ": " + tmpFile);
            }
            
            if (!tmpFile.renameTo(targetFile)) {
                // failed to atomically rename from temp file to target file, so throw an exception, leaving the filesystem in
                // a sane state at all times
                throw new IOException("Could not rename '" + tmpFile + "' to '" + targetFile + "'.");
            }

            return true;
        } else {
            return false;
        }
    }

    public static long computeFileChecksum(@Nonnull final File file, @Nonnull final Checksum checksum) throws IOException {
        return ByteStreams.hash(com.google.common.io.Files.newInputStreamSupplier(file), Hashing.crc32())
            .padToLong();
    }

    /**
     * Writes an object to a file.
     * @return true if the file was successfully written, false otherwise
     * @deprecated use {@link #writeObjectToFileOrDie(Object, String, org.apache.log4j.Logger)} instead
     */
    @Deprecated
    public static boolean writeObjectToFile(Object obj, String file) {
        try {
            writeObjectToFileOrDie(obj, file, LOGGER);
            return true;
        } catch (Exception e) {
            LOGGER.error(e.getClass() + ": writeObjectToFile(" + file + ") encountered exception: " + e.getMessage(), e);
            return false;
        }
    }

    /**
     * Writes an object to a file only if it is different from the current
     * contents of the file, or if the file does not exist.  Note that you must
     * have enough heap to contain the entire contents of the object graph.
     *
     * @return true if the file was actually written, false otherwise
     * @deprecated use {@link #writeObjectIfChangedOrDie(Object, String, org.apache.log4j.Logger)} instead
     */
    @Deprecated
    public static boolean writeObjectIfChanged(Object obj, String filepath) {
        try {
            return writeObjectIfChangedOrDie(obj, filepath, LOGGER);
        } catch (Exception e) {
            LOGGER.error(e.getClass() + ": writeObjectIfChanged(" + filepath + ") encountered exception: " + e.getMessage(), e);
            return false;
        }
    }

    /**
     * Returns true iff the bytes in an array are different from the bytes
     * contained in the given file, or if the file does not exist.
     */
    private static boolean isChanged(byte[] bytes, String filepath) throws IOException {
        return isChanged(bytes, bytes.length,  filepath);
    }

    /**
     * Returns true iff the bytes in an array are different from the bytes
     * contained in the given file, or if the file does not exist.
     */
    private static boolean isChanged(final byte[] bytes, final int length, final String filepath) throws IOException {
        Preconditions.checkArgument(length >= 0, "invalid length value: %s", length);
        Preconditions.checkArgument(bytes.length >= length, "invalid length value: %s", length);

        File file = new File(filepath);
        if (!file.exists()) {
            return true;
        }
        if (file.length() != length) {
            return true;
        }
        final int BUFLEN = 1048576; // 1 megabyte
        byte[] buffer = new byte[BUFLEN];
        InputStream is = new FileInputStream(file);
        try {
            int len;
            for (int offset = 0; ; offset += len) {
                len = is.read(buffer);
                if (len < 0) break; // eof
                if (!arrayCompare(bytes, offset, buffer, 0, len)) return true;
            }
            return false;
        } finally {
            is.close();
        }
    }

    /**
     * Returns true if the array chunks are equal, false otherwise.
     */
    private static boolean arrayCompare(byte[] a, int offset1, byte[] a2, int offset2, int length) {
        for (int i = 0; i < length; i++) {
            if (a[offset1++] != a2[offset2++]) return false;
        }
        return true;
    }

    /**
     * Reads an object of type {@code T} from {@code file}.
     *
     * @param file file from which the object should be read
     * @param clazz non-null Class object for {@code T}
     * @param printException whether or not any stacktraces should be printed
     * @param  the return type
     * @return possibly null object of type {@code T}.
     */
    public static  T readObjectFromFile(String file, Class clazz, boolean printException) {
        final FileInputStream fileIn;
        try {
            fileIn = new FileInputStream(file);
        } catch (Exception e) {
            printException(e, printException);
            return null;
        }

        final BufferedInputStream bufferedIn = new BufferedInputStream(fileIn);
        final ObjectInputStream objIn;
        try {
            objIn = new ObjectInputStream(bufferedIn);
        } catch (Exception e) {
            printException(e, printException);
            closeInputStream(fileIn, printException);
            return null;
        }

        final Object ret;
        try {
            ret = objIn.readObject();
        } catch (Exception e) {
            printException(e, printException);
            closeInputStream(objIn, printException); // objIn.close() also closes fileIn
            return null;
        }

        closeInputStream(objIn, printException); // objIn.close() also closes fileIn
        return clazz.cast(ret);
    }

    /**
     * Convenience for
     * {@link #readObjectFromFile(String file, Class clazz, boolean printException)}
     * where:
     * 
    *
  • {@code clazz} is Object.class
  • *
  • {@code printException} is false
  • *
*/ public static Object readObjectFromClasspathDir(String file) { return readObjectFromClasspathDir(file, Object.class, false); } public static T readObjectFromClasspathDir(String file, Class clazz, boolean printException) { //final FileInputStream fileIn; /*try { fileIn = new FileInputStream(file); } catch (Exception e) { printException(e, printException); return null; } */ final InputStream inStream = Files.class.getResourceAsStream(file); final BufferedInputStream bufferedIn = new BufferedInputStream(inStream); final ObjectInputStream objIn; try { objIn = new ObjectInputStream(bufferedIn); } catch (Exception e) { printException(e, printException); closeInputStream(inStream, printException); return null; } final Object ret; try { ret = objIn.readObject(); } catch (Exception e) { printException(e, printException); closeInputStream(objIn, printException); // objIn.close() also closes fileIn return null; } closeInputStream(objIn, printException); // objIn.close() also closes fileIn return clazz.cast(ret); } private static void closeInputStream(final InputStream in, final boolean printException) { try { in.close(); } catch (Exception e) { printException(e, printException); } } private static void printException(final Exception e, final boolean reallyPrintIt) { if (!reallyPrintIt) return; e.printStackTrace(); } /** * Convenience for * {@link #readObjectFromFile(String file, Class clazz, boolean printException)} * where: *
    *
  • {@code printException} is false
  • *
*/ public static T readObjectFromFile(String file, Class clazz) { return readObjectFromFile(file, clazz, false); } /** * Convenience for * {@link #readObjectFromFile(String file, Class clazz, boolean printException)} * where: *
    *
  • {@code clazz} is Object.class
  • *
*/ public static Object readObjectFromFile(String file, boolean printException) { return readObjectFromFile(file, Object.class, printException); } /** * Convenience for * {@link #readObjectFromFile(String file, Class clazz, boolean printException)} * where: *
    *
  • {@code clazz} is Object.class
  • *
  • {@code printException} is false
  • *
*/ public static Object readObjectFromFile(String file) { return readObjectFromFile(file, Object.class, false); } public static String[] readTextFile(String file) { try { return readTextFileOrDie(file); } catch (Exception e) { e.printStackTrace(); return null; } } public static String[] readTextFileOrDie(String file) throws IOException { ArrayList contents = new ArrayList(); BufferedReader reader = getBufferedReaderForUtf8(file); try { String line = reader.readLine(); while (line != null) { contents.add(line); line = reader.readLine(); } } finally { reader.close(); } return contents.toArray(new String[contents.size()]); } /** * Reads all the lines in the given file, truncating everything that happens after # (including the #) * @param file * @return a List of the lines in the file in the order they appear (whitespace trimmed) * @throws IOException */ public static List readCommentedTextFile(final String file) throws IOException { BufferedReader reader = getBufferedReaderForUtf8(file); try { final List lines = new ArrayList(); for (String line = reader.readLine(); line != null; line = reader.readLine()) { final String trimmed = line.trim(); if (trimmed.length() == 0) { continue; } final int hashIndex = trimmed.indexOf('#'); if (hashIndex == -1) { lines.add(trimmed); } else { final String realPart = trimmed.substring(0, hashIndex).trim(); if (realPart.length() > 0) { lines.add(realPart); } } } return lines; } finally { try { reader.close(); } catch (final IOException e) { // intentionally empty } } } public static int[] readIntsFromTextFile(String file) { String[] strings = readTextFile(file); if (strings == null) return null; int[] ints = new int[strings.length]; for (int i = 0; i < strings.length; i++) ints[i] = Integer.parseInt(strings[i]); return ints; } public static float[] readFloatsFromTextFile(String file) { String[] strings = readTextFile(file); if (strings == null) return null; float[] floats = new float[strings.length]; for (int i = 0; i < strings.length; i++) floats[i] = Float.parseFloat(strings[i]); return floats; } @Deprecated public static void writeToTextFile(String[] lines, String file) { try { final BufferedWriter bufferedWriter = getBufferedWriterForUtf8(file); for (String line : lines) { bufferedWriter.write(line); bufferedWriter.newLine(); } bufferedWriter.close(); } catch (Exception e) { e.printStackTrace(); } } public static void writeToTextFileOrDie( @Nonnull final String[] lines, @Nonnull final String file ) throws IOException { // Write out a temp file (or die) final File f = new File(file); final File temp = writeTextToTempFileOrDie(lines, f, LOGGER); // Rename the temp file if writing succeeded if (!temp.renameTo(f)) { throw new IOException(String.format( "couldn't rename %s to %s", temp.getCanonicalPath(), file )); } } public static void appendToTextFile(String[] lines, String file) { try { PrintStream out = new PrintStream(new FileOutputStream(file, true)); for (String line : lines) { out.println(line); } out.close(); } catch (Exception e) { e.printStackTrace(); } } public static String getTempDirectory(String prefix, String suffix) throws IOException { return getTempDirectory(prefix, suffix, (File)null); } public static String getTempDirectory(String prefix, String suffix, String directory) throws IOException { File dir = null; if (directory != null) { dir = new File(directory); if (!dir.exists()) { if (!dir.mkdirs()) { throw new IOException("directory did not exist and could not be created: " + directory); } } } return getTempDirectory(prefix, suffix, dir); } public static String getTempDirectory(String prefix, String suffix, File directory) throws IOException { File f = File.createTempFile(prefix, suffix, directory); f.delete(); f.mkdir(); return f.getAbsolutePath(); } /** * Deletes file or recursively deletes a directory * * NOTE: this returns true if the file was actually deleted, and false for 2 cases: * 1. file did not exist to start with * 2. File.delete() failed at some point for some reason * * use {@link #deleteOrDie(String)} instead if you want a clearer distinction between the 'falsy' responses * * @param file path to erase * @return true if all deletions were successful. If a deletion fails, the method stops attempting to delete and returns false */ public static boolean delete(String file) { File f = new File(file); if (f.isDirectory()) { // first insure the directory is empty String[] children = f.list(); for (String child : children) { if (!delete(Files.buildPath(file, child))) return false; } } return f.delete(); } /** * Deletes file or recursively deletes a directory * @param file path to erase * @return true if all deletions were successful, false if file did not exist * @throws IOException if deletion fails and the file still exists at the end */ public static boolean deleteOrDie(@Nonnull final String file) throws IOException { // this returns true if the file was actually deleted // and false for 2 cases: // 1. file did not exist to start with // 2. File.delete() failed at some point for some reason // so we disambiguate the 'false' case below by checking for file existence final boolean fileWasDeleted = delete(file); if (fileWasDeleted) { // file was definitely deleted return true; } else { final File fileObj = new File(file); if (fileObj.exists()) { throw new IOException("File still exists after erasure, cannot write object to file: " + file); } // file was not deleted, because it does not exist return false; } } /** * Use this function instead of {@link java.io.File#getCanonicalPath()}, as that method * can fail during symlink changes, and this method will retry up to 3 times with a * short delay. Returns null if unsuccessful after retrying. * * @param path path to canonicalize * @return the canonical pathname, or null if unsuccessful */ public static String getCanonicalPath(String path) { if (path == null) return null; return getCanonicalPath( path, new Supplier() { int retries = 2; public Boolean get() { if (retries-- == 0) { return false; } try { // if retries not exhausted, sleep 100 milliseconds Thread.sleep(100); } catch (InterruptedException e) { return false; } return true; } } ); } static String getCanonicalPath(String path, Supplier retryPolicy) { boolean shouldRetry = true; while (shouldRetry) { File file = new File(path); if (file.exists()) { try { return file.getCanonicalPath(); } catch (IOException e) { // try again I guess } } shouldRetry = retryPolicy.get(); } return null; } /** * Gets the directory name of the canonical path -- the last element in the result of * {@link #getCanonicalPath(String)}. * @param path path to canonicalize * @return canonical directory name */ public static String getCanonicalDirectoryName(String path) { String realPath = getCanonicalPath(path); if (realPath == null) { return null; } String separator = System.getProperty("file.separator", "/"); // backslashes must be escaped for split(). kthxbai separator = Pattern.quote(separator); String[] pathElements = realPath.split(separator); return pathElements.length > 0 ? pathElements[pathElements.length - 1] : realPath; } public static byte[] loadFileAsByteArray(final String file) throws IOException { final InputStream inputStream = new BufferedInputStream(new FileInputStream(file)); try { final ByteArrayOutputStream out = new ByteArrayOutputStream(10000); while (true) { final int val = inputStream.read(); if (val == -1) break; out.write(val); } return out.toByteArray(); } finally { inputStream.close(); } } public static String getFileHash(final String file, final String algorithm) throws IOException, NoSuchAlgorithmException { final MessageDigest md = MessageDigest.getInstance(algorithm); return Files.toHex(md.digest(loadFileAsByteArray(file))); } /** * Converts a byte array to a hex string. The String returned * will be of length exactly {@code bytes.length * 2}. */ @Nonnull public static String toHex(@Nonnull final byte[] bytes) { StringBuilder buf = new StringBuilder(bytes.length * 2); for (byte b : bytes) { String hexDigits = Integer.toHexString((int) b & 0x00ff); if (hexDigits.length() == 1) { buf.append('0'); } buf.append(hexDigits); } return buf.toString(); } public static BufferedReader getBufferedReaderForUtf8(String file) throws FileNotFoundException { try { final FileInputStream fileInputStream = new FileInputStream(file); final InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8"); return new BufferedReader(inputStreamReader); } catch (UnsupportedEncodingException uee) { // Should never occur! throw new RuntimeException(uee); } } private static BufferedWriter getBufferedWriterForUtf8(String file) throws FileNotFoundException { try { final FileOutputStream fileOutputStream = new FileOutputStream(file); final OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8"); return new BufferedWriter(outputStreamWriter); } catch (UnsupportedEncodingException uee) { // Should never occur! throw new RuntimeException(uee); } } public static String readStreamAsString(final InputStream in) throws IOException { return readStreamAsString(in, 256); } public static String readStreamAsString(final InputStream in, final int bufferSize) throws IOException { final StringBuilder sb = new StringBuilder(); final char[] buffer = new char[bufferSize]; final InputStreamReader reader = new InputStreamReader(new BufferedInputStream(in)); for (int read = reader.read(buffer); read != -1; read = reader.read(buffer)) { if (read > 0) { sb.append(buffer, 0, read); } } return sb.toString(); } /** * Use this instead of {@link FileWriter} because you cannot specify the character encoding with that. */ public static Writer newBufferedUTF8FileWriter(final String file) throws UnsupportedEncodingException, FileNotFoundException { return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); } /** * Use this instead of {@link FileWriter} because you cannot specify the character encoding with that. */ public static Writer newBufferedUTF8FileWriter(final File file) throws UnsupportedEncodingException, FileNotFoundException { return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy