You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FileUtil.java 47KB

21 years ago
21 years ago
21 years ago
13 years ago
21 years ago
13 years ago
21 years ago
14 years ago
15 years ago
15 years ago
14 years ago
15 years ago
14 years ago
15 years ago
15 years ago
15 years ago
14 years ago
15 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
15 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
13 years ago
14 years ago
21 years ago
14 years ago
13 years ago
21 years ago
15 years ago
21 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
21 years ago
15 years ago
21 years ago
21 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
15 years ago
21 years ago
14 years ago
21 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
13 years ago
13 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570
  1. /* *******************************************************************
  2. * Copyright (c) 1999-2001 Xerox Corporation,
  3. * 2002 Palo Alto Research Center, Incorporated (PARC).
  4. * All rights reserved.
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Public License v1.0
  7. * which accompanies this distribution and is available at
  8. * http://www.eclipse.org/legal/epl-v10.html
  9. *
  10. * Contributors:
  11. * Xerox/PARC initial implementation
  12. * ******************************************************************/
  13. package org.aspectj.util;
  14. import java.io.BufferedOutputStream;
  15. import java.io.BufferedReader;
  16. import java.io.ByteArrayOutputStream;
  17. import java.io.DataInputStream;
  18. import java.io.DataOutputStream;
  19. import java.io.File;
  20. import java.io.FileFilter;
  21. import java.io.FileInputStream;
  22. import java.io.FileNotFoundException;
  23. import java.io.FileOutputStream;
  24. import java.io.FileReader;
  25. import java.io.FileWriter;
  26. import java.io.FilenameFilter;
  27. import java.io.IOException;
  28. import java.io.InputStream;
  29. import java.io.OutputStream;
  30. import java.io.PrintStream;
  31. import java.io.Reader;
  32. import java.io.StringReader;
  33. import java.io.Writer;
  34. import java.net.MalformedURLException;
  35. import java.net.URISyntaxException;
  36. import java.net.URL;
  37. import java.util.ArrayList;
  38. import java.util.Arrays;
  39. import java.util.Collections;
  40. import java.util.Iterator;
  41. import java.util.LinkedList;
  42. import java.util.List;
  43. import java.util.zip.ZipEntry;
  44. import java.util.zip.ZipFile;
  45. /**
  46. * @author Andy Clement
  47. * @author Kris De Volder
  48. */
  49. public class FileUtil {
  50. /** default parent directory File when a file has a null parent */
  51. public static final File DEFAULT_PARENT = new File("."); // XXX user.dir?
  52. /** unmodifiable List of String source file suffixes (including leading ".") */
  53. public static final List<String> SOURCE_SUFFIXES = Collections.unmodifiableList(Arrays.asList(new String[] { ".java", ".aj" }));
  54. public static final FileFilter ZIP_FILTER = new FileFilter() {
  55. public boolean accept(File file) {
  56. return isZipFile(file);
  57. }
  58. public String toString() {
  59. return "ZIP_FILTER";
  60. }
  61. };
  62. // public static final FileFilter SOURCE_FILTER = new FileFilter() {
  63. // public boolean accept(File file) {
  64. // return hasSourceSuffix(file);
  65. // }
  66. //
  67. // public String toString() {
  68. // return "SOURCE_FILTER";
  69. // }
  70. // };
  71. final static int[] INT_RA = new int[0];
  72. /** accept all files */
  73. public static final FileFilter ALL = new FileFilter() {
  74. public boolean accept(File f) {
  75. return true;
  76. }
  77. };
  78. public static final FileFilter DIRS_AND_WRITABLE_CLASSES = new FileFilter() {
  79. public boolean accept(File file) {
  80. return ((null != file) && (file.isDirectory() || (file.canWrite() && file.getName().toLowerCase().endsWith(".class"))));
  81. }
  82. };
  83. private static final boolean PERMIT_CVS;
  84. static {
  85. String name = FileUtil.class.getName() + ".PERMIT_CVS";
  86. PERMIT_CVS = LangUtil.getBoolean(name, false);
  87. }
  88. /** @return true if file exists and is a zip file */
  89. public static boolean isZipFile(File file) {
  90. try {
  91. return (null != file) && new ZipFile(file) != null;
  92. } catch (IOException e) {
  93. return false;
  94. }
  95. }
  96. /** @return true if path ends with .zip or .jar */
  97. // public static boolean hasZipSuffix(String path) {
  98. // return ((null != path) && (0 != zipSuffixLength(path)));
  99. // }
  100. /** @return 0 if file has no zip/jar suffix or 4 otherwise */
  101. public static int zipSuffixLength(File file) {
  102. return (null == file ? 0 : zipSuffixLength(file.getPath()));
  103. }
  104. /** @return 0 if no zip/jar suffix or 4 otherwise */
  105. public static int zipSuffixLength(String path) {
  106. if ((null != path) && (4 < path.length())) {
  107. String test = path.substring(path.length() - 4).toLowerCase();
  108. if (".zip".equals(test) || ".jar".equals(test)) {
  109. return 4;
  110. }
  111. }
  112. return 0;
  113. }
  114. /** @return true if file path has a source suffix */
  115. public static boolean hasSourceSuffix(File file) {
  116. return ((null != file) && hasSourceSuffix(file.getPath()));
  117. }
  118. /** @return true if path ends with .java or .aj */
  119. public static boolean hasSourceSuffix(String path) {
  120. return ((null != path) && (0 != sourceSuffixLength(path)));
  121. }
  122. /**
  123. * @return 0 if file has no source suffix or the length of the suffix otherwise
  124. */
  125. public static int sourceSuffixLength(File file) {
  126. return (null == file ? 0 : sourceSuffixLength(file.getPath()));
  127. }
  128. /** @return 0 if no source suffix or the length of the suffix otherwise */
  129. public static int sourceSuffixLength(String path) {
  130. if (LangUtil.isEmpty(path)) {
  131. return 0;
  132. }
  133. for (Iterator<String> iter = SOURCE_SUFFIXES.iterator(); iter.hasNext();) {
  134. String suffix = iter.next();
  135. if (path.endsWith(suffix) || path.toLowerCase().endsWith(suffix)) {
  136. return suffix.length();
  137. }
  138. }
  139. return 0;
  140. }
  141. /** @return true if this is a readable directory */
  142. public static boolean canReadDir(File dir) {
  143. return ((null != dir) && dir.canRead() && dir.isDirectory());
  144. }
  145. /** @return true if this is a readable file */
  146. public static boolean canReadFile(File file) {
  147. return ((null != file) && file.canRead() && file.isFile());
  148. }
  149. /** @return true if dir is a writable directory */
  150. public static boolean canWriteDir(File dir) {
  151. return ((null != dir) && dir.canWrite() && dir.isDirectory());
  152. }
  153. /** @return true if this is a writable file */
  154. public static boolean canWriteFile(File file) {
  155. return ((null != file) && file.canWrite() && file.isFile());
  156. }
  157. // /**
  158. // * @throws IllegalArgumentException unless file is readable and not a
  159. // * directory
  160. // */
  161. // public static void throwIaxUnlessCanReadFile(File file, String label) {
  162. // if (!canReadFile(file)) {
  163. // throw new IllegalArgumentException(label + " not readable file: " +
  164. // file);
  165. // }
  166. // }
  167. /**
  168. * @throws IllegalArgumentException unless dir is a readable directory
  169. */
  170. public static void throwIaxUnlessCanReadDir(File dir, String label) {
  171. if (!canReadDir(dir)) {
  172. throw new IllegalArgumentException(label + " not readable dir: " + dir);
  173. }
  174. }
  175. /**
  176. * @throws IllegalArgumentException unless file is readable and not a directory
  177. */
  178. public static void throwIaxUnlessCanWriteFile(File file, String label) {
  179. if (!canWriteFile(file)) {
  180. throw new IllegalArgumentException(label + " not writable file: " + file);
  181. }
  182. }
  183. /** @throws IllegalArgumentException unless dir is a readable directory */
  184. public static void throwIaxUnlessCanWriteDir(File dir, String label) {
  185. if (!canWriteDir(dir)) {
  186. throw new IllegalArgumentException(label + " not writable dir: " + dir);
  187. }
  188. }
  189. /** @return array same length as input, with String paths */
  190. public static String[] getPaths(File[] files) {
  191. if ((null == files) || (0 == files.length)) {
  192. return new String[0];
  193. }
  194. String[] result = new String[files.length];
  195. for (int i = 0; i < result.length; i++) {
  196. if (null != files[i]) {
  197. result[i] = files[i].getPath();
  198. }
  199. }
  200. return result;
  201. }
  202. /** @return array same length as input, with String paths */
  203. public static String[] getPaths(List<File> files) {
  204. final int size = (null == files ? 0 : files.size());
  205. if (0 == size) {
  206. return new String[0];
  207. }
  208. String[] result = new String[size];
  209. for (int i = 0; i < size; i++) {
  210. File file = files.get(i);
  211. if (null != file) {
  212. result[i] = file.getPath();
  213. }
  214. }
  215. return result;
  216. }
  217. /**
  218. * Extract the name of a class from the path to its file. If the basedir is null, then the class is assumed to be in the default
  219. * package unless the classFile has one of the top-level suffixes { com, org, java, javax } as a parent directory.
  220. *
  221. * @param basedir the File of the base directory (prefix of classFile)
  222. * @param classFile the File of the class to extract the name for
  223. * @throws IllegalArgumentException if classFile is null or does not end with ".class" or a non-null basedir is not a prefix of
  224. * classFile
  225. */
  226. public static String fileToClassName(File basedir, File classFile) {
  227. LangUtil.throwIaxIfNull(classFile, "classFile");
  228. String classFilePath = normalizedPath(classFile);
  229. if (!classFilePath.endsWith(".class")) {
  230. String m = classFile + " does not end with .class";
  231. throw new IllegalArgumentException(m);
  232. }
  233. classFilePath = classFilePath.substring(0, classFilePath.length() - 6);
  234. if (null != basedir) {
  235. String basePath = normalizedPath(basedir);
  236. if (!classFilePath.startsWith(basePath)) {
  237. String m = classFile + " does not start with " + basedir;
  238. throw new IllegalArgumentException(m);
  239. }
  240. classFilePath = classFilePath.substring(basePath.length() + 1);
  241. } else {
  242. final String[] suffixes = new String[] { "com", "org", "java", "javax" };
  243. boolean found = false;
  244. for (int i = 0; !found && (i < suffixes.length); i++) {
  245. int loc = classFilePath.indexOf(suffixes[i] + "/");
  246. if ((0 == loc) || ((-1 != loc) && ('/' == classFilePath.charAt(loc - 1)))) {
  247. classFilePath = classFilePath.substring(loc);
  248. found = true;
  249. }
  250. }
  251. if (!found) {
  252. int loc = classFilePath.lastIndexOf("/");
  253. if (-1 != loc) { // treat as default package
  254. classFilePath = classFilePath.substring(loc + 1);
  255. }
  256. }
  257. }
  258. return classFilePath.replace('/', '.');
  259. }
  260. /**
  261. * Normalize path for comparisons by rendering absolute, clipping basedir prefix, trimming and changing '\\' to '/'
  262. *
  263. * @param file the File with the path to normalize
  264. * @param basedir the File for the prefix of the file to normalize - ignored if null
  265. * @return "" if null or normalized path otherwise
  266. * @throws IllegalArgumentException if basedir is not a prefix of file
  267. */
  268. public static String normalizedPath(File file, File basedir) {
  269. String filePath = normalizedPath(file);
  270. if (null != basedir) {
  271. String basePath = normalizedPath(basedir);
  272. if (filePath.startsWith(basePath)) {
  273. filePath = filePath.substring(basePath.length());
  274. if (filePath.startsWith("/")) {
  275. filePath = filePath.substring(1);
  276. }
  277. }
  278. }
  279. return filePath;
  280. }
  281. /**
  282. * Render a set of files to String as a path by getting absolute paths of each and delimiting with infix.
  283. *
  284. * @param files the File[] to flatten - may be null or empty
  285. * @param infix the String delimiter internally between entries (if null, then use File.pathSeparator). (alias to
  286. * <code>flatten(getAbsolutePaths(files), infix)</code>
  287. * @return String with absolute paths to entries in order, delimited with infix
  288. */
  289. public static String flatten(File[] files, String infix) {
  290. if (LangUtil.isEmpty(files)) {
  291. return "";
  292. }
  293. return flatten(getPaths(files), infix);
  294. }
  295. /**
  296. * Flatten File[] to String.
  297. *
  298. * @param files the File[] of paths to flatten - null ignored
  299. * @param infix the String infix to use - null treated as File.pathSeparator
  300. */
  301. public static String flatten(String[] paths, String infix) {
  302. if (null == infix) {
  303. infix = File.pathSeparator;
  304. }
  305. StringBuffer result = new StringBuffer();
  306. boolean first = true;
  307. for (int i = 0; i < paths.length; i++) {
  308. String path = paths[i];
  309. if (null == path) {
  310. continue;
  311. }
  312. if (first) {
  313. first = false;
  314. } else {
  315. result.append(infix);
  316. }
  317. result.append(path);
  318. }
  319. return result.toString();
  320. }
  321. /**
  322. * Normalize path for comparisons by rendering absolute trimming and changing '\\' to '/'
  323. *
  324. * @return "" if null or normalized path otherwise
  325. */
  326. public static String normalizedPath(File file) {
  327. return (null == file ? "" : weakNormalize(file.getAbsolutePath()));
  328. }
  329. /**
  330. * Weakly normalize path for comparisons by trimming and changing '\\' to '/'
  331. */
  332. public static String weakNormalize(String path) {
  333. if (null != path) {
  334. path = path.replace('\\', '/').trim();
  335. }
  336. return path;
  337. }
  338. /**
  339. * Get best File for the first-readable path in input paths, treating entries prefixed "sp:" as system property keys. Safe to
  340. * call in static initializers.
  341. *
  342. * @param paths the String[] of paths to check.
  343. * @return null if not found, or valid File otherwise
  344. */
  345. public static File getBestFile(String[] paths) {
  346. if (null == paths) {
  347. return null;
  348. }
  349. File result = null;
  350. for (int i = 0; (null == result) && (i < paths.length); i++) {
  351. String path = paths[i];
  352. if (null == path) {
  353. continue;
  354. }
  355. if (path.startsWith("sp:")) {
  356. try {
  357. path = System.getProperty(path.substring(3));
  358. } catch (Throwable t) {
  359. path = null;
  360. }
  361. if (null == path) {
  362. continue;
  363. }
  364. }
  365. try {
  366. File f = new File(path);
  367. if (f.exists() && f.canRead()) {
  368. result = FileUtil.getBestFile(f);
  369. }
  370. } catch (Throwable t) {
  371. // swallow
  372. }
  373. }
  374. return result;
  375. }
  376. /**
  377. * Render as best file, canonical or absolute.
  378. *
  379. * @param file the File to get the best File for (not null)
  380. * @return File of the best-available path
  381. * @throws IllegalArgumentException if file is null
  382. */
  383. public static File getBestFile(File file) {
  384. LangUtil.throwIaxIfNull(file, "file");
  385. if (file.exists()) {
  386. try {
  387. return file.getCanonicalFile();
  388. } catch (IOException e) {
  389. return file.getAbsoluteFile();
  390. }
  391. } else {
  392. return file;
  393. }
  394. }
  395. /**
  396. * Render as best path, canonical or absolute.
  397. *
  398. * @param file the File to get the path for (not null)
  399. * @return String of the best-available path
  400. * @throws IllegalArgumentException if file is null
  401. */
  402. public static String getBestPath(File file) {
  403. LangUtil.throwIaxIfNull(file, "file");
  404. if (file.exists()) {
  405. try {
  406. return file.getCanonicalPath();
  407. } catch (IOException e) {
  408. return file.getAbsolutePath();
  409. }
  410. } else {
  411. return file.getPath();
  412. }
  413. }
  414. /** @return array same length as input, with String absolute paths */
  415. public static String[] getAbsolutePaths(File[] files) {
  416. if ((null == files) || (0 == files.length)) {
  417. return new String[0];
  418. }
  419. String[] result = new String[files.length];
  420. for (int i = 0; i < result.length; i++) {
  421. if (null != files[i]) {
  422. result[i] = files[i].getAbsolutePath();
  423. }
  424. }
  425. return result;
  426. }
  427. /**
  428. * Recursively delete the contents of dir, but not the dir itself
  429. *
  430. * @return the total number of files deleted
  431. */
  432. public static int deleteContents(File dir) {
  433. return deleteContents(dir, ALL);
  434. }
  435. /**
  436. * Recursively delete some contents of dir, but not the dir itself. This deletes any subdirectory which is empty after its files
  437. * are deleted.
  438. *
  439. * @return the total number of files deleted
  440. */
  441. public static int deleteContents(File dir, FileFilter filter) {
  442. return deleteContents(dir, filter, true);
  443. }
  444. /**
  445. * Recursively delete some contents of dir, but not the dir itself. If deleteEmptyDirs is true, this deletes any subdirectory
  446. * which is empty after its files are deleted.
  447. *
  448. * @param dir the File directory (if a file, the the file is deleted)
  449. * @return the total number of files deleted
  450. */
  451. public static int deleteContents(File dir, FileFilter filter, boolean deleteEmptyDirs) {
  452. if (null == dir) {
  453. throw new IllegalArgumentException("null dir");
  454. }
  455. if ((!dir.exists()) || (!dir.canWrite())) {
  456. return 0;
  457. }
  458. if (!dir.isDirectory()) {
  459. dir.delete();
  460. return 1;
  461. }
  462. String[] fromFiles = dir.list();
  463. int result = 0;
  464. for (int i = 0; i < fromFiles.length; i++) {
  465. String string = fromFiles[i];
  466. File file = new File(dir, string);
  467. if ((null == filter) || filter.accept(file)) {
  468. if (file.isDirectory()) {
  469. result += deleteContents(file, filter, deleteEmptyDirs);
  470. if (deleteEmptyDirs && (0 == file.list().length)) {
  471. file.delete();
  472. }
  473. } else {
  474. /* boolean ret = */file.delete();
  475. result++;
  476. }
  477. }
  478. }
  479. return result;
  480. }
  481. /**
  482. * Copy contents of fromDir into toDir
  483. *
  484. * @param fromDir must exist and be readable
  485. * @param toDir must exist or be creatable and be writable
  486. * @return the total number of files copied
  487. */
  488. public static int copyDir(File fromDir, File toDir) throws IOException {
  489. return copyDir(fromDir, toDir, null, null);
  490. }
  491. /**
  492. * Recursively copy files in fromDir (with any fromSuffix) to toDir, replacing fromSuffix with toSuffix if any. This silently
  493. * ignores dirs and files that are not readable but throw IOException for directories that are not writable. This does not clean
  494. * out the original contents of toDir. (subdirectories are not renamed per directory rules)
  495. *
  496. * @param fromSuffix select files with this suffix - select all if null or empty
  497. * @param toSuffix replace fromSuffix with toSuffix in the destination file name - ignored if null or empty, appended to name if
  498. * fromSuffix is null or empty
  499. * @return the total number of files copied
  500. */
  501. public static int copyDir(File fromDir, File toDir, final String fromSuffix, String toSuffix) throws IOException {
  502. return copyDir(fromDir, toDir, fromSuffix, toSuffix, (FileFilter) null);
  503. }
  504. // /**
  505. // * Recursively copy files in fromDir (with any fromSuffix) to toDir,
  506. // * replacing fromSuffix with toSuffix if any, and adding the destination
  507. // * file to any collector. This silently ignores dirs and files that are
  508. // not
  509. // * readable but throw IOException for directories that are not writable.
  510. // * This does not clean out the original contents of toDir. (subdirectories
  511. // * are not renamed per directory rules) This calls any delegate
  512. // * FilenameFilter to collect any selected file.
  513. // *
  514. // * @param fromSuffix select files with this suffix - select all if null or
  515. // * empty
  516. // * @param toSuffix replace fromSuffix with toSuffix in the destination
  517. // file
  518. // * name - ignored if null or empty, appended to name if
  519. // * fromSuffix is null or empty
  520. // * @param collector the List sink for destination files - ignored if null
  521. // * @return the total number of files copied
  522. // */
  523. // public static int copyDir(File fromDir, File toDir, final String
  524. // fromSuffix, final String toSuffix, final List collector)
  525. // throws IOException {
  526. // // int before = collector.size();
  527. // if (null == collector) {
  528. // return copyDir(fromDir, toDir, fromSuffix, toSuffix);
  529. // } else {
  530. // FileFilter collect = new FileFilter() {
  531. // public boolean accept(File pathname) {
  532. // return collector.add(pathname);
  533. // }
  534. // };
  535. // return copyDir(fromDir, toDir, fromSuffix, toSuffix, collect);
  536. // }
  537. // }
  538. /**
  539. * Recursively copy files in fromDir (with any fromSuffix) to toDir, replacing fromSuffix with toSuffix if any. This silently
  540. * ignores dirs and files that are not readable but throw IOException for directories that are not writable. This does not clean
  541. * out the original contents of toDir. (subdirectories are not renamed per directory rules) This calls any delegate
  542. * FilenameFilter to collect any selected file.
  543. *
  544. * @param fromSuffix select files with this suffix - select all if null or empty
  545. * @param toSuffix replace fromSuffix with toSuffix in the destination file name - ignored if null or empty, appended to name if
  546. * fromSuffix is null or empty
  547. * @return the total number of files copied
  548. */
  549. public static int copyDir(File fromDir, File toDir, final String fromSuffix, final String toSuffix, final FileFilter delegate)
  550. throws IOException {
  551. if ((null == fromDir) || (!fromDir.canRead())) {
  552. return 0;
  553. }
  554. final boolean haveSuffix = ((null != fromSuffix) && (0 < fromSuffix.length()));
  555. final int slen = (!haveSuffix ? 0 : fromSuffix.length());
  556. if (!toDir.exists()) {
  557. toDir.mkdirs();
  558. }
  559. final String[] fromFiles;
  560. if (!haveSuffix) {
  561. fromFiles = fromDir.list();
  562. } else {
  563. FilenameFilter filter = new FilenameFilter() {
  564. public boolean accept(File dir, String name) {
  565. return (new File(dir, name).isDirectory() || (name.endsWith(fromSuffix)));
  566. }
  567. };
  568. fromFiles = fromDir.list(filter);
  569. }
  570. int result = 0;
  571. final int MAX = (null == fromFiles ? 0 : fromFiles.length);
  572. for (int i = 0; i < MAX; i++) {
  573. String filename = fromFiles[i];
  574. File fromFile = new File(fromDir, filename);
  575. if (fromFile.canRead()) {
  576. if (fromFile.isDirectory()) {
  577. result += copyDir(fromFile, new File(toDir, filename), fromSuffix, toSuffix, delegate);
  578. } else if (fromFile.isFile()) {
  579. if (haveSuffix) {
  580. filename = filename.substring(0, filename.length() - slen);
  581. }
  582. if (null != toSuffix) {
  583. filename = filename + toSuffix;
  584. }
  585. File targetFile = new File(toDir, filename);
  586. if ((null == delegate) || delegate.accept(targetFile)) {
  587. copyFile(fromFile, targetFile);
  588. }
  589. result++;
  590. }
  591. }
  592. }
  593. return result;
  594. }
  595. /**
  596. * Recursively list files in srcDir.
  597. *
  598. * @return ArrayList with String paths of File under srcDir (relative to srcDir)
  599. */
  600. public static String[] listFiles(File srcDir) {
  601. ArrayList<String> result = new ArrayList<String>();
  602. if ((null != srcDir) && srcDir.canRead()) {
  603. listFiles(srcDir, null, result);
  604. }
  605. return result.toArray(new String[0]);
  606. }
  607. public static final FileFilter aspectjSourceFileFilter = new FileFilter() {
  608. public boolean accept(File pathname) {
  609. String name = pathname.getName().toLowerCase();
  610. return name.endsWith(".java") || name.endsWith(".aj");
  611. }
  612. };
  613. /**
  614. * Recursively list files in srcDir.
  615. *
  616. * @return ArrayList with String paths of File under srcDir (relative to srcDir)
  617. */
  618. public static File[] listFiles(File srcDir, FileFilter fileFilter) {
  619. ArrayList<File> result = new ArrayList<File>();
  620. if ((null != srcDir) && srcDir.canRead()) {
  621. listFiles(srcDir, result, fileFilter);
  622. }
  623. return result.toArray(new File[result.size()]);
  624. }
  625. /**
  626. * Recursively list .class files in specified directory
  627. *
  628. * @return List of File objects
  629. */
  630. public static List<File> listClassFiles(File dir) {
  631. ArrayList<File> result = new ArrayList<File>();
  632. if ((null != dir) && dir.canRead()) {
  633. listClassFiles(dir, result);
  634. }
  635. return result;
  636. }
  637. /**
  638. * Convert String[] paths to File[] as offset of base directory
  639. *
  640. * @param basedir the non-null File base directory for File to create with paths
  641. * @param paths the String[] of paths to create
  642. * @return File[] with same length as paths
  643. */
  644. public static File[] getBaseDirFiles(File basedir, String[] paths) {
  645. return getBaseDirFiles(basedir, paths, (String[]) null);
  646. }
  647. /**
  648. * Convert String[] paths to File[] as offset of base directory
  649. *
  650. * @param basedir the non-null File base directory for File to create with paths
  651. * @param paths the String[] of paths to create
  652. * @param suffixes the String[] of suffixes to limit sources to - ignored if null
  653. * @return File[] with same length as paths
  654. */
  655. public static File[] getBaseDirFiles(File basedir, String[] paths, String[] suffixes) {
  656. LangUtil.throwIaxIfNull(basedir, "basedir");
  657. LangUtil.throwIaxIfNull(paths, "paths");
  658. File[] result = null;
  659. if (!LangUtil.isEmpty(suffixes)) {
  660. ArrayList<File> list = new ArrayList<File>();
  661. for (int i = 0; i < paths.length; i++) {
  662. String path = paths[i];
  663. for (int j = 0; j < suffixes.length; j++) {
  664. if (path.endsWith(suffixes[j])) {
  665. list.add(new File(basedir, paths[i]));
  666. break;
  667. }
  668. }
  669. }
  670. result = list.toArray(new File[0]);
  671. } else {
  672. result = new File[paths.length];
  673. for (int i = 0; i < result.length; i++) {
  674. result[i] = newFile(basedir, paths[i]);
  675. }
  676. }
  677. return result;
  678. }
  679. /**
  680. * Create a new File, resolving paths ".." and "." specially.
  681. *
  682. * @param dir the File for the parent directory of the file
  683. * @param path the path in the parent directory (filename only?)
  684. * @return File for the new file.
  685. */
  686. private static File newFile(File dir, String path) {
  687. if (".".equals(path)) {
  688. return dir;
  689. } else if ("..".equals(path)) {
  690. File parentDir = dir.getParentFile();
  691. if (null != parentDir) {
  692. return parentDir;
  693. } else {
  694. return new File(dir, "..");
  695. }
  696. } else {
  697. return new File(dir, path);
  698. }
  699. }
  700. /**
  701. * Copy files from source dir into destination directory, creating any needed directories. This differs from copyDir in not
  702. * being recursive; each input with the source dir creates a full path. However, if the source is a directory, it is copied as
  703. * such.
  704. *
  705. * @param srcDir an existing, readable directory containing relativePaths files
  706. * @param relativePaths a set of paths relative to srcDir to readable File to copy
  707. * @param destDir an existing, writable directory to copy files to
  708. * @throws IllegalArgumentException if input invalid, IOException if operations fail
  709. */
  710. public static File[] copyFiles(File srcDir, String[] relativePaths, File destDir) throws IllegalArgumentException, IOException {
  711. final String[] paths = relativePaths;
  712. throwIaxUnlessCanReadDir(srcDir, "srcDir");
  713. throwIaxUnlessCanWriteDir(destDir, "destDir");
  714. LangUtil.throwIaxIfNull(paths, "relativePaths");
  715. File[] result = new File[paths.length];
  716. for (int i = 0; i < paths.length; i++) {
  717. String path = paths[i];
  718. LangUtil.throwIaxIfNull(path, "relativePaths-entry");
  719. File src = newFile(srcDir, paths[i]);
  720. File dest = newFile(destDir, path);
  721. File destParent = dest.getParentFile();
  722. if (!destParent.exists()) {
  723. destParent.mkdirs();
  724. }
  725. LangUtil.throwIaxIfFalse(canWriteDir(destParent), "dest-entry-parent");
  726. copyFile(src, dest); // both file-dir and dir-dir copies
  727. result[i] = dest;
  728. }
  729. return result;
  730. }
  731. /**
  732. * Copy fromFile to toFile, handling file-file, dir-dir, and file-dir copies.
  733. *
  734. * @param fromFile the File path of the file or directory to copy - must be readable
  735. * @param toFile the File path of the target file or directory - must be writable (will be created if it does not exist)
  736. */
  737. public static void copyFile(File fromFile, File toFile) throws IOException {
  738. LangUtil.throwIaxIfNull(fromFile, "fromFile");
  739. LangUtil.throwIaxIfNull(toFile, "toFile");
  740. LangUtil.throwIaxIfFalse(!toFile.equals(fromFile), "same file");
  741. if (toFile.isDirectory()) { // existing directory
  742. throwIaxUnlessCanWriteDir(toFile, "toFile");
  743. if (fromFile.isFile()) { // file-dir
  744. File targFile = new File(toFile, fromFile.getName());
  745. copyValidFiles(fromFile, targFile);
  746. } else if (fromFile.isDirectory()) { // dir-dir
  747. copyDir(fromFile, toFile);
  748. } else {
  749. LangUtil.throwIaxIfFalse(false, "not dir or file: " + fromFile);
  750. }
  751. } else if (toFile.isFile()) { // target file exists
  752. if (fromFile.isDirectory()) {
  753. LangUtil.throwIaxIfFalse(false, "can't copy to file dir: " + fromFile);
  754. }
  755. copyValidFiles(fromFile, toFile); // file-file
  756. } else { // target file is a non-existent path -- could be file or dir
  757. /* File toFileParent = */ensureParentWritable(toFile);
  758. if (fromFile.isFile()) {
  759. copyValidFiles(fromFile, toFile);
  760. } else if (fromFile.isDirectory()) {
  761. toFile.mkdirs();
  762. throwIaxUnlessCanWriteDir(toFile, "toFile");
  763. copyDir(fromFile, toFile);
  764. } else {
  765. LangUtil.throwIaxIfFalse(false, "not dir or file: " + fromFile);
  766. }
  767. }
  768. }
  769. /**
  770. * Ensure that the parent directory to path can be written. If the path has a null parent, DEFAULT_PARENT is tested. If the path
  771. * parent does not exist, this tries to create it.
  772. *
  773. * @param path the File path whose parent should be writable
  774. * @return the File path of the writable parent directory
  775. * @throws IllegalArgumentException if parent cannot be written or path is null.
  776. */
  777. public static File ensureParentWritable(File path) {
  778. LangUtil.throwIaxIfNull(path, "path");
  779. File pathParent = path.getParentFile();
  780. if (null == pathParent) {
  781. pathParent = DEFAULT_PARENT;
  782. }
  783. if (!pathParent.canWrite()) {
  784. pathParent.mkdirs();
  785. }
  786. throwIaxUnlessCanWriteDir(pathParent, "pathParent");
  787. return pathParent;
  788. }
  789. /**
  790. * Copy file to file.
  791. *
  792. * @param fromFile the File to copy (readable, non-null file)
  793. * @param toFile the File to copy to (non-null, parent dir exists)
  794. * @throws IOException
  795. */
  796. public static void copyValidFiles(File fromFile, File toFile) throws IOException {
  797. FileInputStream in = null;
  798. FileOutputStream out = null;
  799. try {
  800. in = new FileInputStream(fromFile);
  801. out = new FileOutputStream(toFile);
  802. copyStream(in, out);
  803. } finally {
  804. if (out != null) {
  805. out.close();
  806. }
  807. if (in != null) {
  808. in.close();
  809. }
  810. }
  811. }
  812. /** do line-based copying */
  813. @SuppressWarnings("deprecation")
  814. public static void copyStream(DataInputStream in, PrintStream out) throws IOException {
  815. LangUtil.throwIaxIfNull(in, "in");
  816. LangUtil.throwIaxIfNull(in, "out");
  817. String s;
  818. while (null != (s = in.readLine())) {
  819. out.println(s);
  820. }
  821. }
  822. public static void copyStream(InputStream in, OutputStream out) throws IOException {
  823. final int MAX = 4096;
  824. byte[] buf = new byte[MAX];
  825. for (int bytesRead = in.read(buf, 0, MAX); bytesRead != -1; bytesRead = in.read(buf, 0, MAX)) {
  826. out.write(buf, 0, bytesRead);
  827. }
  828. }
  829. public static void copyStream(Reader in, Writer out) throws IOException {
  830. final int MAX = 4096;
  831. char[] buf = new char[MAX];
  832. for (int bytesRead = in.read(buf, 0, MAX); bytesRead != -1; bytesRead = in.read(buf, 0, MAX)) {
  833. out.write(buf, 0, bytesRead);
  834. }
  835. }
  836. /**
  837. * Make a new child directory of parent
  838. *
  839. * @param parent a File for the parent (writable)
  840. * @param child a prefix for the child directory
  841. * @return a File dir that exists with parentDir as the parent file or null
  842. */
  843. public static File makeNewChildDir(File parent, String child) {
  844. if (null == parent || !parent.canWrite() || !parent.isDirectory()) {
  845. throw new IllegalArgumentException("bad parent: " + parent);
  846. } else if (null == child) {
  847. child = "makeNewChildDir";
  848. } else if (!isValidFileName(child)) {
  849. throw new IllegalArgumentException("bad child: " + child);
  850. }
  851. File result = new File(parent, child);
  852. int safety = 1000;
  853. for (String suffix = FileUtil.randomFileString(); ((0 < --safety) && result.exists()); suffix = FileUtil.randomFileString()) {
  854. result = new File(parent, child + suffix);
  855. }
  856. if (result.exists()) {
  857. System.err.println("exhausted files for child dir in " + parent);
  858. return null;
  859. }
  860. return ((result.mkdirs() && result.exists()) ? result : null);
  861. }
  862. /**
  863. * Make a new temporary directory in the same directory that the system uses for temporary files, or if that files, in the
  864. * current directory.
  865. *
  866. * @param name the preferred (simple) name of the directory - may be null.
  867. * @return File of an existing new temp dir, or null if unable to create
  868. */
  869. public static File getTempDir(String name) {
  870. if (null == name) {
  871. name = "FileUtil_getTempDir";
  872. } else if (!isValidFileName(name)) {
  873. throw new IllegalArgumentException(" invalid: " + name);
  874. }
  875. File result = null;
  876. File tempFile = null;
  877. try {
  878. tempFile = File.createTempFile("ignoreMe", ".txt");
  879. File tempParent = tempFile.getParentFile();
  880. result = makeNewChildDir(tempParent, name);
  881. } catch (IOException t) {
  882. result = makeNewChildDir(new File("."), name);
  883. } finally {
  884. if (null != tempFile) {
  885. tempFile.delete();
  886. }
  887. }
  888. return result;
  889. }
  890. public static URL[] getFileURLs(File[] files) {
  891. if ((null == files) || (0 == files.length)) {
  892. return new URL[0];
  893. }
  894. URL[] result = new URL[files.length]; // XXX dangerous non-copy...
  895. for (int i = 0; i < result.length; i++) {
  896. result[i] = getFileURL(files[i]);
  897. }
  898. return result;
  899. }
  900. /**
  901. * Get URL for a File. This appends "/" for directories. prints errors to System.err
  902. *
  903. * @param file the File to convert to URL (not null)
  904. */
  905. @SuppressWarnings("deprecation")
  906. public static URL getFileURL(File file) {
  907. LangUtil.throwIaxIfNull(file, "file");
  908. URL result = null;
  909. try {
  910. result = file.toURL();// TODO AV - was toURI.toURL that does not
  911. // works on Java 1.3
  912. if (null != result) {
  913. return result;
  914. }
  915. String url = "file:" + file.getAbsolutePath().replace('\\', '/');
  916. result = new URL(url + (file.isDirectory() ? "/" : ""));
  917. } catch (MalformedURLException e) {
  918. String m = "Util.makeURL(\"" + file.getPath() + "\" MUE " + e.getMessage();
  919. System.err.println(m);
  920. }
  921. return result;
  922. }
  923. /**
  924. * Write contents to file, returning null on success or error message otherwise. This tries to make any necessary parent
  925. * directories first.
  926. *
  927. * @param file the File to write (not null)
  928. * @param contents the String to write (use "" if null)
  929. * @return String null on no error, error otherwise
  930. */
  931. public static String writeAsString(File file, String contents) {
  932. LangUtil.throwIaxIfNull(file, "file");
  933. if (null == contents) {
  934. contents = "";
  935. }
  936. Writer out = null;
  937. try {
  938. File parentDir = file.getParentFile();
  939. if (!parentDir.exists() && !parentDir.mkdirs()) {
  940. return "unable to make parent dir for " + file;
  941. }
  942. Reader in = new StringReader(contents);
  943. out = new FileWriter(file);
  944. FileUtil.copyStream(in, out);
  945. return null;
  946. } catch (IOException e) {
  947. return LangUtil.unqualifiedClassName(e) + " writing " + file + ": " + e.getMessage();
  948. } finally {
  949. if (null != out) {
  950. try {
  951. out.close();
  952. } catch (IOException e) {
  953. } // ignored
  954. }
  955. }
  956. }
  957. /**
  958. * Reads a boolean array with our encoding
  959. */
  960. public static boolean[] readBooleanArray(DataInputStream s) throws IOException {
  961. int len = s.readInt();
  962. boolean[] ret = new boolean[len];
  963. for (int i = 0; i < len; i++) {
  964. ret[i] = s.readBoolean();
  965. }
  966. return ret;
  967. }
  968. /**
  969. * Writes a boolean array with our encoding
  970. */
  971. public static void writeBooleanArray(boolean[] a, DataOutputStream s) throws IOException {
  972. int len = a.length;
  973. s.writeInt(len);
  974. for (int i = 0; i < len; i++) {
  975. s.writeBoolean(a[i]);
  976. }
  977. }
  978. /**
  979. * Reads an int array with our encoding
  980. */
  981. public static int[] readIntArray(DataInputStream s) throws IOException {
  982. int len = s.readInt();
  983. int[] ret = new int[len];
  984. for (int i = 0; i < len; i++) {
  985. ret[i] = s.readInt();
  986. }
  987. return ret;
  988. }
  989. /**
  990. * Writes an int array with our encoding
  991. */
  992. public static void writeIntArray(int[] a, DataOutputStream s) throws IOException {
  993. int len = a.length;
  994. s.writeInt(len);
  995. for (int i = 0; i < len; i++) {
  996. s.writeInt(a[i]);
  997. }
  998. }
  999. /**
  1000. * Reads an int array with our encoding
  1001. */
  1002. public static String[] readStringArray(DataInputStream s) throws IOException {
  1003. int len = s.readInt();
  1004. String[] ret = new String[len];
  1005. for (int i = 0; i < len; i++) {
  1006. ret[i] = s.readUTF();
  1007. }
  1008. return ret;
  1009. }
  1010. /**
  1011. * Writes an int array with our encoding
  1012. */
  1013. public static void writeStringArray(String[] a, DataOutputStream s) throws IOException {
  1014. if (a == null) {
  1015. s.writeInt(0);
  1016. return;
  1017. }
  1018. int len = a.length;
  1019. s.writeInt(len);
  1020. for (int i = 0; i < len; i++) {
  1021. s.writeUTF(a[i]);
  1022. }
  1023. }
  1024. /**
  1025. * Returns the contents of this file as a String
  1026. */
  1027. public static String readAsString(File file) throws IOException {
  1028. BufferedReader r = new BufferedReader(new FileReader(file));
  1029. StringBuffer b = new StringBuffer();
  1030. while (true) {
  1031. int ch = r.read();
  1032. if (ch == -1) {
  1033. break;
  1034. }
  1035. b.append((char) ch);
  1036. }
  1037. r.close();
  1038. return b.toString();
  1039. }
  1040. // /**
  1041. // * Returns the contents of this stream as a String
  1042. // */
  1043. // public static String readAsString(InputStream in) throws IOException {
  1044. // BufferedReader r = new BufferedReader(new InputStreamReader(in));
  1045. // StringBuffer b = new StringBuffer();
  1046. // while (true) {
  1047. // int ch = r.read();
  1048. // if (ch == -1)
  1049. // break;
  1050. // b.append((char) ch);
  1051. // }
  1052. // in.close();
  1053. // r.close();
  1054. // return b.toString();
  1055. // }
  1056. /**
  1057. * Returns the contents of this file as a byte[]
  1058. */
  1059. public static byte[] readAsByteArray(File file) throws IOException {
  1060. FileInputStream in = new FileInputStream(file);
  1061. byte[] ret = FileUtil.readAsByteArray(in);
  1062. in.close();
  1063. return ret;
  1064. }
  1065. /**
  1066. * Reads this input stream and returns contents as a byte[]
  1067. */
  1068. public static byte[] readAsByteArray(InputStream inStream) throws IOException {
  1069. int size = 1024;
  1070. byte[] ba = new byte[size];
  1071. int readSoFar = 0;
  1072. while (true) {
  1073. int nRead = inStream.read(ba, readSoFar, size - readSoFar);
  1074. if (nRead == -1) {
  1075. break;
  1076. }
  1077. readSoFar += nRead;
  1078. if (readSoFar == size) {
  1079. int newSize = size * 2;
  1080. byte[] newBa = new byte[newSize];
  1081. System.arraycopy(ba, 0, newBa, 0, size);
  1082. ba = newBa;
  1083. size = newSize;
  1084. }
  1085. }
  1086. byte[] newBa = new byte[readSoFar];
  1087. System.arraycopy(ba, 0, newBa, 0, readSoFar);
  1088. return newBa;
  1089. }
  1090. final static String FILECHARS = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  1091. /** @return semi-random String of length 6 usable as filename suffix */
  1092. static String randomFileString() {
  1093. final double FILECHARS_length = FILECHARS.length();
  1094. final int LEN = 6;
  1095. final char[] result = new char[LEN];
  1096. int index = (int) (Math.random() * 6d);
  1097. for (int i = 0; i < LEN; i++) {
  1098. if (index >= LEN) {
  1099. index = 0;
  1100. }
  1101. result[index++] = FILECHARS.charAt((int) (Math.random() * FILECHARS_length));
  1102. }
  1103. return new String(result);
  1104. }
  1105. public static InputStream getStreamFromZip(String zipFile, String name) {
  1106. try {
  1107. ZipFile zf = new ZipFile(zipFile);
  1108. try {
  1109. ZipEntry entry = zf.getEntry(name);
  1110. return zf.getInputStream(entry);
  1111. } finally {
  1112. // ??? is it safe not to close this zf.close();
  1113. }
  1114. } catch (IOException ioe) {
  1115. return null;
  1116. }
  1117. }
  1118. //
  1119. // public static void extractJar(String zipFile, String outDir) throws
  1120. // IOException {
  1121. // ZipInputStream zs = new ZipInputStream(new FileInputStream(zipFile));
  1122. // ZipEntry entry;
  1123. // while ((entry = zs.getNextEntry()) != null) {
  1124. // if (entry.isDirectory())
  1125. // continue;
  1126. // byte[] in = readAsByteArray(zs);
  1127. //
  1128. // File outFile = new File(outDir + "/" + entry.getName());
  1129. // // if (!outFile.getParentFile().exists())
  1130. // // System.err.println("parent: " + outFile.getParentFile());
  1131. // // System.err.println("parent: " + outFile.getParentFile());
  1132. // outFile.getParentFile().mkdirs();
  1133. // FileOutputStream os = new FileOutputStream(outFile);
  1134. // os.write(in);
  1135. // os.close();
  1136. // zs.closeEntry();
  1137. // }
  1138. // zs.close();
  1139. // }
  1140. /**
  1141. * Do line-based search for literal text in source files, returning file:line where found.
  1142. *
  1143. * @param sought the String text to seek in the file
  1144. * @param sources the List of String paths to the source files
  1145. * @param listAll if false, only list first match in file
  1146. * @param errorSink the PrintStream to print any errors to (one per line) (use null to silently ignore errors)
  1147. * @return List of String of the form file:line for each found entry (never null, might be empty)
  1148. */
  1149. // OPTIMIZE only used by tests? move it out
  1150. public static List<String> lineSeek(String sought, List<String> sources, boolean listAll, PrintStream errorSink) {
  1151. if (LangUtil.isEmpty(sought) || LangUtil.isEmpty(sources)) {
  1152. return Collections.emptyList();
  1153. }
  1154. ArrayList<String> result = new ArrayList<String>();
  1155. for (Iterator<String> iter = sources.iterator(); iter.hasNext();) {
  1156. String path = iter.next();
  1157. String error = lineSeek(sought, path, listAll, result);
  1158. if ((null != error) && (null != errorSink)) {
  1159. errorSink.println(error);
  1160. }
  1161. }
  1162. return result;
  1163. }
  1164. /**
  1165. * Do line-based search for literal text in source file, returning line where found as a String in the form
  1166. * {sourcePath}:line:column submitted to the collecting parameter sink. Any error is rendered to String and returned as the
  1167. * result.
  1168. *
  1169. * @param sought the String text to seek in the file
  1170. * @param sources the List of String paths to the source files
  1171. * @param listAll if false, only list first match in file
  1172. * @param List sink the List for String entries of the form {sourcePath}:line:column
  1173. * @return String error if any, or add String entries to sink
  1174. */
  1175. public static String lineSeek(String sought, String sourcePath, boolean listAll, ArrayList<String> sink) {
  1176. if (LangUtil.isEmpty(sought) || LangUtil.isEmpty(sourcePath)) {
  1177. return "nothing sought";
  1178. }
  1179. if (LangUtil.isEmpty(sourcePath)) {
  1180. return "no sourcePath";
  1181. }
  1182. final File file = new File(sourcePath);
  1183. if (!file.canRead() || !file.isFile()) {
  1184. return "sourcePath not a readable file";
  1185. }
  1186. int lineNum = 0;
  1187. FileReader fin = null;
  1188. try {
  1189. fin = new FileReader(file);
  1190. BufferedReader reader = new BufferedReader(fin);
  1191. String line;
  1192. while (null != (line = reader.readLine())) {
  1193. lineNum++;
  1194. int loc = line.indexOf(sought);
  1195. if (-1 != loc) {
  1196. sink.add(sourcePath + ":" + lineNum + ":" + loc);
  1197. if (!listAll) {
  1198. break;
  1199. }
  1200. }
  1201. }
  1202. } catch (IOException e) {
  1203. return LangUtil.unqualifiedClassName(e) + " reading " + sourcePath + ":" + lineNum;
  1204. } finally {
  1205. try {
  1206. if (null != fin) {
  1207. fin.close();
  1208. }
  1209. } catch (IOException e) {
  1210. } // ignore
  1211. }
  1212. return null;
  1213. }
  1214. public static BufferedOutputStream makeOutputStream(File file) throws FileNotFoundException {
  1215. File parent = file.getParentFile();
  1216. if (parent != null) {
  1217. parent.mkdirs();
  1218. }
  1219. return new BufferedOutputStream(new FileOutputStream(file));
  1220. }
  1221. /**
  1222. * Sleep until after the last last-modified stamp from the files.
  1223. *
  1224. * @param files the File[] of files to inspect for last modified times (this ignores null or empty files array and null or
  1225. * non-existing components of files array)
  1226. * @return true if succeeded without 100 interrupts
  1227. */
  1228. public static boolean sleepPastFinalModifiedTime(File[] files) {
  1229. if ((null == files) || (0 == files.length)) {
  1230. return true;
  1231. }
  1232. long delayUntil = System.currentTimeMillis();
  1233. for (int i = 0; i < files.length; i++) {
  1234. File file = files[i];
  1235. if ((null == file) || !file.exists()) {
  1236. continue;
  1237. }
  1238. long nextModTime = file.lastModified();
  1239. if (nextModTime > delayUntil) {
  1240. delayUntil = nextModTime;
  1241. }
  1242. }
  1243. return LangUtil.sleepUntil(++delayUntil);
  1244. }
  1245. private static void listClassFiles(final File baseDir, ArrayList<File> result) {
  1246. File[] files = baseDir.listFiles();
  1247. for (int i = 0; i < files.length; i++) {
  1248. File f = files[i];
  1249. if (f.isDirectory()) {
  1250. listClassFiles(f, result);
  1251. } else {
  1252. if (f.getName().endsWith(".class")) {
  1253. result.add(f);
  1254. }
  1255. }
  1256. }
  1257. }
  1258. private static void listFiles(final File baseDir, ArrayList<File> result, FileFilter filter) {
  1259. File[] files = baseDir.listFiles();
  1260. // hack https://bugs.eclipse.org/bugs/show_bug.cgi?id=48650
  1261. final boolean skipCVS = (!PERMIT_CVS && (filter == aspectjSourceFileFilter));
  1262. for (int i = 0; i < files.length; i++) {
  1263. File f = files[i];
  1264. if (f.isDirectory()) {
  1265. if (skipCVS) {
  1266. String name = f.getName().toLowerCase();
  1267. if ("cvs".equals(name) || "sccs".equals(name)) {
  1268. continue;
  1269. }
  1270. }
  1271. listFiles(f, result, filter);
  1272. } else {
  1273. if (filter.accept(f)) {
  1274. result.add(f);
  1275. }
  1276. }
  1277. }
  1278. }
  1279. /** @return true if input is not null and contains no path separator */
  1280. private static boolean isValidFileName(String input) {
  1281. return ((null != input) && (-1 == input.indexOf(File.pathSeparator)));
  1282. }
  1283. private static void listFiles(final File baseDir, String dir, ArrayList<String> result) {
  1284. final String dirPrefix = (null == dir ? "" : dir + "/");
  1285. final File dirFile = (null == dir ? baseDir : new File(baseDir.getPath() + "/" + dir));
  1286. final String[] files = dirFile.list();
  1287. for (int i = 0; i < files.length; i++) {
  1288. File f = new File(dirFile, files[i]);
  1289. String path = dirPrefix + files[i];
  1290. if (f.isDirectory()) {
  1291. listFiles(baseDir, path, result);
  1292. } else {
  1293. result.add(path);
  1294. }
  1295. }
  1296. }
  1297. private FileUtil() {
  1298. }
  1299. public static List<String> makeClasspath(URL[] urls) {
  1300. List<String> ret = new LinkedList<String>();
  1301. if (urls != null) {
  1302. for (int i = 0; i < urls.length; i++) {
  1303. ret.add(toPathString(urls[i]));
  1304. }
  1305. }
  1306. return ret;
  1307. }
  1308. private static String toPathString(URL url) {
  1309. try {
  1310. return url.toURI().getPath();
  1311. } catch (URISyntaxException e) {
  1312. System.err.println("Warning!! Malformed URL may cause problems: "+url); // TODO: Better way to report this?
  1313. // In this case it was likely not using properly escaped
  1314. // characters so we just use the 'bad' method that doesn't decode
  1315. // special chars
  1316. return url.getPath();
  1317. }
  1318. }
  1319. /**
  1320. * A pipe when run reads from an input stream to an output stream, optionally sleeping between reads.
  1321. *
  1322. * @see #copyStream(InputStream, OutputStream)
  1323. */
  1324. public static class Pipe implements Runnable {
  1325. private final InputStream in;
  1326. private final OutputStream out;
  1327. private final long sleep;
  1328. private ByteArrayOutputStream snoop;
  1329. private long totalWritten;
  1330. private Throwable thrown;
  1331. private boolean halt;
  1332. /**
  1333. * Seem to be unable to detect erroroneous closing of System.out...
  1334. */
  1335. private final boolean closeInput;
  1336. private final boolean closeOutput;
  1337. /**
  1338. * If true, then continue processing stream until no characters are returned when halting.
  1339. */
  1340. private boolean finishStream;
  1341. private boolean done; // true after completing() completes
  1342. /**
  1343. * alias for <code>Pipe(in, out, 100l, false, false)</code>
  1344. *
  1345. * @param in the InputStream source to read
  1346. * @param out the OutputStream sink to write
  1347. */
  1348. Pipe(InputStream in, OutputStream out) {
  1349. this(in, out, 100l, false, false);
  1350. }
  1351. /**
  1352. * @param in the InputStream source to read
  1353. * @param out the OutputStream sink to write
  1354. * @param tryClosingStreams if true, then try closing both streams when done
  1355. * @param sleep milliseconds to delay between reads (pinned to 0..1 minute)
  1356. */
  1357. Pipe(InputStream in, OutputStream out, long sleep, boolean closeInput, boolean closeOutput) {
  1358. LangUtil.throwIaxIfNull(in, "in");
  1359. LangUtil.throwIaxIfNull(out, "out");
  1360. this.in = in;
  1361. this.out = out;
  1362. this.closeInput = closeInput;
  1363. this.closeOutput = closeOutput;
  1364. this.sleep = Math.min(0l, Math.max(60l * 1000l, sleep));
  1365. }
  1366. public void setSnoop(ByteArrayOutputStream snoop) {
  1367. this.snoop = snoop;
  1368. }
  1369. /**
  1370. * Run the pipe. This halts on the first Throwable thrown or when a read returns -1 (for end-of-file) or on demand.
  1371. */
  1372. public void run() {
  1373. totalWritten = 0;
  1374. if (halt) {
  1375. return;
  1376. }
  1377. try {
  1378. final int MAX = 4096;
  1379. byte[] buf = new byte[MAX];
  1380. // TODO this blocks, hanging the harness
  1381. int count = in.read(buf, 0, MAX);
  1382. ByteArrayOutputStream mySnoop;
  1383. while ((halt && finishStream && (0 < count)) || (!halt && (-1 != count))) {
  1384. out.write(buf, 0, count);
  1385. mySnoop = snoop;
  1386. if (null != mySnoop) {
  1387. mySnoop.write(buf, 0, count);
  1388. }
  1389. totalWritten += count;
  1390. if (halt && !finishStream) {
  1391. break;
  1392. }
  1393. if (!halt && (0 < sleep)) {
  1394. Thread.sleep(sleep);
  1395. }
  1396. if (halt && !finishStream) {
  1397. break;
  1398. }
  1399. count = in.read(buf, 0, MAX);
  1400. }
  1401. } catch (Throwable e) {
  1402. thrown = e;
  1403. } finally {
  1404. halt = true;
  1405. if (closeInput) {
  1406. try {
  1407. in.close();
  1408. } catch (IOException e) {
  1409. // ignore
  1410. }
  1411. }
  1412. if (closeOutput) {
  1413. try {
  1414. out.close();
  1415. } catch (IOException e) {
  1416. // ignore
  1417. }
  1418. }
  1419. done = true;
  1420. completing(totalWritten, thrown);
  1421. }
  1422. }
  1423. /**
  1424. * Tell the pipe to halt the next time it gains control.
  1425. *
  1426. * @param wait if true, this waits synchronously until pipe is done
  1427. * @param finishStream if true, then continue until a read from the input stream returns no bytes, then halt.
  1428. * @return true if <code>run()</code> will return the next time it gains control
  1429. */
  1430. public boolean halt(boolean wait, boolean finishStream) {
  1431. if (!halt) {
  1432. halt = true;
  1433. }
  1434. if (wait) {
  1435. while (!done) {
  1436. synchronized (this) {
  1437. notifyAll();
  1438. }
  1439. if (!done) {
  1440. try {
  1441. Thread.sleep(5l);
  1442. } catch (InterruptedException e) {
  1443. break;
  1444. }
  1445. }
  1446. }
  1447. }
  1448. return halt;
  1449. }
  1450. /** @return the total number of bytes written */
  1451. public long totalWritten() {
  1452. return totalWritten;
  1453. }
  1454. /** @return any exception thrown when reading/writing */
  1455. public Throwable getThrown() {
  1456. return thrown;
  1457. }
  1458. /**
  1459. * This is called when the pipe is completing. This implementation does nothing. Subclasses implement this to get notice.
  1460. * Note that halt(true, true) might or might not have completed before this method is called.
  1461. */
  1462. protected void completing(long totalWritten, Throwable thrown) {
  1463. }
  1464. }
  1465. }