001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.internal; 014 015import static org.apache.juneau.common.internal.ArgUtils.*; 016import static org.apache.juneau.common.internal.StringUtils.*; 017import static org.apache.juneau.common.internal.ThrowableUtils.*; 018 019import java.io.*; 020import java.nio.file.*; 021 022import org.apache.juneau.*; 023import org.apache.juneau.common.internal.*; 024 025/** 026 * File utilities. 027 * 028 * <h5 class='section'>See Also:</h5><ul> 029 030 * </ul> 031 */ 032public class FileUtils { 033 034 /** 035 * Same as {@link File#mkdirs()} except throws a RuntimeExeption if directory could not be created. 036 * 037 * @param f The directory to create. Must not be <jk>null</jk>. 038 * @param clean If <jk>true</jk>, deletes the contents of the directory if it already exists. 039 * @return The same file. 040 * @throws RuntimeException if directory could not be created. 041 */ 042 public static File mkdirs(File f, boolean clean) { 043 assertArgNotNull("f", f); 044 if (f.exists()) { 045 if (clean) { 046 if (! delete(f)) 047 throw new BasicRuntimeException("Could not clean directory ''{0}''", f.getAbsolutePath()); 048 } else { 049 return f; 050 } 051 } 052 if (! f.mkdirs()) 053 throw new BasicRuntimeException("Could not create directory ''{0}''", f.getAbsolutePath()); 054 return f; 055 } 056 057 /** 058 * Same as {@link #mkdirs(String, boolean)} but uses String path. 059 * 060 * @param path The path of the directory to create. Must not be <jk>null</jk> 061 * @param clean If <jk>true</jk>, deletes the contents of the directory if it already exists. 062 * @return The directory. 063 */ 064 public static File mkdirs(String path, boolean clean) { 065 assertArgNotNull("path", path); 066 return mkdirs(new File(path), clean); 067 } 068 069 /** 070 * Recursively deletes a file or directory. 071 * 072 * @param f The file or directory to delete. 073 * @return <jk>true</jk> if file or directory was successfully deleted. 074 */ 075 public static boolean delete(File f) { 076 if (f == null) 077 return true; 078 if (f.isDirectory()) { 079 File[] cf = f.listFiles(); 080 if (cf != null) 081 for (File c : cf) 082 delete(c); 083 } 084 return f.delete(); 085 } 086 087 /** 088 * Creates a file if it doesn't already exist using {@link File#createNewFile()}. 089 * 090 * <p> 091 * Throws a {@link RuntimeException} if the file could not be created. 092 * 093 * @param f The file to create. 094 */ 095 public static void create(File f) { 096 if (f.exists()) 097 return; 098 try { 099 if (! f.createNewFile()) 100 throw new BasicRuntimeException("Could not create file ''{0}''", f.getAbsolutePath()); 101 } catch (IOException e) { 102 throw asRuntimeException(e); 103 } 104 } 105 106 /** 107 * Updates the modified timestamp on the specified file. 108 * 109 * <p> 110 * Method ensures that the timestamp changes even if it's been modified within the past millisecond. 111 * 112 * @param f The file to modify the modified timestamp on. 113 */ 114 public static void modifyTimestamp(File f) { 115 long lm = f.lastModified(); 116 long l = System.currentTimeMillis(); 117 if (lm == l) 118 l++; 119 if (! f.setLastModified(l)) 120 throw new BasicRuntimeException("Could not modify timestamp on file ''{0}''", f.getAbsolutePath()); 121 122 // Linux only gives 1s precision, so set the date 1s into the future. 123 if (lm == f.lastModified()) { 124 l += 1000; 125 if (! f.setLastModified(l)) 126 throw new BasicRuntimeException("Could not modify timestamp on file ''{0}''", f.getAbsolutePath()); 127 } 128 } 129 130 /** 131 * Create a temporary file with the specified name. 132 * 133 * <p> 134 * The name is broken into file name and suffix, and the parts are passed to 135 * {@link File#createTempFile(String, String)}. 136 * 137 * <p> 138 * {@link File#deleteOnExit()} is called on the resulting file before being returned by this method. 139 * 140 * @param name The file name 141 * @return A newly-created temporary file. 142 * @throws IOException Thrown by underlying stream. 143 */ 144 public static File createTempFile(String name) throws IOException { 145 String[] parts = name.split("\\."); 146 File f = File.createTempFile(parts[0], "." + parts[1]); 147 f.deleteOnExit(); 148 return f; 149 } 150 151 /** 152 * Create a temporary file with the specified name and specified contents. 153 * 154 * <p> 155 * The name is broken into file name and suffix, and the parts are passed to 156 * {@link File#createTempFile(String, String)}. 157 * 158 * <p> 159 * {@link File#deleteOnExit()} is called on the resulting file before being returned by this method. 160 * 161 * @param name The file name 162 * @param contents The file contents. 163 * @return A newly-created temporary file. 164 * @throws IOException Thrown by underlying stream. 165 */ 166 public static File createTempFile(String name, String contents) throws IOException { 167 File f = createTempFile(name); 168 try (Reader r = new StringReader(contents); Writer w = new FileWriter(f)) { 169 IOUtils.pipe(r, w); 170 w.flush(); 171 } 172 return f; 173 } 174 175 /** 176 * Strips the extension from a file name. 177 * 178 * @param name The file name. 179 * @return The file name without the extension, or <jk>null</jk> if name was <jk>null</jk>. 180 */ 181 public static String getBaseName(String name) { 182 if (name == null) 183 return null; 184 int i = name.lastIndexOf('.'); 185 if (i == -1) 186 return name; 187 return name.substring(0, i); 188 } 189 190 /** 191 * Returns the extension from a file name. 192 * 193 * @param name The file name. 194 * @return The the extension, or <jk>null</jk> if name was <jk>null</jk>. 195 */ 196 public static String getExtension(String name) { 197 if (name == null) 198 return null; 199 int i = name.lastIndexOf('.'); 200 if (i == -1) 201 return ""; 202 return name.substring(i+1); 203 } 204 205 /** 206 * Returns <jk>true</jk> if the specified file exists in the specified directory. 207 * 208 * @param dir The directory. 209 * @param fileName The file name. 210 * @return <jk>true</jk> if the specified file exists in the specified directory. 211 */ 212 public static boolean exists(File dir, String fileName) { 213 if (dir == null || fileName == null) 214 return false; 215 return Files.exists(dir.toPath().resolve(fileName)); 216 } 217 218 /** 219 * Returns <jk>true</jk> if the specified file name contains the specified extension. 220 * 221 * @param name The file name. 222 * @param ext The extension. 223 * @return <jk>true</jk> if the specified file name contains the specified extension. 224 */ 225 public static boolean hasExtension(String name, String ext) { 226 if (name == null || ext == null) 227 return false; 228 return ext.equals(getExtension(name)); 229 } 230 231 /** 232 * Given an arbitrary path, returns the file name portion of that path. 233 * 234 * @param path The path to check. 235 * @return The file name. 236 */ 237 public static String getFileName(String path) { 238 if (isEmpty(path)) 239 return null; 240 path = trimTrailingSlashes(path); 241 int i = path.lastIndexOf('/'); 242 return i == -1 ? path : path.substring(i+1); 243 } 244}