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