Package ch.inftec.ju.util

Source Code of ch.inftec.ju.util.IOUtil

package ch.inftec.ju.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.inftec.ju.util.io.NewLineReader;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;

/**
* Utility class containing I/O related helper methods. Methods that depend on a charset
* or on a text Reader are not static. In this case, a new IOUtil instance must be created using either the
* default charset or an explicit charset (as specified in the constructor).
* <p>
* The IOUtil class converts line endings to a single LF character ('\n'), regardless of the actual
* line feed policy used in the source file.
* @author tgdmemae
*
*/
public final class IOUtil {
  static final Logger log = LoggerFactory.getLogger(IOUtil.class);
 
  /**
   * The default charset that will be used to initialize an IOUtil instance
   * if no explizit charset is specified.
   */
  private static String defaultCharset = null;
 
  private static int tempFileCounter = 0;
 
  /**
   * The Charset used by the IOUtil instance. If not submitted with the constructor, the
   * defaultCharset will be used.
   */
  private final String charset;
 
  /**
   * Gets the default charset used by the IOUtil classes if no explicit
   * charset is submited with the call. If not changed by the used,
   * this is the system's default charset as returned by
   * Charset.defaultCharset()
   * @return Default charset
   */
  public synchronized static String getDefaultCharset() {
    if (IOUtil.defaultCharset == null) {
      IOUtil.defaultCharset = Charset.defaultCharset().displayName();
    }
    return IOUtil.defaultCharset;
  }
 
  /**
   * Sets the default charset used by the IOUtil classes if no explicit
   * charset is submitted with the call.
   * <p>
   * Note that this will only change the default charset for the IOUtil class
   * and not for the whole java runtime.
   * @param charset Default charset
   */
  public synchronized static void setDefaultCharset(String charset) {
    IOUtil.defaultCharset = charset;
  }
 
  /**
   * Gets the charset that this IOUtil instance uses.
   * @return Charset
   */
  public String getCharset() {
    return this.charset;
  }
 
  /**
   * Creates a new IOUtil instance using the default charset.
   */
  public IOUtil() {
    this(IOUtil.getDefaultCharset());
  }
 
  /**
   * Creates a new IOUtil instance with the specified charset.
   * @param charset
   */
  public IOUtil(String charset) {
    this.charset = charset;
  }
 
  /**
   * Closes the specified Reader and consumes any exception that
   * might be raised.
   * @param reader Reader instance
   */
  public static void close(Reader reader) {
    try {
      log.debug("Closing Reader: " + ObjectUtils.identityToString(reader));
      if (reader != null) reader.close();
    } catch (IOException ex) {
      log.warn("Could not close Reader instance: " + ex.getMessage());
    }
  }
 
  /**
   * Closes the specified InputStream and consumes any exception that
   * might be raised.
   * @param stream InputStream instance
   */
  public static void close(InputStream stream) {
    try {
      log.debug("Closing InputStream: " + ObjectUtils.identityToString(stream));
      if (stream != null) stream.close();
    } catch (IOException ex) {
      log.warn("Could not close InputStream instance: " + ex.getMessage());
    }
  }
 
  /**
   * Closes the specified OutputStream and consumes any exception that
   * might be raised.
   * @param stream OutputStream instance
   */
  public static void close(OutputStream stream) {
    try {
      log.debug("Closing OutputStream: " + ObjectUtils.identityToString(stream));
      if (stream != null) stream.close();
    } catch (IOException ex) {
      log.warn("Could not close OutputStream instance: " + ex.getMessage());
    }
  }
 
  /**
   * Generates a String for the specified reader.
   * @param reader Reader instance
   * @throws JuRuntimeException If the conversion fails
   */
  public static String toString(Reader reader) {
    try {
      return IOUtils.toString(reader);
    } catch (Exception ex) {
      throw new JuRuntimeException("Couldn't generate String for Reader", ex);
    }
  }

  /**
   * Converts the specified String to a String containing Unix style new lines, i.e. \n
   * @param s String to be converted
   * @return String containing \n for line breaks
   */
  public static String toNewLineUnix(String s) {
    NewLineReader reader = new NewLineReader(new StringReader(s), null, IOUtils.LINE_SEPARATOR_UNIX);
    return IOUtil.toString(reader);
  }
 
  /**
   * Creates a new temporary file in the default temporary directory.
   * <p>
   * The file will be new/empty and deleted automatically when the JVM is exited.
   * @return New temporary file
   */
  public static synchronized Path getTemporaryFile() throws JuException {
    try {
      Path tempPath = Files.createTempFile(String.format("%s_%s_%s",
          IOUtil.class.getName(),
          IOUtil.tempFileCounter++,
          System.currentTimeMillis())
          , "tmp");
           
      tempPath.toFile().deleteOnExit();
     
      return tempPath;
    } catch (Exception ex) {
      throw new JuException("Couldn't create temporary file", ex);
    }
  }
 
  /**
   * Deletes the specified file (if it exists) and throws a runtime
   * exception if deletion fails.
   * @param path Path to file to delete
   * @return True if file existed, false otherwise
   */
  public static boolean deleteFile(Path path) {
    if (Files.exists(path)) {
      if (!Files.isRegularFile(path)) {
        throw new JuRuntimeException("Not a regular file: " + path);
      }
      try {
        Files.delete(path);
        return true;
      } catch (Exception ex) {
        throw new JuRuntimeException("Couldn't delete file: " + path, ex);
      }
    } else {
      return false;
    }
  }
 
  /**
   * Delets all specified files (if they exist).
   * @param paths Path to files
   * @return True if at least one file was deleted, false otherwise
   */
  public static boolean deleteFiles(Path... paths) {
    boolean oneDeleted = false;
    for (Path path : paths) {
      if (IOUtil.deleteFile(path)) {
        oneDeleted = true;
      }
    }
    return oneDeleted;
  }
 
  /**
   * Creates a file using the specified path.
   * @param file Path to file
   * @param overwrite If true and the file exists, it will be truncated. Otherwise, an exception will be thrown.
   * @return Path to the file
   */
  public static Path createFile(Path file, boolean overwrite) throws JuException {
    try {
      if (Files.exists(file)) {
        if (Files.isDirectory(file)) {
          throw new JuException("Directory with file name exists: " + file);
        } else {
          if (!overwrite) {
            throw new JuException("File exists: " + file);
          } else {
            // overwrite, i.e. recreate
            Files.delete(file);
            Files.createFile(file);
          }
        }
      } else {
        Files.createDirectories(file.getParent()); // Makes sure directories exist
        Files.createFile(file);
      }
    } catch (JuException ex) {
      throw ex;
    } catch (Exception ex) {
      throw new JuException("Couldn't create file " + file, ex);
    }
   
    return file;
  }
 
  /**
   * Checks if the specified object is Serializable.
   * <p>
   * This will actually perform a Serialization and not just check for tag interfaces.
   * @param obj Object
   * @return True if the objects is serializable, false otherwise
   */
  public static boolean isSerializable(Object obj) {
    try (ObjectOutputStream s = new ObjectOutputStream(new ByteArrayOutputStream())) {
      s.writeObject(obj);
      return true;
    } catch (Exception ex) {
      return false;
    }
  }
 
  /**
   * Lists all files in the specified directory.
   * @param parentDir Parent directory
   * @return List of all files in the directory (recursively)
   */
  public static List<Path> listFiles(Path parentDir) {
    return IOUtil.listFiles(parentDir, Predicates.<Path>alwaysTrue());
  }

  /**
   * Lists all files in the specified parent directory with the specified ending (e.g. .xml).
   * @param parentDir Parent directory
   * @param ending Ending, e.g. .xml
   * @return List of Path instances to files
   */
  public static List<Path> listFiles(Path parentDir, final String ending) {
    return IOUtil.listFiles(parentDir, new Predicate<Path>() {
      @Override
      public boolean apply(Path input) {
        return input.getFileName().toString().endsWith(ending);
      }
    });
  }
 
  /**
   * Lists all files of the specified parent directory that meet the predicate.
   * @param parentDir ParentDirectory
   * @param predicate Predicate whether the file should be included
   * @return List of file paths
   */
  public static List<Path> listFiles(Path parentDir, final Predicate<Path> predicate) {
    final List<Path> files = new ArrayList<>();
   
    try {
      Files.walkFileTree(parentDir, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
          if (predicate.apply(file)) files.add(file);
         
          return FileVisitResult.CONTINUE;
        }
      });
     
      return files;
    } catch (Exception ex) {
      throw new JuRuntimeException("Couldn't list file of directory %s", ex, parentDir);
    }
  }
 
  /**
   * Loads the specified URL resource into a string. This method uses the charset of the
   * IOUtil instance.
   * <p>
   * Line breaks from the source will be converted to LF if necessary.
   * @param url URL to resource
   * @param replacements Optional 'key, value' strings to replace %key% tags in the resource with the specified value
   * @return Loaded resource as string
   * @throws JuException If the resource cannot be loaded
   */
  public String loadTextFromUrl(URL url, String... replacements) throws JuException {
    try {
      if (url == null) {
        throw new JuException("Resource not found: " + url);
      }
     
      try (Reader reader = this.createReader(url)) {
     
        StringBuilder sb = new StringBuilder();
        char[] buff = new char[1024];
        int read;
        while ((read = reader.read(buff)) > 0) {
          sb.append(buff, 0, read);
        }
       
        return JuStringUtils.replaceAll(sb.toString(), replacements);
      }
    } catch (Exception ex) {
      throw new JuException("Couldn't load text from URL " + url, ex);
    }
  }

  /**
   * Creates a Reader for the resource at the specified URL using the IOUtils
   * charset.
   * <p>
   * Line breaks will be automatically converted to LF if necessary.
   * <p>
   * The reader will be buffered.
   * <p>
   * The reader needs to be closed by the client.
   * @param url URL to text resource
   * @return Reader instance
   */
  public BufferedReader createReader(URL url) {
    try {
      BufferedReader reader = new BufferedReader(
          new NewLineReader(
            new InputStreamReader(url.openStream(), this.charset)
              , null, NewLineReader.LF));
      return reader;
    } catch (Exception ex) {
      throw new JuRuntimeException("Couldn't create reader for URL " + url, ex);
    }
  }

  /**
   * Loads properties from the specified URL.
   * @param url
   * @return Properties
   * @throws JuException If loading fails
   */
  public Properties loadPropertiesFromUrl(URL url) throws JuException {
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), this.charset))) {
      Properties props = new Properties();
      props.load(reader);
     
      return props;
    } catch (Exception ex) {
      throw new JuException("Couldn't load properties from URL: " + url, ex);
    }   
  }
 
  /**
   * Writes the specified text to a file.
   * @param text Text
   * @param file File to write to
   * @param overwrite If true, an existing file will be overwritten. If false, it will be preserved.
   * @throws JuException If the file cannot be written
   */
  public void writeTextToFile(String text, Path file, boolean overwrite) throws JuException {
    try {
      if (Files.exists(file)) {
        if (Files.isDirectory(file)) throw new JuException("Directory with file name exists: " + file);
        else if (!overwrite) throw new JuException("File exists: " + file);
      }   
     
      try (BufferedWriter w = Files.newBufferedWriter(file, Charset.forName(this.charset))) {
        w.write(text);
      }
    } catch (JuException ex) {
      throw ex;
    } catch (Exception ex) {
      throw new JuException("Couldn't write text to file: " + file, ex);
    }
  }
 
  /**
   * Opens a Writer to the specified file with this IOUtils character encoding.
   * @param file File to write to
   * @param append If true and the file exists, text will be appended. If the file doesn't exist, we create a new one.
   * @param overwrite If true and the file exists, it will be overwritten. If false and the file exists, a
   * JuException will be thrown. If append is true, overwrite must be false.
   * @return Writer to write to the file. The caller is responsible of closing the writer
   * @throws JuException If the file cannot be opened for writing using the specified options
   */
  public Writer openWriter(Path file, boolean append, boolean overwrite) throws JuException {
    if (append) AssertUtil.assertFalse("When appending, overwrite must be set to false", overwrite);
   
    try {
      OpenOption openOption = StandardOpenOption.WRITE;
      // Handle append case
      if (Files.exists(file) && append) {
        openOption = StandardOpenOption.APPEND;
      } else {
        IOUtil.createFile(file, overwrite);
      }
           
      BufferedWriter w = Files.newBufferedWriter(file, Charset.forName(this.charset), openOption);
      return w;
    } catch (JuException ex) {
      throw ex;
    } catch (Exception ex) {
      throw new JuException("Couldn't open Writer to: " + file, ex);
    }
  }
 
  @Override
  public String toString() {
    return JuStringUtils.toString(this, "charset", this.charset);
  }
}
TOP

Related Classes of ch.inftec.ju.util.IOUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.