OSDN Git Service

クラスメンバ定義順統一
[jindolf/Jindolf.git] / src / main / java / jp / sourceforge / jindolf / FileUtils.java
1 /*\r
2  * file utilities\r
3  *\r
4  * License : The MIT License\r
5  * Copyright(c) 2009 olyutorskii\r
6  */\r
7 \r
8 package jp.sourceforge.jindolf;\r
9 \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
20 \r
21 /**\r
22  * 諸々のファイル操作ユーティリティ。\r
23  * JRE1.6 API へのリフレクションアクセスを含む。\r
24  */\r
25 public final class FileUtils{\r
26 \r
27     private static final String SCHEME_FILE = "file";\r
28 \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
35 \r
36     static{\r
37         Method method;\r
38         int modifiers;\r
39 \r
40         try{\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
45                 method = null;\r
46             }\r
47         }catch(NoSuchMethodException e){\r
48             method = null;\r
49         }catch(SecurityException e){\r
50             method = null;\r
51         }\r
52         METHOD_SETREADABLE = method;\r
53 \r
54         try{\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
59                 method = null;\r
60             }\r
61         }catch(NoSuchMethodException e){\r
62             method = null;\r
63         }catch(SecurityException e){\r
64             method = null;\r
65         }\r
66         METHOD_SETWRITABLE = method;\r
67 \r
68         assert ! ( isMacOSXFs() && isWindowsOSFs() );\r
69     }\r
70 \r
71 \r
72     /**\r
73      * 隠しコンストラクタ。\r
74      */\r
75     private FileUtils(){\r
76         assert false;\r
77         throw new AssertionError();\r
78     }\r
79 \r
80 \r
81     /**\r
82      * なるべく自分にだけ許可を与え自分以外には許可を与えないように\r
83      * ファイル属性を操作する。\r
84      * @param method setReadableかsetWritableのいずれかのメソッド。\r
85      * nullならなにもしない。\r
86      * @param file 操作対象のファイル。\r
87      * @return 成功すればtrue\r
88      * @throws SecurityException セキュリティ上の許可が無い場合\r
89      */\r
90     private static boolean invokeOwnerOnly(Method method, File file)\r
91             throws SecurityException{\r
92         if(method == null) return false;\r
93         if(file == null) throw new NullPointerException();\r
94 \r
95         Object result1;\r
96         Object result2;\r
97         try{\r
98             result1 = method.invoke(file, false, false);\r
99             result2 = method.invoke(file, true,  true);\r
100         }catch(IllegalAccessException e){\r
101             assert false;\r
102             return false;\r
103         }catch(IllegalArgumentException e){\r
104             assert false;\r
105             return false;\r
106         }catch(ExceptionInInitializerError e){\r
107             assert false;\r
108             return false;\r
109         }catch(InvocationTargetException e){\r
110             Throwable cause = e.getCause();\r
111             if(cause instanceof SecurityException){\r
112                 throw (SecurityException) cause;\r
113             }else if(cause instanceof RuntimeException){\r
114                 throw (RuntimeException) cause;\r
115             }else if(cause instanceof Error){\r
116                 throw (Error) cause;\r
117             }else{\r
118                 assert false;\r
119             }\r
120             return false;\r
121         }\r
122 \r
123         assert result1 instanceof Boolean;\r
124         assert result2 instanceof Boolean;\r
125         Boolean bresult1 = (Boolean) result1;\r
126         Boolean bresult2 = (Boolean) result2;\r
127 \r
128         return bresult1 && bresult2;\r
129     }\r
130 \r
131     /**\r
132      * なるべく自分にだけ読み書き許可を与え\r
133      * 自分以外には読み書き許可を与えないように\r
134      * ファイル属性を操作する。\r
135      * JRE1.6環境でなければなにもしない。\r
136      * @param file 操作対象ファイル\r
137      * @return 成功すればtrue\r
138      * @throws SecurityException セキュリティ上の許可が無い場合\r
139      */\r
140     public static boolean setOwnerOnlyAccess(File file)\r
141             throws SecurityException{\r
142         boolean readresult  = invokeOwnerOnly(METHOD_SETREADABLE, file);\r
143         boolean writeresult = invokeOwnerOnly(METHOD_SETWRITABLE, file);\r
144         return readresult & writeresult;\r
145     }\r
146 \r
147     /**\r
148      * 任意の絶対パスの祖先の内、存在するもっとも近い祖先を返す。\r
149      * @param file 任意の絶対パス\r
150      * @return 存在するもっとも近い祖先。一つも存在しなければnull。\r
151      * @throws IllegalArgumentException 引数が絶対パスでない\r
152      */\r
153     public static File findExistsAncestor(File file)\r
154             throws IllegalArgumentException{\r
155         if(file == null) return null;\r
156         if( ! file.isAbsolute() ) throw new IllegalArgumentException();\r
157         if(file.exists()) return file;\r
158         File parent = file.getParentFile();\r
159         return findExistsAncestor(parent);\r
160     }\r
161 \r
162     /**\r
163      * 任意の絶対パスのルートファイルシステムもしくはドライブレターを返す。\r
164      * @param file 任意の絶対パス\r
165      * @return ルートファイルシステムもしくはドライブレター\r
166      * @throws IllegalArgumentException 引数が絶対パスでない\r
167      */\r
168     public static File findRootFile(File file)\r
169             throws IllegalArgumentException{\r
170         if( ! file.isAbsolute() ) throw new IllegalArgumentException();\r
171         File parent = file.getParentFile();\r
172         if(parent == null) return file;\r
173         return findRootFile(parent);\r
174     }\r
175 \r
176     /**\r
177      * 相対パスの絶対パス化を試みる。\r
178      * @param file 対象パス\r
179      * @return 絶対パス。絶対化に失敗した場合は元の引数。\r
180      */\r
181     public static File supplyFullPath(File file){\r
182         if(file.isAbsolute()) return file;\r
183 \r
184         File absFile;\r
185 \r
186         try{\r
187             absFile = file.getAbsoluteFile();\r
188         }catch(SecurityException e){\r
189             return file;\r
190         }\r
191 \r
192         return absFile;\r
193     }\r
194 \r
195     /**\r
196      * 任意のディレクトリがアクセス可能な状態にあるか判定する。\r
197      * アクセス可能の条件を満たすためには、与えられたパスが\r
198      * 存在し、\r
199      * かつディレクトリであり、\r
200      * かつ読み込み可能であり、\r
201      * かつ書き込み可能\r
202      * でなければならない。\r
203      * @param path 任意のディレクトリ\r
204      * @return アクセス可能ならtrue\r
205      */\r
206     public static boolean isAccessibleDirectory(File path){\r
207         if(path == null) return false;\r
208 \r
209         if( ! path.exists() )      return false;\r
210         if( ! path.isDirectory() ) return false;\r
211         if( ! path.canRead() )     return false;\r
212         if( ! path.canWrite() )    return false;\r
213 \r
214         return true;\r
215     }\r
216 \r
217     /**\r
218      * クラスがローカルファイルからロードされたのであれば\r
219      * そのファイルを返す。\r
220      * @param klass 任意のクラス\r
221      * @return ロード元ファイル。見つからなければnull。\r
222      */\r
223     public static File getClassSourceFile(Class<?> klass){\r
224         ProtectionDomain domain;\r
225         try{\r
226             domain = klass.getProtectionDomain();\r
227         }catch(SecurityException e){\r
228             return null;\r
229         }\r
230 \r
231         CodeSource src = domain.getCodeSource();\r
232 \r
233         URL location = src.getLocation();\r
234         String scheme = location.getProtocol();\r
235         if( ! scheme.equals(SCHEME_FILE) ) return null;\r
236 \r
237         URI uri;\r
238         try{\r
239             uri = location.toURI();\r
240         }catch(URISyntaxException e){\r
241             assert false;\r
242             return null;\r
243         }\r
244 \r
245         File file = new File(uri);\r
246 \r
247         return file;\r
248     }\r
249 \r
250     /**\r
251      * すでに存在するJARファイルか判定する。\r
252      * @param file 任意のファイル\r
253      * @return すでに存在するJARファイルであればtrue\r
254      */\r
255     public static boolean isExistsJarFile(File file){\r
256         if(file == null) return false;\r
257         if( ! file.exists() ) return false;\r
258         if( ! file.isFile() ) return false;\r
259 \r
260         String name = file.getName();\r
261         if( ! name.matches("^.+\\.[jJ][aA][rR]$") ) return false;\r
262 \r
263         // TODO ファイル先頭マジックナンバーのテストも必要?\r
264 \r
265         return true;\r
266     }\r
267 \r
268     /**\r
269      * クラスがローカルJARファイルからロードされたのであれば\r
270      * その格納ディレクトリを返す。\r
271      * @param klass 任意のクラス\r
272      * @return ロード元JARファイルの格納ディレクトリ。\r
273      * JARが見つからない、もしくはロード元がJARファイルでなければnull。\r
274      */\r
275     public static File getJarDirectory(Class<?> klass){\r
276         File jarFile = getClassSourceFile(klass);\r
277         if(jarFile == null) return null;\r
278 \r
279         if( ! isExistsJarFile(jarFile) ){\r
280             return null;\r
281         }\r
282 \r
283         return jarFile.getParentFile();\r
284     }\r
285 \r
286     /**\r
287      * ホームディレクトリを得る。\r
288      * システムプロパティuser.homeで示されたホームディレクトリを返す。\r
289      * @return ホームディレクトリ。何らかの事情でnullを返す場合もあり。\r
290      */\r
291     public static File getHomeDirectory(){\r
292         String homeProp;\r
293         try{\r
294             homeProp = System.getProperty("user.home");\r
295         }catch(SecurityException e){\r
296             return null;\r
297         }\r
298 \r
299         File homeFile = new File(homeProp);\r
300 \r
301         return homeFile;\r
302     }\r
303 \r
304     /**\r
305      * MacOSX環境か否か判定する。\r
306      * @return MacOSX環境ならtrue\r
307      */\r
308     public static boolean isMacOSXFs(){\r
309         if(File.separatorChar != '/') return false;\r
310 \r
311         String osName;\r
312         try{\r
313             osName = System.getProperty("os.name");\r
314         }catch(SecurityException e){\r
315             return false;\r
316         }\r
317 \r
318         if(osName == null) return false;\r
319 \r
320         osName = osName.toLowerCase(ROOT);\r
321 \r
322         if(osName.startsWith("mac os x")){\r
323             return true;\r
324         }\r
325 \r
326         return false;\r
327     }\r
328 \r
329     /**\r
330      * Windows環境か否か判定する。\r
331      * @return Windows環境ならtrue\r
332      */\r
333     public static boolean isWindowsOSFs(){\r
334         if(File.separatorChar != '\\') return false;\r
335 \r
336         String osName;\r
337         try{\r
338             osName = System.getProperty("os.name");\r
339         }catch(SecurityException e){\r
340             return false;\r
341         }\r
342 \r
343         if(osName == null) return false;\r
344 \r
345         osName = osName.toLowerCase(ROOT);\r
346 \r
347         if(osName.startsWith("windows")){\r
348             return true;\r
349         }\r
350 \r
351         return false;\r
352     }\r
353 \r
354     /**\r
355      * アプリケーション設定ディレクトリを返す。\r
356      * 存在の有無、アクセスの可否は関知しない。\r
357      * @return アプリケーション設定ディレクトリ\r
358      */\r
359     public static File getAppSetDir(){\r
360         File home = getHomeDirectory();\r
361         if(home == null) return null;\r
362 \r
363         File result = home;\r
364 \r
365         if(isMacOSXFs()){\r
366             result = new File(result, "Library");\r
367             result = new File(result, "Application Support");\r
368         }\r
369 \r
370         // TODO Win環境での%APPDATA%サポート\r
371 \r
372         return result;\r
373     }\r
374 \r
375     /**\r
376      * ファイル名を表示するためのJLabel用HTML文字列を生成する。\r
377      * Windows日本語環境では、バックスラッシュ記号が円通貨記号に置換される。\r
378      * @param file 対象ファイル\r
379      * @return HTML文字列断片\r
380      */\r
381     public static String getHtmledFileName(File file){\r
382         String pathName = file.getPath();\r
383 \r
384         Locale locale = Locale.getDefault();\r
385         String lang = locale.getLanguage();\r
386 \r
387         if( FileUtils.isWindowsOSFs() && lang.equals("ja") ){\r
388             pathName = pathName.replace(File.separator, "&yen;");\r
389         }\r
390 \r
391         return "<code>" + pathName + "</code>";\r
392     }\r
393 \r
394 }\r