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

FileUtils.java 54 kB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429
  1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.util;
  18. import java.io.BufferedInputStream;
  19. import java.io.BufferedReader;
  20. import java.io.BufferedWriter;
  21. import java.io.File;
  22. import java.io.FileInputStream;
  23. import java.io.FileOutputStream;
  24. import java.io.FileReader;
  25. import java.io.FileWriter;
  26. import java.io.IOException;
  27. import java.io.InputStream;
  28. import java.io.InputStreamReader;
  29. import java.io.OutputStreamWriter;
  30. import java.io.Reader;
  31. import java.io.Writer;
  32. import java.io.OutputStream;
  33. import java.net.MalformedURLException;
  34. import java.net.URL;
  35. import java.text.CharacterIterator;
  36. import java.text.DecimalFormat;
  37. import java.text.StringCharacterIterator;
  38. import java.util.Random;
  39. import java.util.Stack;
  40. import java.util.StringTokenizer;
  41. import java.util.Vector;
  42. import org.apache.tools.ant.BuildException;
  43. import org.apache.tools.ant.Project;
  44. import org.apache.tools.ant.filters.util.ChainReaderHelper;
  45. import org.apache.tools.ant.taskdefs.condition.Os;
  46. import org.apache.tools.ant.types.FilterSetCollection;
  47. import org.apache.tools.ant.launch.Locator;
  48. /**
  49. * This class also encapsulates methods which allow Files to be
  50. * refered to using abstract path names which are translated to native
  51. * system file paths at runtime as well as copying files or setting
  52. * there last modification time.
  53. *
  54. * @version $Revision$
  55. */
  56. public class FileUtils {
  57. //get some non-crypto-grade randomness from various places.
  58. private static Random rand = new Random(System.currentTimeMillis()
  59. + Runtime.getRuntime().freeMemory());
  60. private boolean onNetWare = Os.isFamily("netware");
  61. // for toURI
  62. private static boolean[] isSpecial = new boolean[256];
  63. private static char[] escapedChar1 = new char[256];
  64. private static char[] escapedChar2 = new char[256];
  65. /**
  66. * the granularity of timestamps under FAT
  67. */
  68. public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000;
  69. /**
  70. * the granularity of timestamps under Unix
  71. */
  72. public static final long UNIX_FILE_TIMESTAMP_GRANULARITY = 1000;
  73. // stolen from FilePathToURI of the Xerces-J team
  74. static {
  75. for (int i = 0; i <= 0x20; i++) {
  76. isSpecial[i] = true;
  77. escapedChar1[i] = Character.forDigit(i >> 4, 16);
  78. escapedChar2[i] = Character.forDigit(i & 0xf, 16);
  79. }
  80. isSpecial[0x7f] = true;
  81. escapedChar1[0x7f] = '7';
  82. escapedChar2[0x7f] = 'F';
  83. char[] escChs = {'<', '>', '#', '%', '"', '{', '}',
  84. '|', '\\', '^', '~', '[', ']', '`'};
  85. int len = escChs.length;
  86. char ch;
  87. for (int i = 0; i < len; i++) {
  88. ch = escChs[i];
  89. isSpecial[ch] = true;
  90. escapedChar1[ch] = Character.forDigit(ch >> 4, 16);
  91. escapedChar2[ch] = Character.forDigit(ch & 0xf, 16);
  92. }
  93. }
  94. /**
  95. * Factory method.
  96. *
  97. * @return a new instance of FileUtils.
  98. */
  99. public static FileUtils newFileUtils() {
  100. return new FileUtils();
  101. }
  102. /**
  103. * Empty constructor.
  104. */
  105. protected FileUtils() {
  106. }
  107. /**
  108. * Get the URL for a file taking into account # characters
  109. *
  110. * @param file the file whose URL representation is required.
  111. * @return The FileURL value
  112. * @throws MalformedURLException if the URL representation cannot be
  113. * formed.
  114. */
  115. public URL getFileURL(File file) throws MalformedURLException {
  116. return new URL(toURI(file.getAbsolutePath()));
  117. }
  118. /**
  119. * Convienence method to copy a file from a source to a destination.
  120. * No filtering is performed.
  121. *
  122. * @param sourceFile Name of file to copy from.
  123. * Must not be <code>null</code>.
  124. * @param destFile Name of file to copy to.
  125. * Must not be <code>null</code>.
  126. *
  127. * @throws IOException if the copying fails
  128. */
  129. public void copyFile(String sourceFile, String destFile)
  130. throws IOException {
  131. copyFile(new File(sourceFile), new File(destFile), null, false, false);
  132. }
  133. /**
  134. * Convienence method to copy a file from a source to a destination
  135. * specifying if token filtering must be used.
  136. *
  137. * @param sourceFile Name of file to copy from.
  138. * Must not be <code>null</code>.
  139. * @param destFile Name of file to copy to.
  140. * Must not be <code>null</code>.
  141. * @param filters the collection of filters to apply to this copy
  142. *
  143. * @throws IOException if the copying fails
  144. */
  145. public void copyFile(String sourceFile, String destFile,
  146. FilterSetCollection filters)
  147. throws IOException {
  148. copyFile(new File(sourceFile), new File(destFile), filters,
  149. false, false);
  150. }
  151. /**
  152. * Convienence method to copy a file from a source to a
  153. * destination specifying if token filtering must be used and if
  154. * source files may overwrite newer destination files.
  155. *
  156. * @param sourceFile Name of file to copy from.
  157. * Must not be <code>null</code>.
  158. * @param destFile Name of file to copy to.
  159. * Must not be <code>null</code>.
  160. * @param filters the collection of filters to apply to this copy
  161. * @param overwrite Whether or not the destination file should be
  162. * overwritten if it already exists.
  163. *
  164. * @throws IOException if the copying fails
  165. */
  166. public void copyFile(String sourceFile, String destFile, FilterSetCollection filters,
  167. boolean overwrite) throws IOException {
  168. copyFile(new File(sourceFile), new File(destFile), filters,
  169. overwrite, false);
  170. }
  171. /**
  172. * Convienence method to copy a file from a source to a
  173. * destination specifying if token filtering must be used, if
  174. * source files may overwrite newer destination files and the
  175. * last modified time of <code>destFile</code> file should be made equal
  176. * to the last modified time of <code>sourceFile</code>.
  177. *
  178. * @param sourceFile Name of file to copy from.
  179. * Must not be <code>null</code>.
  180. * @param destFile Name of file to copy to.
  181. * Must not be <code>null</code>.
  182. * @param filters the collection of filters to apply to this copy
  183. * @param overwrite Whether or not the destination file should be
  184. * overwritten if it already exists.
  185. * @param preserveLastModified Whether or not the last modified time of
  186. * the resulting file should be set to that
  187. * of the source file.
  188. *
  189. * @throws IOException if the copying fails
  190. */
  191. public void copyFile(String sourceFile, String destFile, FilterSetCollection filters,
  192. boolean overwrite, boolean preserveLastModified)
  193. throws IOException {
  194. copyFile(new File(sourceFile), new File(destFile), filters,
  195. overwrite, preserveLastModified);
  196. }
  197. /**
  198. * Convienence method to copy a file from a source to a
  199. * destination specifying if token filtering must be used, if
  200. * source files may overwrite newer destination files and the
  201. * last modified time of <code>destFile</code> file should be made equal
  202. * to the last modified time of <code>sourceFile</code>.
  203. *
  204. * @param sourceFile Name of file to copy from.
  205. * Must not be <code>null</code>.
  206. * @param destFile Name of file to copy to.
  207. * Must not be <code>null</code>.
  208. * @param filters the collection of filters to apply to this copy
  209. * @param overwrite Whether or not the destination file should be
  210. * overwritten if it already exists.
  211. * @param preserveLastModified Whether or not the last modified time of
  212. * the resulting file should be set to that
  213. * of the source file.
  214. * @param encoding the encoding used to read and write the files.
  215. *
  216. * @throws IOException if the copying fails
  217. *
  218. * @since Ant 1.5
  219. */
  220. public void copyFile(String sourceFile, String destFile,
  221. FilterSetCollection filters, boolean overwrite,
  222. boolean preserveLastModified, String encoding)
  223. throws IOException {
  224. copyFile(new File(sourceFile), new File(destFile), filters,
  225. overwrite, preserveLastModified, encoding);
  226. }
  227. /**
  228. * Convienence method to copy a file from a source to a
  229. * destination specifying if token filtering must be used, if
  230. * filter chains must be used, if source files may overwrite
  231. * newer destination files and the last modified time of
  232. * <code>destFile</code> file should be made equal
  233. * to the last modified time of <code>sourceFile</code>.
  234. *
  235. * @param sourceFile Name of file to copy from.
  236. * Must not be <code>null</code>.
  237. * @param destFile Name of file to copy to.
  238. * Must not be <code>null</code>.
  239. * @param filters the collection of filters to apply to this copy
  240. * @param filterChains filterChains to apply during the copy.
  241. * @param overwrite Whether or not the destination file should be
  242. * overwritten if it already exists.
  243. * @param preserveLastModified Whether or not the last modified time of
  244. * the resulting file should be set to that
  245. * of the source file.
  246. * @param encoding the encoding used to read and write the files.
  247. * @param project the project instance
  248. *
  249. * @throws IOException if the copying fails
  250. *
  251. * @since Ant 1.5
  252. */
  253. public void copyFile(String sourceFile, String destFile,
  254. FilterSetCollection filters, Vector filterChains,
  255. boolean overwrite, boolean preserveLastModified,
  256. String encoding, Project project)
  257. throws IOException {
  258. copyFile(new File(sourceFile), new File(destFile), filters,
  259. filterChains, overwrite, preserveLastModified,
  260. encoding, project);
  261. }
  262. /**
  263. * Convienence method to copy a file from a source to a
  264. * destination specifying if token filtering must be used, if
  265. * filter chains must be used, if source files may overwrite
  266. * newer destination files and the last modified time of
  267. * <code>destFile</code> file should be made equal
  268. * to the last modified time of <code>sourceFile</code>.
  269. *
  270. * @param sourceFile Name of file to copy from.
  271. * Must not be <code>null</code>.
  272. * @param destFile Name of file to copy to.
  273. * Must not be <code>null</code>.
  274. * @param filters the collection of filters to apply to this copy
  275. * @param filterChains filterChains to apply during the copy.
  276. * @param overwrite Whether or not the destination file should be
  277. * overwritten if it already exists.
  278. * @param preserveLastModified Whether or not the last modified time of
  279. * the resulting file should be set to that
  280. * of the source file.
  281. * @param inputEncoding the encoding used to read the files.
  282. * @param outputEncoding the encoding used to write the files.
  283. * @param project the project instance
  284. *
  285. * @throws IOException if the copying fails
  286. *
  287. * @since Ant 1.6
  288. */
  289. public void copyFile(String sourceFile, String destFile,
  290. FilterSetCollection filters, Vector filterChains,
  291. boolean overwrite, boolean preserveLastModified,
  292. String inputEncoding, String outputEncoding,
  293. Project project)
  294. throws IOException {
  295. copyFile(new File(sourceFile), new File(destFile), filters,
  296. filterChains, overwrite, preserveLastModified,
  297. inputEncoding, outputEncoding, project);
  298. }
  299. /**
  300. * Convienence method to copy a file from a source to a destination.
  301. * No filtering is performed.
  302. *
  303. * @param sourceFile the file to copy from.
  304. * Must not be <code>null</code>.
  305. * @param destFile the file to copy to.
  306. * Must not be <code>null</code>.
  307. *
  308. * @throws IOException if the copying fails
  309. */
  310. public void copyFile(File sourceFile, File destFile) throws IOException {
  311. copyFile(sourceFile, destFile, null, false, false);
  312. }
  313. /**
  314. * Convienence method to copy a file from a source to a destination
  315. * specifying if token filtering must be used.
  316. *
  317. * @param sourceFile the file to copy from.
  318. * Must not be <code>null</code>.
  319. * @param destFile the file to copy to.
  320. * Must not be <code>null</code>.
  321. * @param filters the collection of filters to apply to this copy
  322. *
  323. * @throws IOException if the copying fails
  324. */
  325. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters)
  326. throws IOException {
  327. copyFile(sourceFile, destFile, filters, false, false);
  328. }
  329. /**
  330. * Convienence method to copy a file from a source to a
  331. * destination specifying if token filtering must be used and if
  332. * source files may overwrite newer destination files.
  333. *
  334. * @param sourceFile the file to copy from.
  335. * Must not be <code>null</code>.
  336. * @param destFile the file to copy to.
  337. * Must not be <code>null</code>.
  338. * @param filters the collection of filters to apply to this copy
  339. * @param overwrite Whether or not the destination file should be
  340. * overwritten if it already exists.
  341. *
  342. * @throws IOException if the copying fails
  343. */
  344. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
  345. boolean overwrite) throws IOException {
  346. copyFile(sourceFile, destFile, filters, overwrite, false);
  347. }
  348. /**
  349. * Convienence method to copy a file from a source to a
  350. * destination specifying if token filtering must be used, if
  351. * source files may overwrite newer destination files and the
  352. * last modified time of <code>destFile</code> file should be made equal
  353. * to the last modified time of <code>sourceFile</code>.
  354. *
  355. * @param sourceFile the file to copy from.
  356. * Must not be <code>null</code>.
  357. * @param destFile the file to copy to.
  358. * Must not be <code>null</code>.
  359. * @param filters the collection of filters to apply to this copy
  360. * @param overwrite Whether or not the destination file should be
  361. * overwritten if it already exists.
  362. * @param preserveLastModified Whether or not the last modified time of
  363. * the resulting file should be set to that
  364. * of the source file.
  365. *
  366. * @throws IOException if the copying fails
  367. */
  368. public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
  369. boolean overwrite, boolean preserveLastModified)
  370. throws IOException {
  371. copyFile(sourceFile, destFile, filters, overwrite,
  372. preserveLastModified, null);
  373. }
  374. /**
  375. * Convienence method to copy a file from a source to a
  376. * destination specifying if token filtering must be used, if
  377. * source files may overwrite newer destination files, the last
  378. * modified time of <code>destFile</code> file should be made
  379. * equal to the last modified time of <code>sourceFile</code> and
  380. * which character encoding to assume.
  381. *
  382. * @param sourceFile the file to copy from.
  383. * Must not be <code>null</code>.
  384. * @param destFile the file to copy to.
  385. * Must not be <code>null</code>.
  386. * @param filters the collection of filters to apply to this copy
  387. * @param overwrite Whether or not the destination file should be
  388. * overwritten if it already exists.
  389. * @param preserveLastModified Whether or not the last modified time of
  390. * the resulting file should be set to that
  391. * of the source file.
  392. * @param encoding the encoding used to read and write the files.
  393. *
  394. * @throws IOException if the copying fails
  395. *
  396. * @since Ant 1.5
  397. */
  398. public void copyFile(File sourceFile, File destFile,
  399. FilterSetCollection filters, boolean overwrite,
  400. boolean preserveLastModified, String encoding)
  401. throws IOException {
  402. copyFile(sourceFile, destFile, filters, null, overwrite,
  403. preserveLastModified, encoding, null);
  404. }
  405. /**
  406. * Convienence method to copy a file from a source to a
  407. * destination specifying if token filtering must be used, if
  408. * filter chains must be used, if source files may overwrite
  409. * newer destination files and the last modified time of
  410. * <code>destFile</code> file should be made equal
  411. * to the last modified time of <code>sourceFile</code>.
  412. *
  413. * @param sourceFile the file to copy from.
  414. * Must not be <code>null</code>.
  415. * @param destFile the file to copy to.
  416. * Must not be <code>null</code>.
  417. * @param filters the collection of filters to apply to this copy
  418. * @param filterChains filterChains to apply during the copy.
  419. * @param overwrite Whether or not the destination file should be
  420. * overwritten if it already exists.
  421. * @param preserveLastModified Whether or not the last modified time of
  422. * the resulting file should be set to that
  423. * of the source file.
  424. * @param encoding the encoding used to read and write the files.
  425. * @param project the project instance
  426. *
  427. * @throws IOException if the copying fails
  428. *
  429. * @since Ant 1.5
  430. */
  431. public void copyFile(File sourceFile, File destFile,
  432. FilterSetCollection filters, Vector filterChains,
  433. boolean overwrite, boolean preserveLastModified,
  434. String encoding, Project project)
  435. throws IOException {
  436. copyFile(sourceFile, destFile, filters, filterChains,
  437. overwrite, preserveLastModified, encoding, encoding, project);
  438. }
  439. /**
  440. * Convienence method to copy a file from a source to a
  441. * destination specifying if token filtering must be used, if
  442. * filter chains must be used, if source files may overwrite
  443. * newer destination files and the last modified time of
  444. * <code>destFile</code> file should be made equal
  445. * to the last modified time of <code>sourceFile</code>.
  446. *
  447. * @param sourceFile the file to copy from.
  448. * Must not be <code>null</code>.
  449. * @param destFile the file to copy to.
  450. * Must not be <code>null</code>.
  451. * @param filters the collection of filters to apply to this copy
  452. * @param filterChains filterChains to apply during the copy.
  453. * @param overwrite Whether or not the destination file should be
  454. * overwritten if it already exists.
  455. * @param preserveLastModified Whether or not the last modified time of
  456. * the resulting file should be set to that
  457. * of the source file.
  458. * @param inputEncoding the encoding used to read the files.
  459. * @param outputEncoding the encoding used to write the files.
  460. * @param project the project instance
  461. *
  462. *
  463. * @throws IOException if the copying fails
  464. *
  465. * @since Ant 1.6
  466. */
  467. public void copyFile(File sourceFile, File destFile,
  468. FilterSetCollection filters, Vector filterChains,
  469. boolean overwrite, boolean preserveLastModified,
  470. String inputEncoding, String outputEncoding,
  471. Project project)
  472. throws IOException {
  473. if (overwrite || !destFile.exists()
  474. || destFile.lastModified() < sourceFile.lastModified()) {
  475. if (destFile.exists() && destFile.isFile()) {
  476. destFile.delete();
  477. }
  478. // ensure that parent dir of dest file exists!
  479. // not using getParentFile method to stay 1.1 compat
  480. File parent = getParentFile(destFile);
  481. if (parent != null && !parent.exists()) {
  482. parent.mkdirs();
  483. }
  484. final boolean filterSetsAvailable = (filters != null
  485. && filters.hasFilters());
  486. final boolean filterChainsAvailable = (filterChains != null
  487. && filterChains.size() > 0);
  488. if (filterSetsAvailable) {
  489. BufferedReader in = null;
  490. BufferedWriter out = null;
  491. try {
  492. if (inputEncoding == null) {
  493. in = new BufferedReader(new FileReader(sourceFile));
  494. } else {
  495. InputStreamReader isr
  496. = new InputStreamReader(new FileInputStream(sourceFile),
  497. inputEncoding);
  498. in = new BufferedReader(isr);
  499. }
  500. if (outputEncoding == null) {
  501. out = new BufferedWriter(new FileWriter(destFile));
  502. } else {
  503. OutputStreamWriter osw
  504. = new OutputStreamWriter(new FileOutputStream(destFile),
  505. outputEncoding);
  506. out = new BufferedWriter(osw);
  507. }
  508. if (filterChainsAvailable) {
  509. ChainReaderHelper crh = new ChainReaderHelper();
  510. crh.setBufferSize(8192);
  511. crh.setPrimaryReader(in);
  512. crh.setFilterChains(filterChains);
  513. crh.setProject(project);
  514. Reader rdr = crh.getAssembledReader();
  515. in = new BufferedReader(rdr);
  516. }
  517. LineTokenizer lineTokenizer = new LineTokenizer();
  518. lineTokenizer.setIncludeDelims(true);
  519. String newline = null;
  520. String line = lineTokenizer.getToken(in);
  521. while (line != null) {
  522. if (line.length() == 0) {
  523. // this should not happen, because the lines are
  524. // returned with the end of line delimiter
  525. out.newLine();
  526. } else {
  527. newline = filters.replaceTokens(line);
  528. out.write(newline);
  529. }
  530. line = lineTokenizer.getToken(in);
  531. }
  532. } finally {
  533. close(out);
  534. close(in);
  535. }
  536. } else if (filterChainsAvailable
  537. || (inputEncoding != null
  538. && !inputEncoding.equals(outputEncoding))
  539. || (inputEncoding == null && outputEncoding != null)) {
  540. BufferedReader in = null;
  541. BufferedWriter out = null;
  542. try {
  543. if (inputEncoding == null) {
  544. in = new BufferedReader(new FileReader(sourceFile));
  545. } else {
  546. in =
  547. new BufferedReader(
  548. new InputStreamReader(
  549. new FileInputStream(sourceFile),
  550. inputEncoding));
  551. }
  552. if (outputEncoding == null) {
  553. out = new BufferedWriter(new FileWriter(destFile));
  554. } else {
  555. out =
  556. new BufferedWriter(
  557. new OutputStreamWriter(
  558. new FileOutputStream(destFile),
  559. outputEncoding));
  560. }
  561. if (filterChainsAvailable) {
  562. ChainReaderHelper crh = new ChainReaderHelper();
  563. crh.setBufferSize(8192);
  564. crh.setPrimaryReader(in);
  565. crh.setFilterChains(filterChains);
  566. crh.setProject(project);
  567. Reader rdr = crh.getAssembledReader();
  568. in = new BufferedReader(rdr);
  569. }
  570. char[] buffer = new char[1024 * 8];
  571. while (true) {
  572. int nRead = in.read(buffer, 0, buffer.length);
  573. if (nRead == -1) {
  574. break;
  575. }
  576. out.write(buffer, 0, nRead);
  577. }
  578. } finally {
  579. close(out);
  580. close(in);
  581. }
  582. } else {
  583. FileInputStream in = null;
  584. FileOutputStream out = null;
  585. try {
  586. in = new FileInputStream(sourceFile);
  587. out = new FileOutputStream(destFile);
  588. byte[] buffer = new byte[8 * 1024];
  589. int count = 0;
  590. do {
  591. out.write(buffer, 0, count);
  592. count = in.read(buffer, 0, buffer.length);
  593. } while (count != -1);
  594. } finally {
  595. close(out);
  596. close(in);
  597. }
  598. }
  599. if (preserveLastModified) {
  600. destFile.setLastModified(sourceFile.lastModified());
  601. }
  602. }
  603. }
  604. /**
  605. * Calls File.setLastModified(long time). Originally written to
  606. * to dynamically bind to that call on Java1.2+.
  607. *
  608. * @param file the file whose modified time is to be set
  609. * @param time the time to which the last modified time is to be set.
  610. * if this is -1, the current time is used.
  611. * @throws BuildException if the time cannot be set.
  612. */
  613. public void setFileLastModified(File file, long time)
  614. throws BuildException {
  615. if (time < 0) {
  616. time = System.currentTimeMillis();
  617. }
  618. file.setLastModified(time);
  619. }
  620. /**
  621. * Interpret the filename as a file relative to the given file -
  622. * unless the filename already represents an absolute filename.
  623. *
  624. * @param file the "reference" file for relative paths. This
  625. * instance must be an absolute file and must not contain
  626. * &quot;./&quot; or &quot;../&quot; sequences (same for \ instead
  627. * of /). If it is null, this call is equivalent to
  628. * <code>new java.io.File(filename)</code>.
  629. *
  630. * @param filename a file name
  631. *
  632. * @return an absolute file that doesn't contain &quot;./&quot; or
  633. * &quot;../&quot; sequences and uses the correct separator for
  634. * the current platform.
  635. */
  636. public File resolveFile(File file, String filename) {
  637. filename = filename.replace('/', File.separatorChar)
  638. .replace('\\', File.separatorChar);
  639. // deal with absolute files
  640. if (!onNetWare) {
  641. if (filename.startsWith(File.separator)
  642. || (filename.length() >= 2
  643. && Character.isLetter(filename.charAt(0))
  644. && filename.charAt(1) == ':')) {
  645. return normalize(filename);
  646. }
  647. } else {
  648. // the assumption that the : will appear as the second character in
  649. // the path name breaks down when NetWare is a supported platform.
  650. // Netware volumes are of the pattern: "data:\"
  651. int colon = filename.indexOf(":");
  652. if (filename.startsWith(File.separator)
  653. || (colon > -1)) {
  654. return normalize(filename);
  655. }
  656. }
  657. if (file == null) {
  658. return new File(filename);
  659. }
  660. File helpFile = new File(file.getAbsolutePath());
  661. StringTokenizer tok = new StringTokenizer(filename, File.separator);
  662. while (tok.hasMoreTokens()) {
  663. String part = tok.nextToken();
  664. if (part.equals("..")) {
  665. helpFile = getParentFile(helpFile);
  666. if (helpFile == null) {
  667. String msg = "The file or path you specified ("
  668. + filename + ") is invalid relative to "
  669. + file.getPath();
  670. throw new BuildException(msg);
  671. }
  672. } else if (part.equals(".")) {
  673. // Do nothing here
  674. } else {
  675. helpFile = new File(helpFile, part);
  676. }
  677. }
  678. return new File(helpFile.getAbsolutePath());
  679. }
  680. /**
  681. * &quot;normalize&quot; the given absolute path.
  682. *
  683. * <p>This includes:
  684. * <ul>
  685. * <li>Uppercase the drive letter if there is one.</li>
  686. * <li>Remove redundant slashes after the drive spec.</li>
  687. * <li>resolve all ./, .\, ../ and ..\ sequences.</li>
  688. * <li>DOS style paths that start with a drive letter will have
  689. * \ as the separator.</li>
  690. * </ul>
  691. * Unlike <code>File#getCanonicalPath()</code> it specifically doesn't
  692. * resolve symbolic links.
  693. *
  694. * @param path the path to be normalized
  695. * @return the normalized version of the path.
  696. *
  697. * @throws java.lang.NullPointerException if the file path is
  698. * equal to null.
  699. */
  700. public File normalize(String path) {
  701. String orig = path;
  702. path = path.replace('/', File.separatorChar)
  703. .replace('\\', File.separatorChar);
  704. // make sure we are dealing with an absolute path
  705. int colon = path.indexOf(":");
  706. if (!onNetWare) {
  707. if (!path.startsWith(File.separator)
  708. && !(path.length() >= 2
  709. && Character.isLetter(path.charAt(0))
  710. && colon == 1)) {
  711. String msg = path + " is not an absolute path";
  712. throw new BuildException(msg);
  713. }
  714. } else {
  715. if (!path.startsWith(File.separator)
  716. && (colon == -1)) {
  717. String msg = path + " is not an absolute path";
  718. throw new BuildException(msg);
  719. }
  720. }
  721. boolean dosWithDrive = false;
  722. String root = null;
  723. // Eliminate consecutive slashes after the drive spec
  724. if ((!onNetWare && path.length() >= 2
  725. && Character.isLetter(path.charAt(0))
  726. && path.charAt(1) == ':')
  727. || (onNetWare && colon > -1)) {
  728. dosWithDrive = true;
  729. char[] ca = path.replace('/', '\\').toCharArray();
  730. StringBuffer sbRoot = new StringBuffer();
  731. for (int i = 0; i < colon; i++) {
  732. sbRoot.append(Character.toUpperCase(ca[i]));
  733. }
  734. sbRoot.append(':');
  735. if (colon + 1 < path.length()) {
  736. sbRoot.append(File.separatorChar);
  737. }
  738. root = sbRoot.toString();
  739. // Eliminate consecutive slashes after the drive spec
  740. StringBuffer sbPath = new StringBuffer();
  741. for (int i = colon + 1; i < ca.length; i++) {
  742. if ((ca[i] != '\\')
  743. || (ca[i] == '\\' && ca[i - 1] != '\\')) {
  744. sbPath.append(ca[i]);
  745. }
  746. }
  747. path = sbPath.toString().replace('\\', File.separatorChar);
  748. } else {
  749. if (path.length() == 1) {
  750. root = File.separator;
  751. path = "";
  752. } else if (path.charAt(1) == File.separatorChar) {
  753. // UNC drive
  754. root = File.separator + File.separator;
  755. path = path.substring(2);
  756. } else {
  757. root = File.separator;
  758. path = path.substring(1);
  759. }
  760. }
  761. Stack s = new Stack();
  762. s.push(root);
  763. StringTokenizer tok = new StringTokenizer(path, File.separator);
  764. while (tok.hasMoreTokens()) {
  765. String thisToken = tok.nextToken();
  766. if (".".equals(thisToken)) {
  767. continue;
  768. } else if ("..".equals(thisToken)) {
  769. if (s.size() < 2) {
  770. throw new BuildException("Cannot resolve path " + orig);
  771. } else {
  772. s.pop();
  773. }
  774. } else { // plain component
  775. s.push(thisToken);
  776. }
  777. }
  778. StringBuffer sb = new StringBuffer();
  779. for (int i = 0; i < s.size(); i++) {
  780. if (i > 1) {
  781. // not before the filesystem root and not after it, since root
  782. // already contains one
  783. sb.append(File.separatorChar);
  784. }
  785. sb.append(s.elementAt(i));
  786. }
  787. path = sb.toString();
  788. if (dosWithDrive) {
  789. path = path.replace('/', '\\');
  790. }
  791. return new File(path);
  792. }
  793. /**
  794. * Returns a VMS String representation of a <code>File</code> object.
  795. * This is useful since the JVM by default internally converts VMS paths
  796. * to Unix style.
  797. * The returned String is always an absolute path.
  798. *
  799. * @param f The <code>File</code> to get the VMS path for.
  800. * @return The absolute VMS path to <code>f</code>.
  801. */
  802. public String toVMSPath(File f) {
  803. // format: "DEVICE:[DIR.SUBDIR]FILE"
  804. String osPath;
  805. String path = normalize(f.getAbsolutePath()).getPath();
  806. String name = f.getName();
  807. boolean isAbsolute = path.charAt(0) == File.separatorChar;
  808. // treat directories specified using .DIR syntax as files
  809. boolean isDirectory = f.isDirectory()
  810. && !name.regionMatches(true, name.length() - 4, ".DIR", 0, 4);
  811. String device = null;
  812. StringBuffer directory = null;
  813. String file = null;
  814. int index = 0;
  815. if (isAbsolute) {
  816. index = path.indexOf(File.separatorChar, 1);
  817. if (index == -1) {
  818. return path.substring(1) + ":[000000]";
  819. } else {
  820. device = path.substring(1, index++);
  821. }
  822. }
  823. if (isDirectory) {
  824. directory = new StringBuffer(path.substring(index).
  825. replace(File.separatorChar, '.'));
  826. } else {
  827. int dirEnd =
  828. path.lastIndexOf(File.separatorChar, path.length());
  829. if (dirEnd == -1 || dirEnd < index) {
  830. file = path.substring(index);
  831. } else {
  832. directory = new StringBuffer(path.substring(index, dirEnd).
  833. replace(File.separatorChar, '.'));
  834. index = dirEnd + 1;
  835. if (path.length() > index) {
  836. file = path.substring(index);
  837. }
  838. }
  839. }
  840. if (!isAbsolute && directory != null) {
  841. directory.insert(0, '.');
  842. }
  843. osPath = ((device != null) ? device + ":" : "")
  844. + ((directory != null) ? "[" + directory + "]" : "")
  845. + ((file != null) ? file : "");
  846. return osPath;
  847. }
  848. /**
  849. * Create a temporary file in a given directory.
  850. *
  851. * <p>The file denoted by the returned abstract pathname did not
  852. * exist before this method was invoked, any subsequent invocation
  853. * of this method will yield a different file name.</p>
  854. * <p>
  855. * The filename is prefixNNNNNsuffix where NNNN is a random number
  856. * </p>
  857. * <p>This method is different to File.createTempFile of JDK 1.2
  858. * as it doesn't create the file itself.
  859. * It uses the location pointed to by java.io.tmpdir
  860. * when the parentDir attribute is
  861. * null.</p>
  862. *
  863. * @param prefix prefix before the random number
  864. * @param suffix file extension; include the '.'
  865. * @param parentDir Directory to create the temporary file in -
  866. * java.io.tmpdir used if not specificed
  867. *
  868. * @return a File reference to the new temporary file.
  869. * @since ant 1.5
  870. */
  871. public File createTempFile(String prefix, String suffix, File parentDir) {
  872. File result = null;
  873. String parent = System.getProperty("java.io.tmpdir");
  874. if (parentDir != null) {
  875. parent = parentDir.getPath();
  876. }
  877. DecimalFormat fmt = new DecimalFormat("#####");
  878. synchronized (rand) {
  879. do {
  880. result = new File(parent,
  881. prefix + fmt.format(Math.abs(rand.nextInt()))
  882. + suffix);
  883. } while (result.exists());
  884. }
  885. return result;
  886. }
  887. /**
  888. * Compares the contents of two files.
  889. *
  890. * <p>simple but sub-optimal comparision algorithm. written for
  891. * working rather than fast. Better would be a block read into
  892. * buffers followed by long comparisions apart from the final 1-7
  893. * bytes.</p>
  894. *
  895. * @param f1 the file whose content is to be compared.
  896. * @param f2 the other file whose content is to be compared.
  897. *
  898. * @return true if the content of the files is the same.
  899. *
  900. * @throws IOException if the files cannot be read.
  901. *
  902. * @since 1.9
  903. */
  904. public boolean contentEquals(File f1, File f2) throws IOException {
  905. if (f1.exists() != f2.exists()) {
  906. return false;
  907. }
  908. if (!f1.exists()) {
  909. // two not existing files are equal
  910. return true;
  911. }
  912. if (f1.isDirectory() || f2.isDirectory()) {
  913. // don't want to compare directory contents for now
  914. return false;
  915. }
  916. if (fileNameEquals(f1, f2)) {
  917. // same filename => true
  918. return true;
  919. }
  920. if (f1.length() != f2.length()) {
  921. // different size =>false
  922. return false;
  923. }
  924. InputStream in1 = null;
  925. InputStream in2 = null;
  926. try {
  927. in1 = new BufferedInputStream(new FileInputStream(f1));
  928. in2 = new BufferedInputStream(new FileInputStream(f2));
  929. int expectedByte = in1.read();
  930. while (expectedByte != -1) {
  931. if (expectedByte != in2.read()) {
  932. return false;
  933. }
  934. expectedByte = in1.read();
  935. }
  936. if (in2.read() != -1) {
  937. return false;
  938. }
  939. return true;
  940. } finally {
  941. if (in1 != null) {
  942. try {
  943. in1.close();
  944. } catch (IOException e) {
  945. // ignore
  946. }
  947. }
  948. if (in2 != null) {
  949. try {
  950. in2.close();
  951. } catch (IOException e) {
  952. // ignore
  953. }
  954. }
  955. }
  956. }
  957. /**
  958. * This was originally an emulation of {@link File#getParentFile} for JDK 1.1,
  959. * but it is now implemented using that method (Ant 1.7 onwards).
  960. * @param f the file whose parent is required.
  961. * @return the given file's parent, or null if the file does not have a
  962. * parent.
  963. * @since 1.10
  964. * @deprecated Just use {@link File#getParentFile} directly.
  965. */
  966. public File getParentFile(File f) {
  967. return (f == null) ? null : f.getParentFile();
  968. }
  969. /**
  970. * Read from reader till EOF
  971. * @param rdr the reader from which to read.
  972. * @return the contents read out of the given reader
  973. *
  974. * @throws IOException if the contents could not be read out from the
  975. * reader.
  976. */
  977. public static final String readFully(Reader rdr) throws IOException {
  978. return readFully(rdr, 8192);
  979. }
  980. /**
  981. * Read from reader till EOF
  982. *
  983. * @param rdr the reader from which to read.
  984. * @param bufferSize the buffer size to use when reading
  985. *
  986. * @return the contents read out of the given reader
  987. *
  988. * @throws IOException if the contents could not be read out from the
  989. * reader.
  990. */
  991. public static final String readFully(Reader rdr, int bufferSize)
  992. throws IOException {
  993. if (bufferSize <= 0) {
  994. throw new IllegalArgumentException("Buffer size must be greater "
  995. + "than 0");
  996. }
  997. final char[] buffer = new char[bufferSize];
  998. int bufferLength = 0;
  999. StringBuffer textBuffer = null;
  1000. while (bufferLength != -1) {
  1001. bufferLength = rdr.read(buffer);
  1002. if (bufferLength > 0) {
  1003. textBuffer = (textBuffer == null) ? new StringBuffer() : textBuffer;
  1004. textBuffer.append(new String(buffer, 0, bufferLength));
  1005. }
  1006. }
  1007. return (textBuffer == null) ? null : textBuffer.toString();
  1008. }
  1009. /**
  1010. * This was originally an emulation of File.createNewFile for JDK 1.1,
  1011. * but it is now implemented using that method (Ant1.7 onwards).
  1012. *
  1013. * <p>This method has historically <strong>not</strong> guaranteed that the
  1014. * operation was atomic. In its current implementation it is.
  1015. *
  1016. * @param f the file to be created
  1017. * @return true if the file did not exist already.
  1018. * @throws IOException on error
  1019. * @since Ant 1.5
  1020. */
  1021. public boolean createNewFile(File f) throws IOException {
  1022. return f.createNewFile();
  1023. }
  1024. /**
  1025. * Checks whether a given file is a symbolic link.
  1026. *
  1027. * <p>It doesn't really test for symbolic links but whether the
  1028. * canonical and absolute paths of the file are identical - this
  1029. * may lead to false positives on some platforms.</p>
  1030. *
  1031. * @param parent the parent directory of the file to test
  1032. * @param name the name of the file to test.
  1033. *
  1034. * @return true if the file is a symbolic link.
  1035. * @throws IOException on error
  1036. * @since Ant 1.5
  1037. */
  1038. public boolean isSymbolicLink(File parent, String name)
  1039. throws IOException {
  1040. File resolvedParent = new File(parent.getCanonicalPath());
  1041. File toTest = new File(resolvedParent, name);
  1042. return !toTest.getAbsolutePath().equals(toTest.getCanonicalPath());
  1043. }
  1044. /**
  1045. * Removes a leading path from a second path.
  1046. *
  1047. * @param leading The leading path, must not be null, must be absolute.
  1048. * @param path The path to remove from, must not be null, must be absolute.
  1049. *
  1050. * @return path's normalized absolute if it doesn't start with
  1051. * leading, path's path with leading's path removed otherwise.
  1052. *
  1053. * @since Ant 1.5
  1054. */
  1055. public String removeLeadingPath(File leading, File path) {
  1056. String l = normalize(leading.getAbsolutePath()).getAbsolutePath();
  1057. String p = normalize(path.getAbsolutePath()).getAbsolutePath();
  1058. if (l.equals(p)) {
  1059. return "";
  1060. }
  1061. // ensure that l ends with a /
  1062. // so we never think /foo was a parent directory of /foobar
  1063. if (!l.endsWith(File.separator)) {
  1064. l += File.separator;
  1065. }
  1066. return (p.startsWith(l)) ? p.substring(l.length()) : p;
  1067. }
  1068. /**
  1069. * Constructs a <code>file:</code> URI that represents the
  1070. * external form of the given pathname.
  1071. *
  1072. * <p>Will be an absolute URI if the given path is absolute.</p>
  1073. *
  1074. * <p>This code doesn't handle non-ASCII characters properly.</p>
  1075. *
  1076. * @param path the path in the local file system
  1077. * @return the URI version of the local path.
  1078. * @since Ant 1.6
  1079. */
  1080. public String toURI(String path) {
  1081. boolean isDir = (new File(path)).isDirectory();
  1082. StringBuffer sb = new StringBuffer("file:");
  1083. // catch exception if normalize thinks this is not an absolute path
  1084. try {
  1085. path = normalize(path).getAbsolutePath();
  1086. sb.append("//");
  1087. // add an extra slash for filesystems with drive-specifiers
  1088. if (!path.startsWith(File.separator)) {
  1089. sb.append("/");
  1090. }
  1091. } catch (BuildException e) {
  1092. // relative path
  1093. }
  1094. path = path.replace('\\', '/');
  1095. CharacterIterator iter = new StringCharacterIterator(path);
  1096. for (char c = iter.first(); c != CharacterIterator.DONE;
  1097. c = iter.next()) {
  1098. if (c < 256 && isSpecial[c]) {
  1099. sb.append('%');
  1100. sb.append(escapedChar1[c]);
  1101. sb.append(escapedChar2[c]);
  1102. } else {
  1103. sb.append(c);
  1104. }
  1105. }
  1106. if (isDir && !path.endsWith("/")) {
  1107. sb.append('/');
  1108. }
  1109. return sb.toString();
  1110. }
  1111. /**
  1112. * Constructs a file path from a <code>file:</code> URI.
  1113. *
  1114. * <p>Will be an absolute path if the given URI is absolute.</p>
  1115. *
  1116. * <p>Swallows '%' that are not followed by two characters,
  1117. * doesn't deal with non-ASCII characters.</p>
  1118. *
  1119. * @param uri the URI designating a file in the local filesystem.
  1120. * @return the local file system path for the file.
  1121. * @since Ant 1.6
  1122. */
  1123. public String fromURI(String uri) {
  1124. String path = Locator.fromURI(uri);
  1125. // catch exception if normalize thinks this is not an absolute path
  1126. try {
  1127. path = normalize(path).getAbsolutePath();
  1128. } catch (BuildException e) {
  1129. // relative path
  1130. }
  1131. return path;
  1132. }
  1133. /**
  1134. * Compares two filenames.
  1135. *
  1136. * <p>Unlike java.io.File#equals this method will try to compare
  1137. * the absolute paths and &quot;normalize&quot; the filenames
  1138. * before comparing them.</p>
  1139. *
  1140. * @param f1 the file whose name is to be compared.
  1141. * @param f2 the other file whose name is to be compared.
  1142. *
  1143. * @return true if the file are for the same file.
  1144. *
  1145. * @since Ant 1.5.3
  1146. */
  1147. public boolean fileNameEquals(File f1, File f2) {
  1148. return normalize(f1.getAbsolutePath())
  1149. .equals(normalize(f2.getAbsolutePath()));
  1150. }
  1151. /**
  1152. * Renames a file, even if that involves crossing file system boundaries.
  1153. *
  1154. * <p>This will remove <code>to</code> (if it exists), ensure that
  1155. * <code>to</code>'s parent directory exists and move
  1156. * <code>from</code>, which involves deleting <code>from</code> as
  1157. * well.</p>
  1158. *
  1159. * @throws IOException if anything bad happens during this
  1160. * process. Note that <code>to</code> may have been deleted
  1161. * already when this happens.
  1162. *
  1163. * @param from the file to move
  1164. * @param to the new file name
  1165. *
  1166. * @since Ant 1.6
  1167. */
  1168. public void rename(File from, File to) throws IOException {
  1169. if (to.exists() && !to.delete()) {
  1170. throw new IOException("Failed to delete " + to
  1171. + " while trying to rename " + from);
  1172. }
  1173. File parent = getParentFile(to);
  1174. if (parent != null && !parent.exists() && !parent.mkdirs()) {
  1175. throw new IOException("Failed to create directory " + parent
  1176. + " while trying to rename " + from);
  1177. }
  1178. if (!from.renameTo(to)) {
  1179. copyFile(from, to);
  1180. if (!from.delete()) {
  1181. throw new IOException("Failed to delete " + from
  1182. + " while trying to rename it.");
  1183. }
  1184. }
  1185. }
  1186. /**
  1187. * get the granularity of file timestamps.
  1188. * The choice is made on OS, which is incorrect -it should really be
  1189. * by filesystem. We do not have an easy way to probe for file systems,
  1190. * however.
  1191. * @return the difference, in milliseconds, which two file timestamps must have
  1192. * in order for the two files to be given a creation order.
  1193. */
  1194. public long getFileTimestampGranularity() {
  1195. if (Os.isFamily("dos")) {
  1196. return FAT_FILE_TIMESTAMP_GRANULARITY;
  1197. } else {
  1198. return UNIX_FILE_TIMESTAMP_GRANULARITY;
  1199. }
  1200. }
  1201. /**
  1202. * Returns true if the source is older than the dest.
  1203. * If the dest file does not exist, then the test returns false; it is
  1204. * implicitly not up do date.
  1205. * @param source source file (should be the older)
  1206. * @param dest dest file (should be the newer)
  1207. * @param granularity an offset added to the source time.
  1208. * @return true if the source is older than the dest, taking the
  1209. * granularity into account
  1210. * @since Ant1.7
  1211. */
  1212. public boolean isUpToDate(File source, File dest, long granularity) {
  1213. //do a check for the destination file existing
  1214. if (!dest.exists()) {
  1215. //if it does not, then the file is not up to date.
  1216. return false;
  1217. }
  1218. long sourceTime = source.lastModified();
  1219. long destTime = dest.lastModified();
  1220. return isUpToDate(sourceTime, destTime, granularity);
  1221. }
  1222. /**
  1223. * returns true if the source is older than the dest
  1224. * @param source source file (should be the older)
  1225. * @param dest dest file (should be the newer)
  1226. * @return true if the source is older than the dest, taking the granularity into account
  1227. * @since Ant1.7
  1228. */
  1229. public boolean isUpToDate(File source, File dest) {
  1230. return isUpToDate(source, dest, getFileTimestampGranularity());
  1231. }
  1232. /**
  1233. * compare two timestamps for being up to date, use granularity too.,
  1234. *
  1235. * @param sourceTime timestamp of source file
  1236. * @param destTime timestamp of dest file
  1237. * @param granularity os/filesys granularity
  1238. * @return true if the dest file is considered up to date
  1239. */
  1240. public boolean isUpToDate(long sourceTime, long destTime, long granularity) {
  1241. if (destTime == -1) {
  1242. return false;
  1243. }
  1244. return destTime >= sourceTime + granularity;
  1245. }
  1246. /**
  1247. * compare two timestamps for being up to date, use the
  1248. * current granularity
  1249. *
  1250. * @param sourceTime timestamp of source file
  1251. * @param destTime timestamp of dest file
  1252. * @return true if the dest file is considered up to date
  1253. */
  1254. public boolean isUpToDate(long sourceTime, long destTime) {
  1255. return isUpToDate(sourceTime, destTime, getFileTimestampGranularity());
  1256. }
  1257. /**
  1258. * close a writer without throwing any exception if something went wrong.
  1259. * Do not attempt to close it if the file is null
  1260. * @param device output writer, can be null
  1261. */
  1262. public static void close(Writer device) {
  1263. if (device != null) {
  1264. try {
  1265. device.close();
  1266. } catch (IOException ioex) {
  1267. //ignore
  1268. }
  1269. }
  1270. }
  1271. /**
  1272. * close a stream without throwing any exception if something went wrong.
  1273. * Do not attempt to close it if the file is null
  1274. *
  1275. * @param device stream, can be null
  1276. */
  1277. public static void close(Reader device) {
  1278. if (device != null) {
  1279. try {
  1280. device.close();
  1281. } catch (IOException ioex) {
  1282. //ignore
  1283. }
  1284. }
  1285. }
  1286. /**
  1287. * close a stream without throwing any exception if something went wrong.
  1288. * Do not attempt to close it if the file is null
  1289. *
  1290. * @param device stream, can be null
  1291. */
  1292. public static void close(OutputStream device) {
  1293. if (device != null) {
  1294. try {
  1295. device.close();
  1296. } catch (IOException ioex) {
  1297. //ignore
  1298. }
  1299. }
  1300. }
  1301. /**
  1302. * close a stream without throwing any exception if something went wrong.
  1303. * Do not attempt to close it if the file is null
  1304. *
  1305. * @param device stream, can be null
  1306. */
  1307. public static void close(InputStream device) {
  1308. if (device != null) {
  1309. try {
  1310. device.close();
  1311. } catch (IOException ioex) {
  1312. //ignore
  1313. }
  1314. }
  1315. }
  1316. /**
  1317. * Delete the file with {@link File#delete()} if the argument is not null.
  1318. * Do nothing on a null argument
  1319. * @param file file to delete
  1320. */
  1321. public static void delete(File file) {
  1322. if (file != null) {
  1323. file.delete();
  1324. }
  1325. }
  1326. }