📄 fileutil.java
字号:
/*
* Created on Oct 10, 2003
* Modified Apr 14, 2004 by Alon Rohter
* Copyright (C) 2003, 2004, 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package org.gudy.azureus2.core3.util;
import java.io.*;
import java.net.URI;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.platform.PlatformManager;
import org.gudy.azureus2.platform.PlatformManagerCapabilities;
import org.gudy.azureus2.platform.PlatformManagerFactory;
import org.gudy.azureus2.plugins.platform.PlatformManagerException;
import com.aelitis.azureus.core.AzureusCore;
import com.aelitis.azureus.core.AzureusCoreFactory;
import com.aelitis.azureus.core.AzureusCoreOperation;
import com.aelitis.azureus.core.AzureusCoreOperationTask;
/**
* File utility class.
*/
public class FileUtil {
private static final LogIDs LOGID = LogIDs.CORE;
public static final String DIR_SEP = System.getProperty("file.separator");
private static final int RESERVED_FILE_HANDLE_COUNT = 4;
private static List reserved_file_handles = new ArrayList();
private static AEMonitor class_mon = new AEMonitor( "FileUtil:class" );
public static boolean isAncestorOf(File parent, File child) {
parent = canonise(parent);
child = canonise(child);
if (parent.equals(child)) {return true;}
String parent_s = parent.getPath();
String child_s = child.getPath();
if (parent_s.charAt(parent_s.length()-1) != File.separatorChar) {
parent_s += File.separatorChar;
}
return child_s.startsWith(parent_s);
}
public static File canonise(File file) {
try {return file.getCanonicalFile();}
catch (IOException ioe) {return file;}
}
public static String getCanonicalFileName(String filename) {
// Sometimes Windows use filename in 8.3 form and cannot
// match .torrent extension. To solve this, canonical path
// is used to get back the long form
String canonicalFileName = filename;
try {
canonicalFileName = new File(filename).getCanonicalPath();
}
catch (IOException ignore) {}
return canonicalFileName;
}
public static File getUserFile(String filename) {
return new File(SystemProperties.getUserPath(), filename);
}
public static File getApplicationFile(String filename) {
String path = SystemProperties.getApplicationPath();
if(Constants.isOSX) {
path = path + "/" + SystemProperties.getApplicationName() + ".app/Contents/";
}
return new File(path, filename);
}
/**
* Deletes the given dir and all files/dirs underneath
*/
public static void recursiveDelete(File f) {
String defSaveDir = COConfigurationManager.getStringParameter("Default save path", "");
String moveToDir = COConfigurationManager.getStringParameter("Completed Files Directory", "");
try{
moveToDir = new File(moveToDir).getCanonicalPath();
}catch( Throwable e ){
}
try{
defSaveDir = new File(defSaveDir).getCanonicalPath();
}catch( Throwable e ){
}
try {
if (f.getCanonicalPath().equals(moveToDir)) {
System.out.println("FileUtil::recursiveDelete:: not allowed to delete the MoveTo dir !");
return;
}
if (f.getCanonicalPath().equals(defSaveDir)) {
System.out.println("FileUtil::recursiveDelete:: not allowed to delete the default data dir !");
return;
}
if (f.isDirectory()) {
File[] files = f.listFiles();
for (int i = 0; i < files.length; i++) {
recursiveDelete(files[i]);
}
f.delete();
}
else {
f.delete();
}
} catch (Exception ignore) {/*ignore*/}
}
public static long
getFileOrDirectorySize(
File file )
{
if ( file.isFile()){
return( file.length());
}else{
long res = 0;
File[] files = file.listFiles();
if ( files != null ){
for (int i=0;i<files.length;i++){
res += getFileOrDirectorySize( files[i] );
}
}
return( res );
}
}
protected static void
recursiveEmptyDirDelete(
File f,
Set ignore_set,
boolean log_warnings )
{
try {
String defSaveDir = COConfigurationManager.getStringParameter("Default save path", "");
String moveToDir = COConfigurationManager.getStringParameter("Completed Files Directory", "");
if ( defSaveDir.trim().length() > 0 ){
defSaveDir = new File(defSaveDir).getCanonicalPath();
}
if ( moveToDir.trim().length() > 0 ){
moveToDir = new File(moveToDir).getCanonicalPath();
}
if ( f.isDirectory()){
File[] files = f.listFiles();
if ( files == null ){
if (log_warnings ){
Debug.out("Empty folder delete: failed to list contents of directory " + f );
}
return;
}
for (int i = 0; i < files.length; i++) {
File x = files[i];
if ( x.isDirectory()){
recursiveEmptyDirDelete(files[i],ignore_set,log_warnings);
}else{
if ( ignore_set.contains( x.getName().toLowerCase())){
if ( !x.delete()){
if ( log_warnings ){
Debug.out("Empty folder delete: failed to delete file " + x );
}
}
}
}
}
if (f.getCanonicalPath().equals(moveToDir)) {
if ( log_warnings ){
Debug.out("Empty folder delete: not allowed to delete the MoveTo dir !");
}
return;
}
if (f.getCanonicalPath().equals(defSaveDir)) {
if ( log_warnings ){
Debug.out("Empty folder delete: not allowed to delete the default data dir !");
}
return;
}
if (f.listFiles().length == 0) {
if ( !f.delete()){
if ( log_warnings ){
Debug.out("Empty folder delete: failed to delete directory " + f );
}
}
}else{
if ( log_warnings ){
Debug.out("Empty folder delete: "+f.listFiles().length+" file(s)/folder(s) still in " + f + ". Not removing.");
}
}
}
} catch (Exception e) { Debug.out(e.toString()); }
}
public static String
convertOSSpecificChars(
String file_name_in )
{
// this rule originally from DiskManager
char[] chars = file_name_in.toCharArray();
for (int i=0;i<chars.length;i++){
if ( chars[i] == '"' ){
chars[i] = '\'';
}
}
if ( !Constants.isOSX ){
if ( Constants.isWindows ){
// this rule originally from DiskManager
// The definitive list of characters permitted for Windows is defined here:
// http://support.microsoft.com/kb/q120138/
String not_allowed = "\\/:?*<>";
for (int i=0;i<chars.length;i++){
if (not_allowed.indexOf(chars[i]) != -1) {
chars[i] = '_';
}
}
}
// '/' is valid in mac file names, replace with space
// so it seems are cr/lf
for (int i=0;i<chars.length;i++){
char c = chars[i];
if ( c == '/' || c == '\r' || c == '\n' ){
chars[i] = ' ';
}
}
}
String file_name_out = new String(chars);
try{
// mac file names can end in space - fix this up by getting
// the canonical form which removes this on Windows
// however, for soem reason getCanonicalFile can generate high CPU usage on some user's systems
// in java.io.Win32FileSystem.canonicalize
// so changing this to only be used on non-windows
if ( Constants.isWindows ){
while( file_name_out.endsWith( " " )){
file_name_out = file_name_out.substring(0,file_name_out.length()-1);
}
}else{
String str = new File(file_name_out).getCanonicalFile().toString();
int p = str.lastIndexOf( File.separator );
file_name_out = str.substring(p+1);
}
}catch( Throwable e ){
// ho hum, carry on, it'll fail later
//e.printStackTrace();
}
//System.out.println( "convertOSSpecificChars: " + file_name_in + " ->" + file_name_out );
return( file_name_out );
}
public static void
writeResilientConfigFile(
String file_name,
Map data )
{
File parent_dir = new File(SystemProperties.getUserPath());
boolean use_backups = COConfigurationManager.getBooleanParameter("Use Config File Backups" );
writeResilientFile( parent_dir, file_name, data, use_backups );
}
public static void
writeResilientFile(
File file,
Map data )
{
writeResilientFile( file.getParentFile(), file.getName(), data, false );
}
public static void
writeResilientFile(
File parent_dir,
String file_name,
Map data,
boolean use_backup )
{
if ( use_backup ){
File originator = new File( parent_dir, file_name );
if ( originator.exists()){
backupFile( originator, true );
}
}
writeResilientFile( parent_dir, file_name, data );
}
// synchronise it to prevent concurrent attempts to write the same file
private static void
writeResilientFile(
File parent_dir,
String file_name,
Map data )
{
try{
class_mon.enter();
try{
getReservedFileHandles();
File temp = new File( parent_dir, file_name + ".saving");
BufferedOutputStream baos = null;
try{
byte[] encoded_data = BEncoder.encode(data);
FileOutputStream tempOS = new FileOutputStream( temp, false );
baos = new BufferedOutputStream( tempOS, 8192 );
baos.write( encoded_data );
baos.flush();
tempOS.getFD().sync();
baos.close();
baos = null;
//only use newly saved file if it got this far, i.e. it saved successfully
if ( temp.length() > 1L ) {
File file = new File( parent_dir, file_name );
if ( file.exists() ){
file.delete();
}
temp.renameTo( file );
}
}catch (Exception e) {
Logger.log(new LogAlert(LogAlert.UNREPEATABLE, "Save of '"
+ file_name + "' fails", e));
}finally{
try {
if (baos != null){
baos.close();
}
}catch( Exception e){
Logger.log(new LogAlert(LogAlert.UNREPEATABLE, "Save of '"
+ file_name + "' fails", e));
}
}
}finally{
releaseReservedFileHandles();
}
}finally{
class_mon.exit();
}
}
public static Map
readResilientConfigFile(
String file_name )
{
File parent_dir = new File(SystemProperties.getUserPath());
boolean use_backups = COConfigurationManager.getBooleanParameter("Use Config File Backups" );
return( readResilientFile( parent_dir, file_name, use_backups ));
}
public static Map
readResilientConfigFile(
String file_name,
boolean use_backups )
{
File parent_dir = new File(SystemProperties.getUserPath());
if ( !use_backups ){
// override if a backup file exists. This is needed to cope with backups
// of the main config file itself as when boostrapping we can't get the
// "use backups"
if ( new File( parent_dir, file_name + ".bak").exists()){
use_backups = true;
}
}
return( readResilientFile( parent_dir, file_name, use_backups ));
}
public static Map
readResilientFile(
File file )
{
return( readResilientFile( file.getParentFile(),file.getName(),false));
}
public static Map
readResilientFile(
File parent_dir,
String file_name,
boolean use_backup )
{
File backup_file = new File( parent_dir, file_name + ".bak" );
if ( use_backup ){
use_backup = backup_file.exists();
}
// if we've got a backup, don't attempt recovery here as the .bak file may be
// fully OK
Map res = readResilientFileSupport( parent_dir, file_name, !use_backup );
if ( res == null && use_backup ){
// try backup without recovery
res = readResilientFileSupport( parent_dir, file_name + ".bak", false );
if ( res != null ){
Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_WARNING,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -