001/* 002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others 003 * 004 * This program and the accompanying materials are made available under the 005 * terms of the Eclipse Public License 2.0 which is available at 006 * http://www.eclipse.org/legal/epl-2.0. 007 * 008 * SPDX-License-Identifier: EPL-2.0 009 */ 010package gololang; 011 012import java.io.BufferedOutputStream; 013import java.io.File; 014import java.io.IOException; 015import java.io.OutputStream; 016import java.io.PrintStream; 017import java.net.MalformedURLException; 018import java.net.URI; 019import java.net.URL; 020import java.nio.charset.Charset; 021import java.nio.file.Files; 022import java.nio.file.Path; 023import java.nio.file.Paths; 024import java.nio.file.StandardOpenOption; 025 026import static gololang.Predefined.require; 027 028/** 029 * Module providing IO related utility functions. 030 */ 031public final class IO { 032 private IO() { 033 // utility class 034 } 035 036 /** 037 * Returns the default charset. 038 */ 039 public static Charset defaultCharset() { 040 return Charset.defaultCharset(); 041 } 042 043 /** 044 * Convert the given String or Charset object into a Charset. 045 */ 046 public static Charset toCharset(Object encoding) { 047 if (encoding == null) { 048 return defaultCharset(); 049 } 050 Charset charset = null; 051 if (encoding instanceof String) { 052 charset = Charset.forName((String) encoding); 053 } else if (encoding instanceof Charset) { 054 charset = (Charset) encoding; 055 } else { 056 throw new IllegalArgumentException("Can't get a charset from a " 057 + encoding.getClass().getName()); 058 } 059 return charset; 060 } 061 062 /** 063 * Reads the content of a text file. 064 * 065 * @param file the file to read from as an instance of either {@link String}, {@link File} or {@link Path}. 066 * @param encoding the file encoding as a {@link String} or {@link Charset}. 067 * @return the content as a {@link String}. 068 */ 069 public static String fileToText(Object file, Object encoding) throws Throwable { 070 return new String(Files.readAllBytes(toPath(file)), toCharset(encoding)); 071 } 072 073 /** 074 * Polymorphic {@link java.nio.file.Path} creation. 075 * 076 * @param file the file descriptor as an instance of either {@link String}, {@link File} or {@link Path}. 077 * @return the corresponding {@link java.nio.file.Path} object. 078 */ 079 public static Path toPath(Object file) { 080 if (file == null) { 081 return null; 082 } else if (file instanceof String) { 083 return Paths.get((String) file); 084 } else if (file instanceof File) { 085 return ((File) file).toPath(); 086 } else if (file instanceof Path) { 087 return (Path) file; 088 } 089 throw new IllegalArgumentException("file must be a string, a file or a path"); 090 } 091 092 /** 093 * Polymorphic {@link java.net.URL} creation. 094 * 095 * @param ref the url descriptor as a {@link String}, {@link URL}, {@link URI}, {@link File} or {@link Path}. 096 * @return the corresponding {@link java.net.URL} object. 097 */ 098 public static URL toURL(Object ref) throws MalformedURLException { 099 if (ref == null) { 100 return null; 101 } else if (ref instanceof String) { 102 return new URL((String) ref); 103 } else if (ref instanceof URL) { 104 return (URL) ref; 105 } else if (ref instanceof URI) { 106 return ((URI) ref).toURL(); 107 } else if (ref instanceof Path) { 108 return ((Path) ref).toUri().toURL(); 109 } else if (ref instanceof File) { 110 return ((File) ref).toURI().toURL(); 111 } 112 throw new IllegalArgumentException(String.format("Can't convert a %s into a URL", ref.getClass().getName())); 113 } 114 115 116 /** 117 * Writes some text to a file. 118 * 119 * The file and parents directories are created if they does not exist. The file is overwritten if it already exists. If the file is {@code "-"}, the content is written to standard output. 120 * 121 * @param text the text to write. 122 * @param file the file to write to as an instance of either {@link String}, {@link File} or {@link Path}. 123 */ 124 public static void textToFile(Object text, Object file) throws Throwable { 125 textToFile(text, file, null); 126 } 127 128 /** 129 * Writes some text to a file using the given {@link Charset}. 130 * 131 * The file and parents directories are created if they does not exist. The file is overwritten if it already exists. If the file is {@code "-"}, the content is written to standard output. 132 * 133 * @param text the text to write. 134 * @param file the file to write to as an instance of either {@link String}, {@link File} or {@link Path}. 135 * @param charset the charset to encode the text in. 136 */ 137 public static void textToFile(Object text, Object file, Object charset) throws Throwable { 138 require(text instanceof String, "text must be a string"); 139 Charset encoding = toCharset(charset); 140 String str = (String) text; 141 if ("-".equals(file.toString())) { 142 System.out.write(str.getBytes(encoding)); 143 } else { 144 Path path = toPath(file); 145 if (path.getParent() != null) { 146 Files.createDirectories(path.getParent()); 147 } 148 Files.write( 149 path, 150 str.getBytes(encoding), 151 StandardOpenOption.WRITE, 152 StandardOpenOption.CREATE, 153 StandardOpenOption.TRUNCATE_EXISTING); 154 } 155 } 156 157 /** 158 * Check if a file exists. 159 * 160 * @param file the file to read from as an instance of either {@link String}, {@link File} or {@link Path}. 161 * @return true if the file exists, false if it doesn't 162 */ 163 public static boolean fileExists(Object file) { 164 return Files.exists(toPath(file)); 165 } 166 167 /** 168 * Reads the next line of characters from the console. 169 * 170 * @return a String. 171 */ 172 public static String readln() throws IOException { 173 return System.console().readLine(); 174 } 175 176 /** 177 * Reads the next line of characters from the console. 178 * 179 * @param message displays a prompt message. 180 * @return a String. 181 */ 182 public static String readln(String message) throws IOException { 183 System.out.print(message); 184 return readln(); 185 } 186 187 /** 188 * Reads a password from the console with echoing disabled. 189 * 190 * @return a String. 191 */ 192 public static String readPassword() throws IOException { 193 return String.valueOf(System.console().readPassword()); 194 } 195 196 /** 197 * Reads a password from the console with echoing disabled. 198 * 199 * @param message displays a prompt message. 200 * @return a String. 201 */ 202 public static String readPassword(String message) throws IOException { 203 System.out.print(message); 204 return readPassword(); 205 } 206 207 /** 208 * Reads a password from the console with echoing disabled, returning an {@code char[]} array. 209 * 210 * @return a character array. 211 */ 212 public static char[] secureReadPassword() throws IOException { 213 return System.console().readPassword(); 214 } 215 216 /** 217 * Reads a password from the console with echoing disabled, returning an {@code char[]} array. 218 * 219 * @param message displays a prompt message. 220 * @return a character array. 221 */ 222 public static char[] secureReadPassword(String message) throws IOException { 223 System.out.print(message); 224 return secureReadPassword(); 225 } 226 227 /** 228 * Create an {@code PrintStream} from the specified value. 229 * <p> 230 * Same as {@code printStreamFrom(output, defaultCharset())} 231 * 232 * @param output the file to use; "-" means standard output 233 * @return a buffered {@code PrintStream} or {@code java.lang.System.out} 234 * @see #defaultCharset() 235 * @see #printStreamFrom(Object, Object) 236 */ 237 public static PrintStream printStreamFrom(Object output) throws IOException { 238 return printStreamFrom(output, defaultCharset()); 239 } 240 241 /** 242 * Create an {@code PrintStream} from the specified value. 243 * <p> 244 * If the given string is "-", {@code java.lang.System.out} is used. Otherwise, a {@code java.nio.file.Path} is 245 * created with {@link #toPath(Object)}. 246 * The returned {@code PrintStream} is buffered and uses the given charset. Parent directory is created. If the file 247 * exists, it is overwritten. 248 * 249 * @param output the file to use; "-" means standard output 250 * @param charset the charset to use, as a {@code java.lang.String} or a {@code java.nio.charset.Charset} 251 * @return a buffered {@code PrintStream} or {@code java.lang.System.out} 252 * @see #toPath(Object) 253 * @see #toCharset(Object) 254 */ 255 public static PrintStream printStreamFrom(Object output, Object charset) throws IOException { 256 if ("-".equals(output)) { 257 return System.out; 258 } 259 if (output instanceof PrintStream) { 260 return (PrintStream) output; 261 } 262 OutputStream out; 263 if (output instanceof OutputStream) { 264 out = (OutputStream) output; 265 } else { 266 Path outputPath = toPath(output); 267 if (outputPath.getParent() != null) { 268 Files.createDirectories(outputPath.getParent()); 269 } 270 out = Files.newOutputStream(outputPath); 271 } 272 return new PrintStream( 273 new BufferedOutputStream(out), 274 true, 275 toCharset(charset).name()); 276 } 277 278 279}