1. package org.jr.io;
  2. /**
  3. * Copyright: Copyright (c) 2002-2004
  4. * Company: JavaResearch(http://www.javaresearch.org)
  5. * 最后更新日期:2003年5月18日
  6. * @author Cherami
  7. */
  8. import java.io.*;
  9. import java.net.*;
  10. import java.util.*;
  11. import org.jr.swing.filter.*;
  12. /**
  13. * 此类中封装一些常用的文件操作。
  14. * 所有方法都是静态方法,不需要生成此类的实例,
  15. * 为避免生成此类的实例,构造方法被申明为private类型的。
  16. * @since 0.1
  17. */
  18. public class FileUtil {
  19. /**
  20. * 私有构造方法,防止类的实例化,因为工具类不需要实例化。
  21. */
  22. private FileUtil() {
  23. }
  24. /**
  25. * 修改文件的最后访问时间。
  26. * 如果文件不存在则创建该文件。
  27. * <b>目前这个方法的行为方式还不稳定,主要是方法有些信息输出,这些信息输出是否保留还在考虑中。</b>
  28. * @param file 需要修改最后访问时间的文件。
  29. * @since 0.1
  30. */
  31. public static void touch(File file) {
  32. long currentTime = System.currentTimeMillis();
  33. if (!file.exists()) {
  34. System.err.println("file not found:" + file.getName());
  35. System.err.println("Create a new file:" + file.getName());
  36. try {
  37. if (file.createNewFile()) {
  38. System.out.println("Succeeded!");
  39. }
  40. else {
  41. System.err.println("Create file failed!");
  42. }
  43. }
  44. catch (IOException e) {
  45. System.err.println("Create file failed!");
  46. e.printStackTrace();
  47. }
  48. }
  49. boolean result = file.setLastModified(currentTime);
  50. if (!result) {
  51. System.err.println("touch failed: " + file.getName());
  52. }
  53. }
  54. /**
  55. * 修改文件的最后访问时间。
  56. * 如果文件不存在则创建该文件。
  57. * <b>目前这个方法的行为方式还不稳定,主要是方法有些信息输出,这些信息输出是否保留还在考虑中。</b>
  58. * @param fileName 需要修改最后访问时间的文件的文件名。
  59. * @since 0.1
  60. */
  61. public static void touch(String fileName) {
  62. File file = new File(fileName);
  63. touch(file);
  64. }
  65. /**
  66. * 修改文件的最后访问时间。
  67. * 如果文件不存在则创建该文件。
  68. * <b>目前这个方法的行为方式还不稳定,主要是方法有些信息输出,这些信息输出是否保留还在考虑中。</b>
  69. * @param files 需要修改最后访问时间的文件数组。
  70. * @since 0.1
  71. */
  72. public static void touch(File[] files) {
  73. for (int i = 0; i < files.length; i++) {
  74. touch(files[i]);
  75. }
  76. }
  77. /**
  78. * 修改文件的最后访问时间。
  79. * 如果文件不存在则创建该文件。
  80. * <b>目前这个方法的行为方式还不稳定,主要是方法有些信息输出,这些信息输出是否保留还在考虑中。</b>
  81. * @param fileNames 需要修改最后访问时间的文件名数组。
  82. * @since 0.1
  83. */
  84. public static void touch(String[] fileNames) {
  85. File[] files = new File[fileNames.length];
  86. for (int i = 0; i < fileNames.length; i++) {
  87. files[i] = new File(fileNames[i]);
  88. }
  89. touch(files);
  90. }
  91. /**
  92. * 判断指定的文件是否存在。
  93. * @param fileName 要判断的文件的文件名
  94. * @return 存在时返回true,否则返回false。
  95. * @since 0.1
  96. */
  97. public static boolean isFileExist(String fileName) {
  98. return new File(fileName).isFile();
  99. }
  100. /**
  101. * 创建指定的目录。
  102. * 如果指定的目录的父目录不存在则创建其目录书上所有需要的父目录。
  103. * <b>注意:可能会在返回false的时候创建部分父目录。</b>
  104. * @param file 要创建的目录
  105. * @return 完全创建成功时返回true,否则返回false。
  106. * @since 0.1
  107. */
  108. public static boolean makeDirectory(File file) {
  109. File parent = file.getParentFile();
  110. if (parent != null) {
  111. return parent.mkdirs();
  112. }
  113. return false;
  114. }
  115. /**
  116. * 创建指定的目录。
  117. * 如果指定的目录的父目录不存在则创建其目录书上所有需要的父目录。
  118. * <b>注意:可能会在返回false的时候创建部分父目录。</b>
  119. * @param fileName 要创建的目录的目录名
  120. * @return 完全创建成功时返回true,否则返回false。
  121. * @since 0.1
  122. */
  123. public static boolean makeDirectory(String fileName) {
  124. File file = new File(fileName);
  125. return makeDirectory(file);
  126. }
  127. /**
  128. * 清空指定目录中的文件。
  129. * 这个方法将尽可能删除所有的文件,但是只要有一个文件没有被删除都会返回false。
  130. * 另外这个方法不会迭代删除,即不会删除子目录及其内容。
  131. * @param directory 要清空的目录
  132. * @return 目录下的所有文件都被成功删除时返回true,否则返回false.
  133. * @since 0.1
  134. */
  135. public static boolean emptyDirectory(File directory) {
  136. boolean result = false;
  137. File[] entries = directory.listFiles();
  138. for (int i = 0; i < entries.length; i++) {
  139. if (!entries[i].delete()) {
  140. result = false;
  141. }
  142. }
  143. return true;
  144. }
  145. /**
  146. * 清空指定目录中的文件。
  147. * 这个方法将尽可能删除所有的文件,但是只要有一个文件没有被删除都会返回false。
  148. * 另外这个方法不会迭代删除,即不会删除子目录及其内容。
  149. * @param directoryName 要清空的目录的目录名
  150. * @return 目录下的所有文件都被成功删除时返回true,否则返回false。
  151. * @since 0.1
  152. */
  153. public static boolean emptyDirectory(String directoryName) {
  154. File dir = new File(directoryName);
  155. return emptyDirectory(dir);
  156. }
  157. /**
  158. * 删除指定目录及其中的所有内容。
  159. * @param dirName 要删除的目录的目录名
  160. * @return 删除成功时返回true,否则返回false。
  161. * @since 0.1
  162. */
  163. public static boolean deleteDirectory(String dirName) {
  164. return deleteDirectory(new File(dirName));
  165. }
  166. /**
  167. * 删除指定目录及其中的所有内容。
  168. * @param dir 要删除的目录
  169. * @return 删除成功时返回true,否则返回false。
  170. * @since 0.1
  171. */
  172. public static boolean deleteDirectory(File dir) {
  173. if ( (dir == null) || !dir.isDirectory()) {
  174. throw new IllegalArgumentException("Argument " + dir +
  175. " is not a directory. ");
  176. }
  177. File[] entries = dir.listFiles();
  178. int sz = entries.length;
  179. for (int i = 0; i < sz; i++) {
  180. if (entries[i].isDirectory()) {
  181. if (!deleteDirectory(entries[i])) {
  182. return false;
  183. }
  184. }
  185. else {
  186. if (!entries[i].delete()) {
  187. return false;
  188. }
  189. }
  190. }
  191. if (!dir.delete()) {
  192. return false;
  193. }
  194. return true;
  195. }
  196. /**
  197. * 列出目录中的所有内容,包括其子目录中的内容。
  198. * @param fileName 要列出的目录的目录名
  199. * @return 目录内容的文件数组。
  200. * @since 0.1
  201. */
  202. public static File[] listAll(String fileName) {
  203. return listAll(new File(fileName));
  204. }
  205. /**
  206. * 列出目录中的所有内容,包括其子目录中的内容。
  207. * @param file 要列出的目录
  208. * @return 目录内容的文件数组。
  209. * @since 0.1
  210. */
  211. public static File[] listAll(File file) {
  212. ArrayList list = new ArrayList();
  213. File[] files;
  214. if (!file.exists() || file.isFile()) {
  215. return new File[0];
  216. }
  217. list(list, file, new AllFileFilter());
  218. list.remove(file);
  219. files = new File[list.size()];
  220. list.toArray(files);
  221. return files;
  222. }
  223. /**
  224. * 列出目录中的所有内容,包括其子目录中的内容。
  225. * @param file 要列出的目录
  226. * @param filter 过滤器
  227. * @return 目录内容的文件数组。
  228. * @since 0.1
  229. */
  230. public static File[] listAll(File file,
  231. javax.swing.filechooser.FileFilter filter) {
  232. ArrayList list = new ArrayList();
  233. File[] files;
  234. if (!file.exists() || file.isFile()) {
  235. return new File[0];
  236. }
  237. list(list, file, filter);
  238. files = new File[list.size()];
  239. list.toArray(files);
  240. return files;
  241. }
  242. /**
  243. * 将目录中的内容添加到列表。
  244. * @param list 文件列表
  245. * @param filter 过滤器
  246. * @param file 目录
  247. */
  248. private static void list(ArrayList list, File file,
  249. javax.swing.filechooser.FileFilter filter) {
  250. if (filter.accept(file)) {
  251. list.add(file);
  252. if (file.isFile()) {
  253. return;
  254. }
  255. }
  256. if (file.isDirectory()) {
  257. File files[] = file.listFiles();
  258. for (int i = 0; i < files.length; i++) {
  259. list(list, files[i], filter);
  260. }
  261. }
  262. }
  263. /**
  264. * 返回文件的URL地址。
  265. * @param file 文件
  266. * @return 文件对应的的URL地址
  267. * @throws MalformedURLException
  268. * @since 0.4
  269. * @deprecated 在实现的时候没有注意到File类本身带一个toURL方法将文件路径转换为URL。
  270. * 请使用File.toURL方法。
  271. */
  272. public static URL getURL(File file) throws MalformedURLException {
  273. String fileURL = "file:/" + file.getAbsolutePath();
  274. URL url = new URL(fileURL);
  275. return url;
  276. }
  277. /**
  278. * 从文件路径得到文件名。
  279. * @param filePath 文件的路径,可以是相对路径也可以是绝对路径
  280. * @return 对应的文件名
  281. * @since 0.4
  282. */
  283. public static String getFileName(String filePath) {
  284. File file = new File(filePath);
  285. return file.getName();
  286. }
  287. /**
  288. * 从文件名得到文件绝对路径。
  289. * @param fileName 文件名
  290. * @return 对应的文件路径
  291. * @since 0.4
  292. */
  293. public static String getFilePath(String fileName) {
  294. File file = new File(fileName);
  295. return file.getAbsolutePath();
  296. }
  297. /**
  298. * 将DOS/Windows格式的路径转换为UNIX/Linux格式的路径。
  299. * 其实就是将路径中的"\"全部换为"/",因为在某些情况下我们转换为这种方式比较方便,
  300. * 某中程度上说"/"比"\"更适合作为路径分隔符,而且DOS/Windows也将它当作路径分隔符。
  301. * @param filePath 转换前的路径
  302. * @return 转换后的路径
  303. * @since 0.4
  304. */
  305. public static String toUNIXpath(String filePath) {
  306. return filePath.replace('\\', '/');
  307. }
  308. /**
  309. * 从文件名得到UNIX风格的文件绝对路径。
  310. * @param fileName 文件名
  311. * @return 对应的UNIX风格的文件路径
  312. * @since 0.4
  313. * @see #toUNIXpath(String filePath) toUNIXpath
  314. */
  315. public static String getUNIXfilePath(String fileName) {
  316. File file = new File(fileName);
  317. return toUNIXpath(file.getAbsolutePath());
  318. }
  319. /**
  320. * 得到文件的类型。
  321. * 实际上就是得到文件名中最后一个“.”后面的部分。
  322. * @param fileName 文件名
  323. * @return 文件名中的类型部分
  324. * @since 0.5
  325. */
  326. public static String getTypePart(String fileName) {
  327. int point = fileName.lastIndexOf('.');
  328. int length = fileName.length();
  329. if (point == -1 || point == length - 1) {
  330. return "";
  331. }
  332. else {
  333. return fileName.substring(point + 1, length);
  334. }
  335. }
  336. /**
  337. * 得到文件的类型。
  338. * 实际上就是得到文件名中最后一个“.”后面的部分。
  339. * @param file 文件
  340. * @return 文件名中的类型部分
  341. * @since 0.5
  342. */
  343. public static String getFileType(File file) {
  344. return getTypePart(file.getName());
  345. }
  346. /**
  347. * 得到文件的名字部分。
  348. * 实际上就是路径中的最后一个路径分隔符后的部分。
  349. * @param fileName 文件名
  350. * @return 文件名中的名字部分
  351. * @since 0.5
  352. */
  353. public static String getNamePart(String fileName) {
  354. int point = getPathLastIndex(fileName);
  355. int length = fileName.length();
  356. if (point == -1) {
  357. return fileName;
  358. }
  359. else if (point == length - 1) {
  360. int secondPoint = getPathLastIndex(fileName, point - 1);
  361. if (secondPoint == -1) {
  362. if (length == 1) {
  363. return fileName;
  364. }
  365. else {
  366. return fileName.substring(0, point);
  367. }
  368. }
  369. else {
  370. return fileName.substring(secondPoint + 1, point);
  371. }
  372. }
  373. else {
  374. return fileName.substring(point + 1);
  375. }
  376. }
  377. /**
  378. * 得到文件名中的父路径部分。
  379. * 对两种路径分隔符都有效。
  380. * 不存在时返回""。
  381. * 如果文件名是以路径分隔符结尾的则不考虑该分隔符,例如"/path/"返回""。
  382. * @param fileName 文件名
  383. * @return 父路径,不存在或者已经是父目录时返回""
  384. * @since 0.5
  385. */
  386. public static String getPathPart(String fileName) {
  387. int point = getPathLastIndex(fileName);
  388. int length = fileName.length();
  389. if (point == -1) {
  390. return "";
  391. }
  392. else if (point == length - 1) {
  393. int secondPoint = getPathLastIndex(fileName, point - 1);
  394. if (secondPoint == -1) {
  395. return "";
  396. }
  397. else {
  398. return fileName.substring(0, secondPoint);
  399. }
  400. }
  401. else {
  402. return fileName.substring(0, point);
  403. }
  404. }
  405. /**
  406. * 得到路径分隔符在文件路径中首次出现的位置。
  407. * 对于DOS或者UNIX风格的分隔符都可以。
  408. * @param fileName 文件路径
  409. * @return 路径分隔符在路径中首次出现的位置,没有出现时返回-1。
  410. * @since 0.5
  411. */
  412. public static int getPathIndex(String fileName) {
  413. int point = fileName.indexOf('/');
  414. if (point == -1) {
  415. point = fileName.indexOf('\\');
  416. }
  417. return point;
  418. }
  419. /**
  420. * 得到路径分隔符在文件路径中指定位置后首次出现的位置。
  421. * 对于DOS或者UNIX风格的分隔符都可以。
  422. * @param fileName 文件路径
  423. * @param fromIndex 开始查找的位置
  424. * @return 路径分隔符在路径中指定位置后首次出现的位置,没有出现时返回-1。
  425. * @since 0.5
  426. */
  427. public static int getPathIndex(String fileName, int fromIndex) {
  428. int point = fileName.indexOf('/', fromIndex);
  429. if (point == -1) {
  430. point = fileName.indexOf('\\', fromIndex);
  431. }
  432. return point;
  433. }
  434. /**
  435. * 得到路径分隔符在文件路径中最后出现的位置。
  436. * 对于DOS或者UNIX风格的分隔符都可以。
  437. * @param fileName 文件路径
  438. * @return 路径分隔符在路径中最后出现的位置,没有出现时返回-1。
  439. * @since 0.5
  440. */
  441. public static int getPathLastIndex(String fileName) {
  442. int point = fileName.lastIndexOf('/');
  443. if (point == -1) {
  444. point = fileName.lastIndexOf('\\');
  445. }
  446. return point;
  447. }
  448. /**
  449. * 得到路径分隔符在文件路径中指定位置前最后出现的位置。
  450. * 对于DOS或者UNIX风格的分隔符都可以。
  451. * @param fileName 文件路径
  452. * @param fromIndex 开始查找的位置
  453. * @return 路径分隔符在路径中指定位置前最后出现的位置,没有出现时返回-1。
  454. * @since 0.5
  455. */
  456. public static int getPathLastIndex(String fileName, int fromIndex) {
  457. int point = fileName.lastIndexOf('/', fromIndex);
  458. if (point == -1) {
  459. point = fileName.lastIndexOf('\\', fromIndex);
  460. }
  461. return point;
  462. }
  463. /**
  464. * 将文件名中的类型部分去掉。
  465. * @param filename 文件名
  466. * @return 去掉类型部分的结果
  467. * @since 0.5
  468. */
  469. public static String trimType(String filename) {
  470. int index = filename.lastIndexOf(".");
  471. if (index != -1) {
  472. return filename.substring(0, index);
  473. }
  474. else {
  475. return filename;
  476. }
  477. }
  478. /**
  479. * 得到相对路径。
  480. * 文件名不是目录名的子节点时返回文件名。
  481. * @param pathName 目录名
  482. * @param fileName 文件名
  483. * @return 得到文件名相对于目录名的相对路径,目录下不存在该文件时返回文件名
  484. * @since 0.5
  485. */
  486. public static String getSubpath(String pathName, String fileName) {
  487. int index = fileName.indexOf(pathName);
  488. if (index != -1) {
  489. return fileName.substring(index + pathName.length() + 1);
  490. }
  491. else {
  492. return fileName;
  493. }
  494. }
  495. /**
  496. * 拷贝文件。
  497. * @param fromFileName 源文件名
  498. * @param toFileName 目标文件名
  499. * @return 成功生成文件时返回true,否则返回false
  500. * @since 0.6
  501. */
  502. public static boolean copy(String fromFileName, String toFileName) {
  503. return copy(fromFileName,toFileName,false);
  504. }
  505. /**
  506. * 拷贝文件。
  507. * @param fromFileName 源文件名
  508. * @param toFileName 目标文件名
  509. * @param override 目标文件存在时是否覆盖
  510. * @return 成功生成文件时返回true,否则返回false
  511. * @since 0.6
  512. */
  513. public static boolean copy(String fromFileName, String toFileName,
  514. boolean override) {
  515. File fromFile = new File(fromFileName);
  516. File toFile = new File(toFileName);
  517. if (!fromFile.exists() || !fromFile.isFile() || !fromFile.canRead()) {
  518. return false;
  519. }
  520. if (toFile.isDirectory()) {
  521. toFile = new File(toFile, fromFile.getName());
  522. }
  523. if (toFile.exists()) {
  524. if (!toFile.canWrite() || override == false) {
  525. return false;
  526. }
  527. }
  528. else {
  529. String parent = toFile.getParent();
  530. if (parent == null) {
  531. parent = System.getProperty("user.dir");
  532. }
  533. File dir = new File(parent);
  534. if (!dir.exists() || dir.isFile() || !dir.canWrite()) {
  535. return false;
  536. }
  537. }
  538. FileInputStream from = null;
  539. FileOutputStream to = null;
  540. try {
  541. from = new FileInputStream(fromFile);
  542. to = new FileOutputStream(toFile);
  543. byte[] buffer = new byte[4096];
  544. int bytes_read;
  545. while ( (bytes_read = from.read(buffer)) != -1) {
  546. to.write(buffer, 0, bytes_read);
  547. }
  548. return true;
  549. }
  550. catch (IOException e) {
  551. return false;
  552. }
  553. finally {
  554. if (from != null) {
  555. try {
  556. from.close();
  557. }
  558. catch (IOException e) {
  559. System.err.println("Exception when close source file");
  560. }
  561. }
  562. if (to != null) {
  563. try {
  564. to.close();
  565. }
  566. catch (IOException e) {
  567. System.err.println("Exception when close target file");
  568. }
  569. }
  570. }
  571. }
  572. }