/* * Copyright (C) 2013 The Java Tool project * Gelin Luo <greenlaw110(at)gmail.com> * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgl.util; import org.osgl.$; import org.osgl.exception.NotAppliedException; import org.osgl.storage.ISObject; import org.osgl.storage.impl.SObject; import java.io.*; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** * IO utilities */ // Some code come from Play!Framework IO.java, under Apache License 2.0 public class IO { public static void close(Closeable closeable) { if (closeable == null) { return; } try { closeable.close(); } catch (Exception e) { // ignore } } public static File child(File file, String fn) { return new File(file, fn); } public static List<File> children(File file) { return Arrays.asList(file.listFiles()); } public static File parent(File file) { return file.getParentFile(); } public static File tmpFile() { return tmpFile(S.random(3), null, null); } public static File tmpFile(String prefix, String suffix) { return tmpFile(prefix, suffix, null); } public static File tmpFile(String prefix, String suffix, File dir) { if (null == prefix) { prefix = S.random(3); } try { return File.createTempFile(prefix, suffix, dir); } catch (IOException e) { throw E.ioException(e); } } /** * Returns a byte array output stream * @return an output stream */ public static OutputStream os() { return new ByteArrayOutputStream(); } /** * Returns a file output stream * @param file the file to which the returned output stream can be used to write to * @return an output stream that can be used to write to file specified */ public static OutputStream os(File file) { try { return new FileOutputStream(file); } catch (FileNotFoundException e) { throw E.ioException(e); } } /** * Returns a string writer * @return an writer that write to string */ public static Writer writer() { return new StringWriter(); } /** * Returns a file writer * @param file the file to be written * @return a writer */ public static Writer writer(File file) { try { return new FileWriter(file); } catch (IOException e) { throw E.ioException(e); } } /** * Returns an empty input stream * @return an empty input stream */ public static InputStream is() { byte[] ba = {}; return new ByteArrayInputStream(ba); } /** * Returns a file input stream * @param file the file to be read * @return inputstream that read the file */ public static InputStream is(File file) { // workaround http://stackoverflow.com/questions/36880692/java-file-does-not-exists-but-file-getabsolutefile-exists if (!file.exists()) { file = file.getAbsoluteFile(); } if (!file.exists()) { throw E.ioException("File does not exists: %s", file.getPath()); } try { return new FileInputStream(file); } catch (FileNotFoundException e) { throw E.ioException(e); } } public static InputStream is(byte[] ba) { return new ByteArrayInputStream(ba); } /** * Returns an input stream from a string which will be encoded with * CharSet.defaultCharset() * @param content the content to be read * @return input stream instance that read the content */ public static InputStream is(String content) { return is(content.getBytes()); } public static InputStream is(URL url) { try { return url.openStream(); } catch (IOException e) { throw E.ioException(e); } } /** * Returns an empty reader * @return a reader that reads empty string "" */ public static Reader reader() { return new StringReader(""); } /** * Returns a file reader * @param file the file to be read * @return a reader that reads the file specified */ public static Reader reader(File file) { try { return new FileReader(file); } catch (IOException e) { throw E.ioException(e); } } public static Reader reader(byte[] ba) { return new StringReader(new String(ba)); } public static Reader reader(InputStream is) { return new InputStreamReader(is); } public static Reader reader(URL url) { try { return reader(url.openStream()); } catch (IOException e) { throw E.ioException(e); } } /** * Returns a string reader from a content specified * @param content the content to be read * @return a string reader instance */ public static Reader reader(String content) { return new StringReader(content); } public static BufferedOutputStream buffered(OutputStream os) { if (os instanceof BufferedOutputStream) { return (BufferedOutputStream)os; } else { return new BufferedOutputStream(os); } } public static BufferedInputStream buffered(InputStream is) { if (is instanceof BufferedInputStream) { return (BufferedInputStream)is; } else { return new BufferedInputStream(is); } } public static BufferedWriter buffered(Writer w) { if (w instanceof BufferedWriter) { return (BufferedWriter)w; } else { return new BufferedWriter(w); } } public static BufferedReader buffered(Reader r) { if (r instanceof BufferedReader) { return (BufferedReader)r; } else { return new BufferedReader(r); } } public static void delete(File file) { delete(file, false); } public static void delete(File f, boolean deleteChildren) { if (null == f || !f.exists()) { return; } if (f.isDirectory()) { String[] sa = f.list(); if (null != sa && sa.length > 0) { if (!deleteChildren) { return; } else { for (File f0 : f.listFiles()) { delete(f0, true); } } } } if (!f.delete()) { f.deleteOnExit(); } } /** * Load properties from a file * @param file the properties file * @return the properties loaded from the file specified */ public static Properties loadProperties(File file) { return loadProperties(IO.is(file)); } /** * Load properties from an inputStream * @param inputStream the input stream to property source * @return the properties loaded from the input stream specified */ public static Properties loadProperties(InputStream inputStream) { Properties prop = new Properties(); try { prop.load(inputStream); } catch (IOException e) { throw E.ioException(e); } finally { IO.close(inputStream); } return prop; } /** * Load properties from an inputStream * @param reader the reader to property source * @return the properties loaded from the reader specified */ public static Properties loadProperties(Reader reader) { Properties prop = new Properties(); try { prop.load(reader); } catch (IOException e) { throw E.ioException(e); } finally { IO.close(reader); } return prop; } /** * Load properties from a string content * @param content the content of a properties file * @return the properties loaded */ public static Properties loadProperties(String content) { return loadProperties(new StringReader(content)); } /** * Read binary content of a file (warning does not use on large file !) * @param file The file te read * @return The binary data */ public static byte[] readContent(File file) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { copy(new BufferedInputStream(new FileInputStream(file)), baos); } catch (FileNotFoundException e) { throw E.ioException(e); } return baos.toByteArray(); } public static byte[] readContent(InputStream is) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); copy(is, baos); return baos.toByteArray(); } /** * Read file content to a String (always use utf-8) * * @param file The file to read * @return The String content */ public static String readContentAsString(File file) { return readContentAsString(file, "utf-8"); } /** * Read file content to a String * * @param url The url resource to read * @param encoding encoding used to read the file into string content * @return The String content */ public static String readContentAsString(URL url, String encoding) { try { return readContentAsString(url.openStream()); } catch (IOException e) { throw E.ioException(e); } } /** * Read file content to a String (always use utf-8) * * @param url the url resource to read * @return The String content */ public static String readContentAsString(URL url) { return readContentAsString(url, "utf-8"); } /** * Read file content to a String * * @param file The file to read * @param encoding encoding used to read the file into string content * @return The String content */ public static String readContentAsString(File file, String encoding) { try { return readContentAsString(new FileInputStream(file), encoding); } catch (FileNotFoundException e) { throw E.ioException(e); } } public static String readContentAsString(InputStream is) { return readContentAsString(is, "utf-8"); } public static String readContentAsString(InputStream is, String encoding) { try { StringWriter result = new StringWriter(); PrintWriter out = new PrintWriter(result); BufferedReader reader = new BufferedReader(new InputStreamReader(is, encoding)); String line; int lineNo = 0; while ((line = reader.readLine()) != null) { if (lineNo++ > 0) out.println(); out.print(line); } return result.toString(); } catch (IOException e) { throw E.ioException(e); } finally { close(is); } } public static List<String> readLines(File file) { return readLines(file, 0); } public static List<String> readLines(File file, int limit) { return readLines(file, "utf-8", limit); } public static List<String> readLines(File file, String encoding) { return readLines(file, encoding, 0); } public static List<String> readLines(File file, String encoding, int limit) { List<String> lines = null; InputStream is = null; try { is = new FileInputStream(file); lines = readLines(is, encoding, limit); } catch (IOException ex) { throw E.ioException(ex); } finally { close(is); } return lines; } public static List<String> readLines(InputStream is, String encoding) { return readLines(is, encoding, 0); } public static List<String> readLines(InputStream is, String encoding, int limit) { if (encoding == null) { return readLines(is, limit); } else { InputStreamReader r = null; try { r = new InputStreamReader(is, encoding); } catch (UnsupportedEncodingException e) { throw E.encodingException(e); } return readLines(r, limit); } } public static List<String> readLines(InputStream inputStream) { return readLines(inputStream, 0); } public static List<String> readLines(InputStream inputStream, int limit) { InputStreamReader r = new InputStreamReader(inputStream); return readLines(r, limit); } public static List<String> readLines(Reader input) { return readLines(input, 0); } public static List<String> readLines(Reader input, int limit) { BufferedReader reader = new BufferedReader(input); List<String> list = new ArrayList<String>(); if (limit < 1) { limit = Integer.MAX_VALUE; } try { int n = 0; String line = reader.readLine(); while ((n++ < limit) && line != null) { list.add(line); line = reader.readLine(); } } catch (IOException e) { throw E.ioException(e); } return list; } /** * Write String content to a file (always use utf-8) * * @param content The content to write * @param file The file to write */ public static void writeContent(CharSequence content, File file) { writeContent(content, file, "utf-8"); } /** * Write String content to a file (always use utf-8) * * @param content The content to write * @param file The file to write * @param encoding encoding used to write the content to file */ public static void writeContent(CharSequence content, File file, String encoding) { OutputStream os = null; try { os = new FileOutputStream(file); PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(os, encoding)); printWriter.println(content); printWriter.flush(); os.flush(); } catch (IOException e) { throw E.unexpected(e); } finally { close(os); } } public static void writeContent(CharSequence content, Writer writer) { try { PrintWriter printWriter = new PrintWriter(writer); printWriter.println(content); printWriter.flush(); writer.flush(); } catch (IOException e) { throw E.ioException(e); } finally { close(writer); } } /** * Copy content from input stream to output stream without closing the output stream * * @param is input stream * @param os output stream * @return number of bytes appended */ public static int append(InputStream is, OutputStream os) { return copy(is, os, false); } public static int copy(InputStream is, OutputStream os) { return copy(is, os, true); } /** * Copy an stream to another one. It close the input stream anyway. * * If the param closeOs is true then close the output stream * @param is input stream * @param os output stream * @param closeOs specify whether it shall close output stream after operation * @return number of bytes copied */ public static int copy(InputStream is, OutputStream os, boolean closeOs) { try { int read, total = 0; byte[] buffer = new byte[8096]; while ((read = is.read(buffer)) > 0) { os.write(buffer, 0, read); total += read; } return total; } catch(IOException e) { throw E.ioException(e); } finally { close(is); if (closeOs) { close(os); } } } /** * Alias of {@link #copy(java.io.InputStream, java.io.OutputStream)} * @param is input stream * @param os output stream */ public static int write(InputStream is, OutputStream os) { return copy(is, os); } public static int write(InputStream is, File f) { try { return copy(is, new BufferedOutputStream(new FileOutputStream(f))); } catch (FileNotFoundException e) { throw E.ioException(e); } } /** * Write binary data to a file * @param data The binary data to write * @param file The file to write */ public static void write(byte[] data, File file) { try { write(new ByteArrayInputStream(data), new BufferedOutputStream(new FileOutputStream(file))); } catch (FileNotFoundException e) { throw E.ioException(e); } } /** * Write binary data to an output steam * @param data the binary data to write * @param os the output stream */ public static void write(byte[] data, OutputStream os) { write(new ByteArrayInputStream(data), os); } // If target does not exist, it will be created. public static void copyDirectory(File source, File target) { if (source.isDirectory()) { if (!target.exists()) { target.mkdir(); } for (String child: source.list()) { copyDirectory(new File(source, child), new File(target, child)); } } else { try { write(new FileInputStream(source), new FileOutputStream(target)); } catch (IOException e) { if (target.isDirectory()) { if (!target.exists()) { if (!target.mkdirs()) { throw E.ioException("cannot copy [%s] to [%s]", source, target); } } target = new File(target, source.getName()); } else { File targetFolder = target.getParentFile(); if (!targetFolder.exists()) { if (!targetFolder.mkdirs()) { throw E.ioException("cannot copy [%s] to [%s]", source, target); } } } try { write(new FileInputStream(source), new FileOutputStream(target)); } catch (IOException e0) { throw E.ioException(e0); } } } } public static ISObject zip(ISObject... objects) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zos = new ZipOutputStream(baos); try { for (ISObject obj: objects) { ZipEntry entry = new ZipEntry(obj.getAttribute(SObject.ATTR_FILE_NAME)); InputStream is = obj.asInputStream(); zos.putNextEntry(entry); copy(is, zos, false); zos.closeEntry(); } } catch (IOException e) { throw E.ioException(e); } finally { close(zos); } return SObject.of(Codec.encodeUrl(S.random()), baos.toByteArray()); } public static File zip(File... files) { try { File temp = File.createTempFile("osgl", ".zip"); zipInto(temp, files); return temp; } catch (IOException e) { throw E.ioException(e); } } public static void zipInto(File target, File... files) { ZipOutputStream zos = null; try { zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(target))); byte[] buffer = new byte[128]; for (File f : files) { ZipEntry entry = new ZipEntry(f.getName()); InputStream is = new BufferedInputStream(new FileInputStream(f)); zos.putNextEntry(entry); int read = 0; while ((read = is.read(buffer)) != -1) { zos.write(buffer, 0, read); } zos.closeEntry(); IO.close(is); } } catch (IOException e) { throw E.ioException(e); } finally { IO.close(zos); } } public static final class F { public static <T> $.Function<?, T> println() { return PRINTLN; } public static $.Function PRINTLN = print("", "\n", System.out); public static <T> $.Function<?, T> print() { return PRINT; } public static $.Function PRINT = print("", "", System.out); public static <T> $.Function<T, ?> print(String prefix, String suffix) { return print(prefix, suffix, System.out); } public static <T> $.Function<T, ?> print(String prefix, String suffix, PrintStream ps) { return new $.F4<T, String, String, PrintStream, Void>() { @Override public Void apply(T t, String prefix, String suffix, PrintStream ps) { StringBuilder sb = new StringBuilder(prefix).append(t).append(suffix); ps.print(sb); return null; } }.curry(prefix, suffix, ps); } public static final $.Function<File, InputStream> FILE_TO_IS = new $.F1<File, InputStream>() { @Override public InputStream apply(File file) throws NotAppliedException, $.Break { try { return new BufferedInputStream(new FileInputStream(file)); } catch (IOException e) { throw E.ioException(e); } } }; } }