All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hsqldb.lib.FileUtil Maven / Gradle / Ivy

There is a newer version: 2.7.2
Show newest version
/* Copyright (c) 2001-2019, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


package org.hsqldb.lib;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Random;

import org.hsqldb.lib.java.JavaSystem;

/**
 * A collection of file management methods.

* Also provides the default FileAccess implementation * * @author Campbell Burnet (campbell-burnet@users dot sourceforge.net) * @author Fred Toussi (fredt@users dot sourceforge.net) * @author Ocke Janssen [email protected] * @version 2.4.1 * @since 1.7.2 */ public class FileUtil implements FileAccess { private static final FrameworkLogger LOG = FrameworkLogger.getLog(FileUtil.class); private static FileUtil fileUtil = new FileUtil(); private static FileAccessRes fileAccessRes = new FileAccessRes(); /** Creates a new instance of FileUtil */ FileUtil() {} public static FileUtil getFileUtil() { return fileUtil; } public static FileAccess getFileAccess(boolean isResource) { return isResource ? fileAccessRes : fileUtil; } public boolean isStreamElement(String elementName) { return new File(elementName).exists(); } public InputStream openInputStreamElement(String streamName) throws IOException { try { return new FileInputStream(new File(streamName)); } catch (Throwable e) { throw JavaSystem.toIOException(e); } } public void createParentDirs(String filename) { makeParentDirectories(new File(filename)); } public void removeElement(String filename) { if (isStreamElement(filename)) { delete(filename); } } public void renameElement(String oldName, String newName, boolean copyIfFailed) { if (renameWithOverwrite(oldName, newName)) { return; } if (!copyIfFailed) { return; } InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = openInputStreamElement(oldName); outputStream = openOutputStreamElement(newName, false); InOutUtil.copy(inputStream, outputStream); getFileSync(outputStream).sync(); } catch (IOException e) { String message = String.format( "Platform does not allow renaming files and failed to copy file contents from %s to %s", oldName, newName); LOG.error(message, e); return; } finally { try { if (inputStream != null) { inputStream.close(); } } catch (IOException e) { LOG.finest("Failed to dispose streams", e); } try { if (outputStream != null) { outputStream.close(); } } catch (IOException e) { LOG.finest("Failed to dispose streams", e); } } if (!delete(oldName)) { LOG.warning("Failed to delete renamed file " + oldName); } String message = String.format( "Platform does not allow renaming files. Copied file from %s to %s instead", oldName, newName); LOG.finer(message); } public OutputStream openOutputStreamElement(String streamName, boolean append) throws IOException { return new FileOutputStream(new File(streamName), append); } // end of FileAccess implementation // a new File("...")'s path is not canonicalized, only resolved // and normalized (e.g. redundant separator chars removed), // so as of JDK 1.4.2, this is a valid test for case insensitivity, // at least when it is assumed that we are dealing with a configuration // that only needs to consider the host platform's native file system, // even if, unlike for File.getCanonicalPath(), (new File("a")).exists() or // (new File("A")).exits(), regardless of the hosting system's // file path case sensitivity policy. public final boolean fsIsIgnoreCase = (new File("A")).equals(new File("a")); // posix separator normalized to File.separator? // CHECKME: is this true for every file system under Java? public final boolean fsNormalizesPosixSeparator = (new File("/")).getPath().endsWith(File.separator); // for JDK 1.1 createTempFile final Random random = new Random(System.currentTimeMillis()); /** * Delete the named file */ public boolean delete(String filename) { return new File(filename).delete(); } /** * Requests, in a JDK 1.1 compliant way, that the file or directory denoted * by the given abstract pathname be deleted when the virtual machine * terminates.

* * Deletion will be attempted only for JDK 1.2 and greater runtime * environments and only upon normal termination of the virtual * machine, as defined by the Java Language Specification.

* * Once deletion has been sucessfully requested, it is not possible to * cancel the request. This method should therefore be used with care.

* * @param f the abstract pathname of the file be deleted when the virtual * machine terminates */ public void deleteOnExit(File f) { f.deleteOnExit(); } /** * Return true or false based on whether the named file exists. */ public boolean exists(String filename) { return new File(filename).exists(); } public boolean exists(String fileName, boolean resource, Class cla) { if (fileName == null || fileName.length() == 0) { return false; } return resource ? null != cla.getResource(fileName) : FileUtil.getFileUtil().exists(fileName); } /** * Rename the file with oldname to newname. If a file with newname already * exists, it is deleted before the renaming operation proceeds. * * If a file with oldname does not exist, no file will exist after the * operation. */ private boolean renameWithOverwrite(String oldname, String newname) { File file = new File(oldname); delete(newname); boolean renamed = file.renameTo(new File(newname)); if (renamed) { return true; } delete(newname); if (exists(newname)) { new File(newname).renameTo(new File(newDiscardFileName(newname))); } return file.renameTo(new File(newname)); } /** * Retrieves the absolute path, given some path specification. * * @param path the path for which to retrieve the absolute path * @return the absolute path */ public String absolutePath(String path) { return new File(path).getAbsolutePath(); } /** * Retrieves the canonical file for the given file, in a * JDK 1.1 complaint way. * * @param f the File for which to retrieve the absolute File * @return the canonical File */ public File canonicalFile(File f) throws IOException { return new File(f.getCanonicalPath()); } /** * Retrieves the canonical file for the given path, in a * JDK 1.1 complaint way. * * @param path the path for which to retrieve the canonical File * @return the canonical File */ public File canonicalFile(String path) throws IOException { return new File(new File(path).getCanonicalPath()); } /** * Retrieves the canonical path for the given File, in a * JDK 1.1 complaint way. * * @param f the File for which to retrieve the canonical path * @return the canonical path */ public String canonicalPath(File f) throws IOException { return f.getCanonicalPath(); } /** * Retrieves the canonical path for the given path, in a * JDK 1.1 complaint way. * * @param path the path for which to retrieve the canonical path * @return the canonical path */ public String canonicalPath(String path) throws IOException { return new File(path).getCanonicalPath(); } /** * Retrieves the canonical path for the given path, or the absolute * path if attempting to retrieve the canonical path fails. * * @param path the path for which to retrieve the canonical or * absolute path * @return the canonical or absolute path */ public String canonicalOrAbsolutePath(String path) { try { return canonicalPath(path); } catch (Exception e) { return absolutePath(path); } } public void makeParentDirectories(File f) { String parent = f.getParent(); if (parent != null) { new File(parent).mkdirs(); } else { // workaround for jdk 1.1 bug (returns null when there is a parent) parent = f.getPath(); int index = parent.lastIndexOf('/'); if (index > 0) { parent = parent.substring(0, index); new File(parent).mkdirs(); } } } public static String makeDirectories(String path) { try { File file = new File(path); file.mkdirs(); return file.getCanonicalPath(); } catch (IOException e) { return null; } } public FileAccess.FileSync getFileSync(java.io.OutputStream os) throws IOException { return new FileSync((FileOutputStream) os); } public static class FileSync implements FileAccess.FileSync { FileDescriptor outDescriptor; FileSync(FileOutputStream os) throws IOException { outDescriptor = os.getFD(); } public void sync() throws IOException { outDescriptor.sync(); } } public static class FileAccessRes implements FileAccess { public boolean isStreamElement(String fileName) { URL url = null; try { url = getClass().getResource(fileName); if (url == null) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl != null) { url = cl.getResource(fileName); } } } catch (Throwable t) { // } return url != null; } public InputStream openInputStreamElement(final String fileName) throws IOException { InputStream fis = null; try { fis = getClass().getResourceAsStream(fileName); if (fis == null) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl != null) { fis = cl.getResourceAsStream(fileName); } } } catch (Throwable t) { // } finally { if (fis == null) { throw new FileNotFoundException(fileName); } } return fis; } public void createParentDirs(String filename) {} public void removeElement(String filename) {} public void renameElement(String oldName, String newName, boolean copyIfFailed) {} public OutputStream openOutputStreamElement(String streamName, boolean append) throws IOException { throw new IOException(); } public FileAccess.FileSync getFileSync(OutputStream os) throws IOException { throw new IOException(); } } /** * Utility method for user applications. Attempts to delete all the files * for the database as listed by the getDatabaseFileList() method. If any * of the current, main database files cannot be deleted, it is renamed * by adding a suffix containing a hexadecimal timestamp portion and * the ".old" extension. Also deletes the ".tmp" directory. * * @param dbNamePath full path or name of database (without a file extension) * @return currently always true */ public static boolean deleteOrRenameDatabaseFiles(String dbNamePath) { DatabaseFilenameFilter filter = new DatabaseFilenameFilter(dbNamePath); File[] fileList = filter.getExistingFileListInDirectory(); for (int i = 0; i < fileList.length; i++) { fileList[i].delete(); } File tempDir = new File(filter.canonicalFile.getPath() + ".tmp"); if (tempDir.isDirectory()) { File[] tempList = tempDir.listFiles(); if (tempList != null) { for (int i = 0; i < tempList.length; i++) { tempList[i].delete(); } } tempDir.delete(); } fileList = filter.getExistingMainFileSetList(); if (fileList.length == 0) { return true; } for (int i = 0; i < fileList.length; i++) { fileList[i].delete(); } fileList = filter.getExistingMainFileSetList(); for (int i = 0; i < fileList.length; i++) { fileList[i].renameTo( new File(newDiscardFileName(fileList[i].getPath()))); } return true; } /** * Utility method for user applications. Returns a list of files that * currently exist for a database. The list includes current database files * as well as ".new", and ".old" versions of the files, plus any app logs. * * @param dbNamePath full path or name of database (without a file extension) */ public static File[] getDatabaseFileList(String dbNamePath) { DatabaseFilenameFilter filter = new DatabaseFilenameFilter(dbNamePath); return filter.getExistingFileListInDirectory(); } /** * Returns a list of existing main files for a database. The list excludes * non-essential files. * * @param dbNamePath full path or name of database (without a file extension) */ public static File[] getDatabaseMainFileList(String dbNamePath) { DatabaseFilenameFilter filter = new DatabaseFilenameFilter(dbNamePath, false); return filter.getExistingFileListInDirectory(); } static int discardSuffixLength = 9; public static String newDiscardFileName(String filename) { String timestamp = StringUtil.toPaddedString( Integer.toHexString((int) System.currentTimeMillis()), discardSuffixLength - 1, '0', true); String discardName = filename + "." + timestamp + ".old"; return discardName; } static class DatabaseFilenameFilter implements FilenameFilter { String[] suffixes = new String[] { ".backup", ".properties", ".script", ".data", ".log", ".lobs" }; String[] extraSuffixes = new String[] { ".lck", ".sql.log", ".app.log" }; private String dbName; private File parent; private File canonicalFile; private boolean extraFiles; DatabaseFilenameFilter(String dbNamePath) { this(dbNamePath, true); } DatabaseFilenameFilter(String dbNamePath, boolean extras) { canonicalFile = new File(dbNamePath); try { canonicalFile = canonicalFile.getCanonicalFile(); } catch (Exception e) {} dbName = canonicalFile.getName(); parent = canonicalFile.getParentFile(); extraFiles = extras; } public File[] getCompleteMainFileSetList() { File[] fileList = new File[suffixes.length]; for (int i = 0; i < suffixes.length; i++) { fileList[i] = new File(canonicalFile.getPath() + suffixes[i]); } return fileList; } public File[] getExistingMainFileSetList() { File[] fileList = getCompleteMainFileSetList(); HsqlArrayList list = new HsqlArrayList(); for (int i = 0; i < fileList.length; i++) { if (fileList[i].exists()) { list.add(fileList[i]); } } fileList = new File[list.size()]; list.toArray(fileList); return fileList; } public File[] getExistingFileListInDirectory() { File[] list = parent.listFiles(this); return list == null ? new File[]{} : list; } /** * Accepts all main files as well as ".new" and ".old" versions. */ public boolean accept(File dir, String name) { if (parent.equals(dir) && name.indexOf(dbName) == 0) { String suffix = name.substring(dbName.length()); if (extraFiles) { for (int i = 0; i < extraSuffixes.length; i++) { if (suffix.equals(extraSuffixes[i])) { return true; } } } for (int i = 0; i < suffixes.length; i++) { if (suffix.equals(suffixes[i])) { return true; } if (!extraFiles) { continue; } if (suffix.startsWith(suffixes[i])) { if (name.endsWith(".new")) { if (suffix.length() == suffixes[i].length() + 4) { return true; } } else if (name.endsWith(".old")) { if (suffix.length() == suffixes[i].length() + discardSuffixLength + 4) { return true; } } } } } return false; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy