4 * Copyright(c) 2009 olyutorskii
\r
5 * $Id: FileUtils.java 952 2009-12-06 14:29:10Z olyutorskii $
\r
8 package jp.sourceforge.jindolf;
\r
10 import java.io.File;
\r
11 import java.lang.reflect.InvocationTargetException;
\r
12 import java.lang.reflect.Method;
\r
13 import java.lang.reflect.Modifier;
\r
14 import java.net.URI;
\r
15 import java.net.URISyntaxException;
\r
16 import java.net.URL;
\r
17 import java.security.CodeSource;
\r
18 import java.security.ProtectionDomain;
\r
19 import java.util.Locale;
\r
23 * JRE1.6 API へのリフレクションアクセスを含む。
\r
25 public final class FileUtils{
\r
27 private static final String SCHEME_FILE = "file";
\r
29 /** JRE1.6のjava.io.File#setReadableに相当。 */
\r
30 private static final Method METHOD_SETREADABLE;
\r
31 /** JRE1.6のjava.io.File#setWritableに相当。 */
\r
32 private static final Method METHOD_SETWRITABLE;
\r
33 /** Locale.ROOT代替品。 */
\r
34 private static final Locale ROOT = new Locale("", "", "");
\r
41 method = File.class.getMethod(
\r
42 "setReadable", Boolean.TYPE, Boolean.TYPE);
\r
43 modifiers = method.getModifiers();
\r
44 if( ! Modifier.isPublic(modifiers) ){
\r
47 }catch(NoSuchMethodException e){
\r
49 }catch(SecurityException e){
\r
52 METHOD_SETREADABLE = method;
\r
55 method = File.class.getMethod(
\r
56 "setWritable", Boolean.TYPE, Boolean.TYPE);
\r
57 modifiers = method.getModifiers();
\r
58 if( ! Modifier.isPublic(modifiers) ){
\r
61 }catch(NoSuchMethodException e){
\r
63 }catch(SecurityException e){
\r
66 METHOD_SETWRITABLE = method;
\r
68 assert ! ( isMacOSXFs() && isWindowsOSFs() );
\r
72 * なるべく自分にだけ許可を与え自分以外には許可を与えないように
\r
74 * @param method setReadableかsetWritableのいずれかのメソッド。
\r
76 * @param file 操作対象のファイル。
\r
78 * @throws SecurityException セキュリティ上の許可が無い場合
\r
80 private static boolean invokeOwnerOnly(Method method, File file)
\r
81 throws SecurityException{
\r
82 if(method == null) return false;
\r
83 if(file == null) throw new NullPointerException();
\r
88 result1 = method.invoke(file, false, false);
\r
89 result2 = method.invoke(file, true, true);
\r
90 }catch(IllegalAccessException e){
\r
93 }catch(IllegalArgumentException e){
\r
96 }catch(ExceptionInInitializerError e){
\r
99 }catch(InvocationTargetException e){
\r
100 Throwable cause = e.getCause();
\r
101 if(cause instanceof SecurityException){
\r
102 throw (SecurityException) cause;
\r
103 }else if(cause instanceof RuntimeException){
\r
104 throw (RuntimeException) cause;
\r
105 }else if(cause instanceof Error){
\r
106 throw (Error) cause;
\r
113 assert result1 instanceof Boolean;
\r
114 assert result2 instanceof Boolean;
\r
115 Boolean bresult1 = (Boolean) result1;
\r
116 Boolean bresult2 = (Boolean) result2;
\r
118 return bresult1 && bresult2;
\r
122 * なるべく自分にだけ読み書き許可を与え
\r
123 * 自分以外には読み書き許可を与えないように
\r
125 * JRE1.6環境でなければなにもしない。
\r
126 * @param file 操作対象ファイル
\r
127 * @return 成功すればtrue
\r
128 * @throws SecurityException セキュリティ上の許可が無い場合
\r
130 public static boolean setOwnerOnlyAccess(File file)
\r
131 throws SecurityException{
\r
132 boolean readresult = invokeOwnerOnly(METHOD_SETREADABLE, file);
\r
133 boolean writeresult = invokeOwnerOnly(METHOD_SETWRITABLE, file);
\r
134 return readresult & writeresult;
\r
138 * 任意の絶対パスの祖先の内、存在するもっとも近い祖先を返す。
\r
139 * @param file 任意の絶対パス
\r
140 * @return 存在するもっとも近い祖先。一つも存在しなければnull。
\r
141 * @throws IllegalArgumentException 引数が絶対パスでない
\r
143 public static File findExistsAncestor(File file)
\r
144 throws IllegalArgumentException{
\r
145 if(file == null) return null;
\r
146 if( ! file.isAbsolute() ) throw new IllegalArgumentException();
\r
147 if(file.exists()) return file;
\r
148 File parent = file.getParentFile();
\r
149 return findExistsAncestor(parent);
\r
153 * 任意の絶対パスのルートファイルシステムもしくはドライブレターを返す。
\r
154 * @param file 任意の絶対パス
\r
155 * @return ルートファイルシステムもしくはドライブレター
\r
156 * @throws IllegalArgumentException 引数が絶対パスでない
\r
158 public static File findRootFile(File file)
\r
159 throws IllegalArgumentException{
\r
160 if( ! file.isAbsolute() ) throw new IllegalArgumentException();
\r
161 File parent = file.getParentFile();
\r
162 if(parent == null) return file;
\r
163 return findRootFile(parent);
\r
169 * @return 絶対パス。絶対化に失敗した場合は元の引数。
\r
171 public static File supplyFullPath(File file){
\r
172 if(file.isAbsolute()) return file;
\r
177 absFile = file.getAbsoluteFile();
\r
178 }catch(SecurityException e){
\r
186 * 任意のディレクトリがアクセス可能な状態にあるか判定する。
\r
187 * アクセス可能の条件を満たすためには、与えられたパスが
\r
193 * @param path 任意のディレクトリ
\r
194 * @return アクセス可能ならtrue
\r
196 public static boolean isAccessibleDirectory(File path){
\r
197 if(path == null) return false;
\r
199 if( ! path.exists() ) return false;
\r
200 if( ! path.isDirectory() ) return false;
\r
201 if( ! path.canRead() ) return false;
\r
202 if( ! path.canWrite() ) return false;
\r
208 * クラスがローカルファイルからロードされたのであれば
\r
210 * @param klass 任意のクラス
\r
211 * @return ロード元ファイル。見つからなければnull。
\r
213 public static File getClassSourceFile(Class<?> klass){
\r
214 ProtectionDomain domain;
\r
216 domain = klass.getProtectionDomain();
\r
217 }catch(SecurityException e){
\r
221 CodeSource src = domain.getCodeSource();
\r
223 URL location = src.getLocation();
\r
224 String scheme = location.getProtocol();
\r
225 if( ! scheme.equals(SCHEME_FILE) ) return null;
\r
229 uri = location.toURI();
\r
230 }catch(URISyntaxException e){
\r
235 File file = new File(uri);
\r
241 * すでに存在するJARファイルか判定する。
\r
242 * @param file 任意のファイル
\r
243 * @return すでに存在するJARファイルであればtrue
\r
245 public static boolean isExistsJarFile(File file){
\r
246 if(file == null) return false;
\r
247 if( ! file.exists() ) return false;
\r
248 if( ! file.isFile() ) return false;
\r
250 String name = file.getName();
\r
251 if( ! name.matches("^.+\\.[jJ][aA][rR]$") ) return false;
\r
253 // TODO ファイル先頭マジックナンバーのテストも必要?
\r
259 * クラスがローカルJARファイルからロードされたのであれば
\r
261 * @param klass 任意のクラス
\r
262 * @return ロード元JARファイルの格納ディレクトリ。
\r
263 * JARが見つからない、もしくはロード元がJARファイルでなければnull。
\r
265 public static File getJarDirectory(Class<?> klass){
\r
266 File jarFile = getClassSourceFile(klass);
\r
267 if(jarFile == null) return null;
\r
269 if( ! isExistsJarFile(jarFile) ){
\r
273 return jarFile.getParentFile();
\r
278 * システムプロパティuser.homeで示されたホームディレクトリを返す。
\r
279 * @return ホームディレクトリ。何らかの事情でnullを返す場合もあり。
\r
281 public static File getHomeDirectory(){
\r
284 homeProp = System.getProperty("user.home");
\r
285 }catch(SecurityException e){
\r
289 File homeFile = new File(homeProp);
\r
296 * @return MacOSX環境ならtrue
\r
298 public static boolean isMacOSXFs(){
\r
299 if(File.separatorChar != '/') return false;
\r
303 osName = System.getProperty("os.name");
\r
304 }catch(SecurityException e){
\r
308 if(osName == null) return false;
\r
310 osName = osName.toLowerCase(ROOT);
\r
312 if(osName.startsWith("mac os x")){
\r
320 * Windows環境か否か判定する。
\r
321 * @return Windows環境ならtrue
\r
323 public static boolean isWindowsOSFs(){
\r
324 if(File.separatorChar != '\\') return false;
\r
328 osName = System.getProperty("os.name");
\r
329 }catch(SecurityException e){
\r
333 if(osName == null) return false;
\r
335 osName = osName.toLowerCase(ROOT);
\r
337 if(osName.startsWith("windows")){
\r
345 * アプリケーション設定ディレクトリを返す。
\r
346 * 存在の有無、アクセスの可否は関知しない。
\r
347 * @return アプリケーション設定ディレクトリ
\r
349 public static File getAppSetDir(){
\r
350 File home = getHomeDirectory();
\r
351 if(home == null) return null;
\r
353 File result = home;
\r
356 result = new File(result, "Library");
\r
357 result = new File(result, "Application Support");
\r
360 // TODO Win環境での%APPDATA%サポート
\r
366 * ファイル名を表示するためのJLabel用HTML文字列を生成する。
\r
367 * Windows日本語環境では、バックスラッシュ記号が円通貨記号に置換される。
\r
368 * @param file 対象ファイル
\r
369 * @return HTML文字列断片
\r
371 public static String getHtmledFileName(File file){
\r
372 String pathName = file.getPath();
\r
374 Locale locale = Locale.getDefault();
\r
375 String lang = locale.getLanguage();
\r
377 if( FileUtils.isWindowsOSFs() && lang.equals("ja") ){
\r
378 pathName = pathName.replace(File.separator, "¥");
\r
381 return "<code>" + pathName + "</code>";
\r
387 private FileUtils(){
\r
389 throw new AssertionError();
\r