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.wicket.util.file; 018 019import java.io.BufferedInputStream; 020import java.io.BufferedOutputStream; 021import java.io.FileInputStream; 022import java.io.FileNotFoundException; 023import java.io.FileOutputStream; 024import java.io.FileWriter; 025import java.io.IOException; 026import java.io.InputStream; 027import java.io.ObjectInputStream; 028import java.io.ObjectOutputStream; 029import java.io.OutputStream; 030import java.io.Serializable; 031import java.net.URI; 032import java.time.Instant; 033import org.apache.wicket.util.io.Streams; 034import org.apache.wicket.util.watch.IModifiable; 035 036 037/** 038 * Simple extension of File that adds an implementation of IModifiable for files. This allows the 039 * ModificationWatcher class to watch files for modification. The IModifiable.lastModifiedTime() 040 * method also returns a Time object with a more convenient API than either Date or a value in 041 * milliseconds. 042 * 043 * @author Jonathan Locke 044 */ 045public class File extends java.io.File implements IModifiable 046{ 047 private static final long serialVersionUID = 1L; 048 049 /** 050 * Constructor. 051 * 052 * @param parent 053 * parent 054 * @param child 055 * child 056 */ 057 public File(final File parent, final String child) 058 { 059 super(parent, child); 060 } 061 062 /** 063 * Construct. 064 * 065 * @param parent 066 * parent 067 * @param child 068 * child 069 */ 070 public File(final java.io.File parent, final String child) 071 { 072 super(parent, child); 073 } 074 075 /** 076 * Construct. 077 * 078 * @param file 079 * File from java.io package 080 */ 081 public File(final java.io.File file) 082 { 083 super(file.getAbsolutePath()); 084 } 085 086 /** 087 * Constructor. 088 * 089 * @param pathname 090 * path name 091 */ 092 public File(final String pathname) 093 { 094 super(pathname); 095 } 096 097 /** 098 * Constructor. 099 * 100 * @param parent 101 * parent 102 * @param child 103 * child 104 */ 105 public File(final String parent, final String child) 106 { 107 super(parent, child); 108 } 109 110 /** 111 * Constructor. 112 * 113 * @param uri 114 * file uri 115 */ 116 public File(final URI uri) 117 { 118 super(uri); 119 } 120 121 /** 122 * @param name 123 * Name of child file 124 * @return Child file object 125 */ 126 public File file(final String name) 127 { 128 return new File(this, name); 129 } 130 131 /** 132 * @return File extension (whatever is after the last '.' in the file name) 133 */ 134 public String getExtension() 135 { 136 final int lastDot = getName().lastIndexOf('.'); 137 if (lastDot >= 0) 138 { 139 return getName().substring(lastDot + 1); 140 } 141 return null; 142 } 143 144 /** 145 * @return Parent folder 146 */ 147 public Folder getParentFolder() 148 { 149 return new Folder(getParent()); 150 } 151 152 /** 153 * @return Input stream that reads this file 154 * @throws FileNotFoundException 155 * Thrown if the file cannot be found 156 */ 157 public InputStream inputStream() throws FileNotFoundException 158 { 159 return new BufferedInputStream(new FileInputStream(this)); 160 } 161 162 /** 163 * Returns a Time object representing the most recent time this file was modified. 164 * 165 * @return This file's lastModified() value as a Time object or <code>null</code> if 166 * that information is not available 167 */ 168 @Override 169 public Instant lastModifiedTime() 170 { 171 final long time = lastModified(); 172 173 if(time == 0) 174 { 175 return null; 176 } 177 return Instant.ofEpochMilli(time); 178 } 179 180 /** 181 * Creates a buffered output stream that writes to this file. If the parent folder does not yet 182 * exist, creates all necessary folders in the path. 183 * 184 * @return Output stream that writes to this file 185 * @throws FileNotFoundException 186 * Thrown if the file cannot be found 187 */ 188 public OutputStream outputStream() throws FileNotFoundException 189 { 190 final Folder parent = getParentFolder(); 191 if (!parent.exists()) 192 { 193 if (!parent.mkdirs()) 194 { 195 throw new FileNotFoundException("Couldn't create path " + parent); 196 } 197 } 198 return new BufferedOutputStream(new FileOutputStream(this)); 199 } 200 201 /** 202 * @return String read from this file 203 * @throws IOException 204 */ 205 public String readString() throws IOException 206 { 207 final InputStream in = new FileInputStream(this); 208 try 209 { 210 return Streams.readString(in); 211 } 212 finally 213 { 214 in.close(); 215 } 216 } 217 218 /** 219 * @return Object read from serialization file 220 * @throws IOException 221 * @throws ClassNotFoundException 222 */ 223 public Object readObject() throws IOException, ClassNotFoundException 224 { 225 return new ObjectInputStream(inputStream()).readObject(); 226 } 227 228 /** 229 * @param object 230 * Object to write to this file 231 * @throws IOException 232 */ 233 public void writeObject(final Serializable object) throws IOException 234 { 235 new ObjectOutputStream(outputStream()).writeObject(object); 236 } 237 238 /** 239 * @return True if the file was removed 240 * @see java.io.File#delete() 241 */ 242 public boolean remove() 243 { 244 return Files.remove(this); 245 } 246 247 /** 248 * Force contents of file to physical storage 249 * 250 * @throws IOException 251 */ 252 public void sync() throws IOException 253 { 254 final FileInputStream in = new FileInputStream(this); 255 try 256 { 257 in.getFD().sync(); 258 } 259 finally 260 { 261 in.close(); 262 } 263 } 264 265 /** 266 * @return This file in double quotes (useful for passing to commands and tools that have issues 267 * with spaces in filenames) 268 */ 269 public String toQuotedString() 270 { 271 return "\"" + toString() + "\""; 272 } 273 274 /** 275 * Writes the given file to this one 276 * 277 * @param file 278 * The file to copy 279 * @return number of bytes written 280 * @throws IOException 281 */ 282 public int write(final File file) throws IOException 283 { 284 final InputStream in = new BufferedInputStream(new FileInputStream(file)); 285 try 286 { 287 return write(in); 288 } 289 finally 290 { 291 in.close(); 292 } 293 } 294 295 /** 296 * Writes the given input stream to this file 297 * 298 * @param input 299 * The input 300 * @return Number of bytes written 301 * @throws IOException 302 */ 303 public int write(final InputStream input) throws IOException 304 { 305 return Files.writeTo(this, input); 306 } 307 308 /** 309 * Write the given string to this file 310 * 311 * @param string 312 * The string to write 313 * @throws IOException 314 */ 315 public void write(final String string) throws IOException 316 { 317 final FileWriter out = new FileWriter(this); 318 try 319 { 320 out.write(string); 321 } 322 finally 323 { 324 out.close(); 325 } 326 } 327}