/* * This source is part of the * _____ ___ ____ * __ / / _ \/ _ | / __/___ _______ _ * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / * /___/ * repository. * * Copyright (C) 2013 Benoit 'BoD' Lubek (BoD@JRAF.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jraf.android.util.file; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; import java.util.UUID; import android.content.Context; import android.util.Log; import org.jraf.android.util.Constants; import org.jraf.android.util.environment.EnvironmentUtil; import org.jraf.android.util.io.IoUtil; public class FileUtil { private static final String TAG = Constants.TAG + FileUtil.class.getSimpleName(); /** * Creates an empty temporary file using the given base name and suffix as part of the file name.<br/> * If {@code suffix} is {@code null}, {@code ".tmp"} is used. * * @param baseName The base name to use (must not be {@code null}). * @param suffix The suffix to use (can be {@code null}). * @return An empty temporary file. * @throws RuntimeException If the file could not be created. * @throws IllegalArgumentException If {@code baseName} is {@code null}. */ public static File newTemporaryFile(Context context, String baseName, String suffix) { if (baseName == null) throw new IllegalArgumentException("baseName must not be null"); File cacheDir = EnvironmentUtil.getExternalCacheDir(context); File res = new File(cacheDir, baseName + (suffix == null ? ".tmp" : suffix)); if (res.exists()) res.delete(); try { res.createNewFile(); // This may very well be useless res.deleteOnExit(); Log.d(TAG, "newTemporaryFile res=" + res); return res; } catch (IOException e) { Log.w(TAG, "Could not create a temporary file at " + res, e); throw new RuntimeException(e); } } /** * Creates an empty temporary file using a unique id as the base name and the given suffix as part of the file name.<br/> * If {@code suffix} is {@code null}, {@code ".tmp"} is used. * * @param suffix The suffix to use (can be {@code null}). * @return An empty temporary file. * @throws RuntimeException If the file could not be created. */ public static File newTemporaryFile(Context context, String suffix) { return newTemporaryFile(context, UUID.randomUUID().toString(), suffix); } /** * Get a string suitable to be used as a file name.<br/> * This will replace characters that cannot be used in a file name (for instance '/' or '='), with the given replacement character, or with nothing if * {@code null} is given. * * @param originalName The original name. * @param replacementChar The replacement character to use or {@code null} to just strip the bad characters. * @return A new string equal to {@code originalName} with the bad characters stripped or replaced. */ public static String getValidFileName(String originalName, Character replacementChar) { int len = originalName.length(); StringBuilder res = new StringBuilder(len); for (int i = 0; i < len; i++) { char c = originalName.charAt(i); if (c == ' ' || c == '-' || c == '_' || c == '.' || c == ',' || c == '(' || c == ')') { res.append(c); } else if (c == '\u00E9' || c == '\u00E0' || c == '\u00E9' || c == '\u00E7' || c == '\u00F4' || c == '\u00EE') { res.append(c); } else if ('0' <= c && c <= '9') { res.append(c); } else if ('a' <= c && c <= 'z') { res.append(c); } else if ('A' <= c && c <= 'Z') { res.append(c); } else if (replacementChar != null) { res.append(replacementChar.charValue()); } } return res.toString(); } /** * Equivalent of calling {@code getValidFilename(originalName, null)}. */ public static String getValidFileName(String originalName) { return getValidFileName(originalName, null); } /** * A criteria to delete files if they are older than a given max age. */ public class ExpiredFileFilter implements FileFilter { private long mMaxAgeMs; public ExpiredFileFilter(long maxAgeMs) { mMaxAgeMs = maxAgeMs; } @Override public boolean accept(File file) { return file.lastModified() < System.currentTimeMillis() - mMaxAgeMs; } } /** * Recursively delete a file or directory.<br/> * An optional {@link FileFilter} can be given to choose to delete only certain files ({@link FileFilter#accept(File)} returning {@code true} means the file * should be deleted).<br/> * If a filter is given, it will only be used on files, not directories and because of that, directories will not be deleted. If {@code null} is given, then * files <strong>and</strong> directories are deleted. * * @param fileOrDirectory The file or directory to delete. * @param criteria The criteria to use to choose to delete only certain files, or {@code null} to delete all of them. */ public static void deleteRecursively(File fileOrDirectory, FileFilter criteria) { if (fileOrDirectory.isDirectory()) { for (File child : fileOrDirectory.listFiles()) { deleteRecursively(child, criteria); } if (criteria == null) { boolean ok = fileOrDirectory.delete(); Log.d(TAG, "deleted directory " + fileOrDirectory + (ok ? " ok" : " NOT ok")); } } else { if (criteria == null || criteria.accept(fileOrDirectory)) { boolean ok = fileOrDirectory.delete(); Log.d(TAG, "deleted file " + fileOrDirectory + (ok ? " ok" : " NOT ok")); } } } /** * Recursively delete a file or directory. * * @param fileOrDirectory The file or directory to delete. */ public static void deleteRecursively(File fileOrDirectory) { deleteRecursively(fileOrDirectory, null); } /** * Copy a file. * * @param from The path of the source file to copy. * @param to The destination path (must include the file name). * @throws IOException If an error occurs while reading or writing. */ public static void copy(String from, String to) throws IOException { copy(new File(from), new File(to)); } /** * Copy a file. * * @param from The source file to copy. * @param to The destination file (must be a file, not a directory). * @throws IOException If an error occurs while reading or writing. */ public static void copy(File from, File to) throws IOException { FileChannel in = new FileInputStream(from).getChannel(); FileChannel out = new FileOutputStream(to).getChannel(); in.transferTo(0, in.size(), out); IoUtil.closeSilently(in, out); } }