/* * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Codename One designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Codename One through http://www.codenameone.com/ if you * need additional information or have any questions. */ package com.codename1.io; import com.codename1.ui.Display; import com.codename1.util.StringUtil; import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; /** * This class provides a similar API to {@code java.io.File} making it almost into a "drop in" replacement. * It is placed in a different package because it is incompatible to {@code java.io.File} by definition. It is useful * in getting some simple code to work without too many changes * * @author Shai Almog */ public class File { public static final char separatorChar = '/'; public static final java.lang.String separator = "/"; private String path; /** * Creates a new File object from the given URI * @param uri */ public File(URI uri) { this("file:/"+uri.getPath()); } /** * Creates a new file object with given path. Paths that do not begin with the "file:" prefix * will automatically be prefixed with the app home path. * @param path The path of the file. Relative or absolute. */ public File(java.lang.String path) { if(!path.startsWith("file:")) { this.path = FileSystemStorage.getInstance().getAppHomePath() + path; } else { this.path = path; } } /** * Creates a new file object in a given directory. * @param dir The parent directory path. * @param file The file name */ public File(java.lang.String dir, java.lang.String file) { if(!dir.startsWith("file:")) { dir = FileSystemStorage.getInstance().getAppHomePath() + dir; } if(!dir.endsWith("/")) { this.path = dir + "/" + file; } else { this.path = dir + file; } } /** * Creates a new file in the given parent directory, and subpath. * @param parent The parent directory. * @param path The subpath, beginning with the parent directory. */ public File(File parent, java.lang.String path) { if(!parent.path.endsWith("/")) { this.path = parent.path + "/" + path; } else { this.path = parent.path + path; } } /** * Returns the file name. * @return The file name. */ public java.lang.String getName() { return path.substring(path.lastIndexOf('/') + 1); } /** * Gets the parent directory path. * @return The parent directory path. */ public java.lang.String getParent() { if ("file://".equals(path) || "file:///".equals(path) || path.length() == 0) { return null; } String out = path; if (out.endsWith("/")) { out = out.substring(0, out.length()-1); if (out.endsWith("/")) { return null; } } return out.substring(0, out.lastIndexOf('/')); } /** * Returns the file object for the parent directory. * @return */ public File getParentFile() { String parentPath = getParent(); if (parentPath == null) { return null; } return new File(parentPath); } /** * Gets the path to the file. * @return */ public java.lang.String getPath() { return path; } /** * Checks if the path is absolute. This always returns {@literal true} as all File objects * use absolute paths - even if they were created with relative paths. Relative paths are automatically * prefixed with the app home directory path. * @return */ public boolean isAbsolute() { return true; } /** * Gets the absolute path of the file as a string, * @return */ public java.lang.String getAbsolutePath() { return path; } /** * Gets the absolute file - which is always itself, since {@link #isAbsolute() } always returns true. * @return The same file object. */ public File getAbsoluteFile() { return this; } /** * Checks if the file described by this object exists on the file system. * @return */ public boolean exists() { return FileSystemStorage.getInstance().exists(path); } /** * Checks if this file is a directory. * @return */ public boolean isDirectory() { return FileSystemStorage.getInstance().isDirectory(path); } /** * Checks if this file object represents a regular file. * @return */ public boolean isFile() { return !isDirectory(); } /** * Checks if this is a hidden file. * @return */ public boolean isHidden() { return FileSystemStorage.getInstance().isHidden(path); } /** * Gets the last modified time as a unix timestamp in milliseconds. * @return */ public long lastModified() { return FileSystemStorage.getInstance().getLastModified(path); } /** * Gets the file size in bytes. * @return The file size in bytes. */ public long length() { return FileSystemStorage.getInstance().getLength(path); } /** * Creates this file as a new blank file in the file system. * @return True if it succeeds. * @throws java.io.IOException */ public boolean createNewFile() throws java.io.IOException { OutputStream os = FileSystemStorage.getInstance().openOutputStream(path); os.close(); return exists(); } /** * Deletes the file described by this object on the file system. * @return True if delete succeeds. */ public boolean delete() { FileSystemStorage.getInstance().delete(path); return !FileSystemStorage.getInstance().exists(path); } /** * Returns the list of child files of this directory. * @return */ public java.lang.String[] list() { try { String[] result = FileSystemStorage.getInstance().listFiles(path); for(int iter = 0 ; iter < result.length ; iter++) { int len = result[iter].length(); if(result[iter].endsWith("/")) { result[iter] = result[iter].substring(0, len - 1); } if (result[iter].indexOf("/") != -1) { result[iter] = result[iter].substring(result[iter].lastIndexOf("/")+1, len); } } return result; } catch(IOException err) { return null; } } /** * Returns list of child files of this directory * @param filter * @return */ public java.lang.String[] list(FilenameFilter filter) { String[] arr = list(); if(arr.length > 0) { ArrayList<String> result = new ArrayList<String>(); for(String s : arr) { if(filter.accept(this, s)) { result.add(s); } } String[] res = new String[result.size()]; result.toArray(res); return res; } return arr; } /** * Interface to filter filenames. */ public static interface FilenameFilter { /** * Checks if the given file should be included in results. * @param f The parent directory of the file to check. * @param name The file name. * @return True if the file should be included in results. */ public abstract boolean accept(File f, String name); } /** * Gets a list of child files of this directory. * @return */ public File[] listFiles() { String[] r = list(); File[] files = new File[r.length]; for(int iter = 0 ; iter < r.length ; iter++) { files[iter] = new File(this, r[iter]); } return files; } /** * Gets a list of child files of this directory, filtered using the provided filter. * @param ff The filter to use. * @return */ public File[] listFiles(FilenameFilter ff) { String[] r = list(ff); File[] files = new File[r.length]; for(int iter = 0 ; iter < r.length ; iter++) { files[iter] = new File(this, r[iter]); } return files; } /** * Interface for filtering files. */ public static interface FileFilter { /** * Returns {@literal true} if the file should be included in results. * @param f The file to check * @return True to include. False to not include in results. */ public abstract boolean accept(File f); } /** * Gets a list of child files of this directory, filtering them using the provided filter. * @param ff The filter to use to filter output. * @return */ public File[] listFiles(FileFilter ff) { File[] arr = listFiles(); if(arr.length > 0) { ArrayList<File> result = new ArrayList<File>(); for(File s : arr) { if(ff.accept(s)) { result.add(s); } } File[] res = new File[result.size()]; result.toArray(res); return res; } return arr; } /** * Attempts to make the directory described by this object. * @return True on success. */ public boolean mkdir() { FileSystemStorage.getInstance().mkdir(path); return exists() && isDirectory(); } /** * Attempts to make the directory (and all parent directories) of this object. * @return True on success. */ public boolean mkdirs() { File parentFile = getParentFile(); if (parentFile!= null && !parentFile.exists()) { boolean res = getParentFile().mkdirs(); if (!res) { return res; } } return mkdir(); } /** * Renames the file to the provided file object. * @param f The file object that we are renaming the file to. * @return True on success. */ public boolean renameTo(File f) { FileSystemStorage.getInstance().rename(path, f.getName()); return f.exists(); } /** * Checks if this file is executable. * @return */ public boolean canExecute() { return Display.getInstance().canExecute(path); } /** * List the file system roots. * @return */ public static File[] listRoots() { return new File[] { new File(FileSystemStorage.getInstance().getAppHomePath()) }; } /** * Returns the total space on the root file system. * @return */ public long getTotalSpace() { return FileSystemStorage.getInstance().getRootSizeBytes(FileSystemStorage.getInstance().getRoots()[0]); } /** * Gets the free space on the root file system. * @return */ public long getFreeSpace() { return FileSystemStorage.getInstance().getRootAvailableSpace(FileSystemStorage.getInstance().getRoots()[0]); } /** * Gets the usable space on this file system. * @return */ public long getUsableSpace() { return getFreeSpace(); } /** * Creates a temporary file. * @param prefix The file name prefix. * @param suffix The file name suffix * @return The resulting temporary file. * @throws java.io.IOException */ public static File createTempFile(java.lang.String prefix, java.lang.String suffix) throws java.io.IOException { String p = FileSystemStorage.getInstance().getAppHomePath() + "/temp/"; FileSystemStorage.getInstance().mkdir(p); return new File(p + prefix + System.currentTimeMillis() + suffix); } /** * Checks if the given object refers to the same file. * @param o * @return */ public boolean equals(java.lang.Object o) { return o instanceof File && ((File)o).path.equals(path); } public int hashCode() { return path.hashCode(); } public java.lang.String toString() { return path; } /** * Converts this file to a URL. * @return * @throws MalformedURLException */ public URL toURL() throws MalformedURLException { try { return new URL(toURI()); } catch (URISyntaxException ex) { throw new MalformedURLException("Invalid URL format: "+ex.getMessage()); } } /** * Converts this file to a URI. * @return * @throws URISyntaxException */ public URI toURI() throws URISyntaxException { String path = getAbsolutePath(); path = path.substring(6); path = StringUtil.replaceAll(path, "\\", "/"); while (path.startsWith("/")) { path = path.substring(1); } path = "/" + path; return new URI("file", null, path, null, null); } }