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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428
  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 File.getParentFile for JDK 1.1,
  959. * but it is now implemented using that method (Ant1.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. */
  965. public File getParentFile(File f) {
  966. return (f == null) ? null : f.getParentFile();
  967. }
  968. /**
  969. * Read from reader till EOF
  970. * @param rdr the reader from which to read.
  971. * @return the contents read out of the given reader
  972. *
  973. * @throws IOException if the contents could not be read out from the
  974. * reader.
  975. */
  976. public static final String readFully(Reader rdr) throws IOException {
  977. return readFully(rdr, 8192);
  978. }
  979. /**
  980. * Read from reader till EOF
  981. *
  982. * @param rdr the reader from which to read.
  983. * @param bufferSize the buffer size to use when reading
  984. *
  985. * @return the contents read out of the given reader
  986. *
  987. * @throws IOException if the contents could not be read out from the
  988. * reader.
  989. */
  990. public static final String readFully(Reader rdr, int bufferSize)
  991. throws IOException {
  992. if (bufferSize <= 0) {
  993. throw new IllegalArgumentException("Buffer size must be greater "
  994. + "than 0");
  995. }
  996. final char[] buffer = new char[bufferSize];
  997. int bufferLength = 0;
  998. StringBuffer textBuffer = null;
  999. while (bufferLength != -1) {
  1000. bufferLength = rdr.read(buffer);
  1001. if (bufferLength > 0) {
  1002. textBuffer = (textBuffer == null) ? new StringBuffer() : textBuffer;
  1003. textBuffer.append(new String(buffer, 0, bufferLength));
  1004. }
  1005. }
  1006. return (textBuffer == null) ? null : textBuffer.toString();
  1007. }
  1008. /**
  1009. * This was originally an emulation of File.createNewFile for JDK 1.1,
  1010. * but it is now implemented using that method (Ant1.7 onwards).
  1011. *
  1012. * <p>This method has historically <strong>not</strong> guaranteed that the
  1013. * operation was atomic. In its current implementation it is.
  1014. *
  1015. * @param f the file to be created
  1016. * @return true if the file did not exist already.
  1017. * @throws IOException on error
  1018. * @since Ant 1.5
  1019. */
  1020. public boolean createNewFile(File f) throws IOException {
  1021. return f.createNewFile();
  1022. }
  1023. /**
  1024. * Checks whether a given file is a symbolic link.
  1025. *
  1026. * <p>It doesn't really test for symbolic links but whether the
  1027. * canonical and absolute paths of the file are identical - this
  1028. * may lead to false positives on some platforms.</p>
  1029. *
  1030. * @param parent the parent directory of the file to test
  1031. * @param name the name of the file to test.
  1032. *
  1033. * @return true if the file is a symbolic link.
  1034. * @throws IOException on error
  1035. * @since Ant 1.5
  1036. */
  1037. public boolean isSymbolicLink(File parent, String name)
  1038. throws IOException {
  1039. File resolvedParent = new File(parent.getCanonicalPath());
  1040. File toTest = new File(resolvedParent, name);
  1041. return !toTest.getAbsolutePath().equals(toTest.getCanonicalPath());
  1042. }
  1043. /**
  1044. * Removes a leading path from a second path.
  1045. *
  1046. * @param leading The leading path, must not be null, must be absolute.
  1047. * @param path The path to remove from, must not be null, must be absolute.
  1048. *
  1049. * @return path's normalized absolute if it doesn't start with
  1050. * leading, path's path with leading's path removed otherwise.
  1051. *
  1052. * @since Ant 1.5
  1053. */
  1054. public String removeLeadingPath(File leading, File path) {
  1055. String l = normalize(leading.getAbsolutePath()).getAbsolutePath();
  1056. String p = normalize(path.getAbsolutePath()).getAbsolutePath();
  1057. if (l.equals(p)) {
  1058. return "";
  1059. }
  1060. // ensure that l ends with a /
  1061. // so we never think /foo was a parent directory of /foobar
  1062. if (!l.endsWith(File.separator)) {
  1063. l += File.separator;
  1064. }
  1065. return (p.startsWith(l)) ? p.substring(l.length()) : p;
  1066. }
  1067. /**
  1068. * Constructs a <code>file:</code> URI that represents the
  1069. * external form of the given pathname.
  1070. *
  1071. * <p>Will be an absolute URI if the given path is absolute.</p>
  1072. *
  1073. * <p>This code doesn't handle non-ASCII characters properly.</p>
  1074. *
  1075. * @param path the path in the local file system
  1076. * @return the URI version of the local path.
  1077. * @since Ant 1.6
  1078. */
  1079. public String toURI(String path) {
  1080. boolean isDir = (new File(path)).isDirectory();
  1081. StringBuffer sb = new StringBuffer("file:");
  1082. // catch exception if normalize thinks this is not an absolute path
  1083. try {
  1084. path = normalize(path).getAbsolutePath();
  1085. sb.append("//");
  1086. // add an extra slash for filesystems with drive-specifiers
  1087. if (!path.startsWith(File.separator)) {
  1088. sb.append("/");
  1089. }
  1090. } catch (BuildException e) {
  1091. // relative path
  1092. }
  1093. path = path.replace('\\', '/');
  1094. CharacterIterator iter = new StringCharacterIterator(path);
  1095. for (char c = iter.first(); c != CharacterIterator.DONE;
  1096. c = iter.next()) {
  1097. if (c < 256 && isSpecial[c]) {
  1098. sb.append('%');
  1099. sb.append(escapedChar1[c]);
  1100. sb.append(escapedChar2[c]);
  1101. } else {
  1102. sb.append(c);
  1103. }
  1104. }
  1105. if (isDir && !path.endsWith("/")) {
  1106. sb.append('/');
  1107. }
  1108. return sb.toString();
  1109. }
  1110. /**
  1111. * Constructs a file path from a <code>file:</code> URI.
  1112. *
  1113. * <p>Will be an absolute path if the given URI is absolute.</p>
  1114. *
  1115. * <p>Swallows '%' that are not followed by two characters,
  1116. * doesn't deal with non-ASCII characters.</p>
  1117. *
  1118. * @param uri the URI designating a file in the local filesystem.
  1119. * @return the local file system path for the file.
  1120. * @since Ant 1.6
  1121. */
  1122. public String fromURI(String uri) {
  1123. String path = Locator.fromURI(uri);
  1124. // catch exception if normalize thinks this is not an absolute path
  1125. try {
  1126. path = normalize(path).getAbsolutePath();
  1127. } catch (BuildException e) {
  1128. // relative path
  1129. }
  1130. return path;
  1131. }
  1132. /**
  1133. * Compares two filenames.
  1134. *
  1135. * <p>Unlike java.io.File#equals this method will try to compare
  1136. * the absolute paths and &quot;normalize&quot; the filenames
  1137. * before comparing them.</p>
  1138. *
  1139. * @param f1 the file whose name is to be compared.
  1140. * @param f2 the other file whose name is to be compared.
  1141. *
  1142. * @return true if the file are for the same file.
  1143. *
  1144. * @since Ant 1.5.3
  1145. */
  1146. public boolean fileNameEquals(File f1, File f2) {
  1147. return normalize(f1.getAbsolutePath())
  1148. .equals(normalize(f2.getAbsolutePath()));
  1149. }
  1150. /**
  1151. * Renames a file, even if that involves crossing file system boundaries.
  1152. *
  1153. * <p>This will remove <code>to</code> (if it exists), ensure that
  1154. * <code>to</code>'s parent directory exists and move
  1155. * <code>from</code>, which involves deleting <code>from</code> as
  1156. * well.</p>
  1157. *
  1158. * @throws IOException if anything bad happens during this
  1159. * process. Note that <code>to</code> may have been deleted
  1160. * already when this happens.
  1161. *
  1162. * @param from the file to move
  1163. * @param to the new file name
  1164. *
  1165. * @since Ant 1.6
  1166. */
  1167. public void rename(File from, File to) throws IOException {
  1168. if (to.exists() && !to.delete()) {
  1169. throw new IOException("Failed to delete " + to
  1170. + " while trying to rename " + from);
  1171. }
  1172. File parent = getParentFile(to);
  1173. if (parent != null && !parent.exists() && !parent.mkdirs()) {
  1174. throw new IOException("Failed to create directory " + parent
  1175. + " while trying to rename " + from);
  1176. }
  1177. if (!from.renameTo(to)) {
  1178. copyFile(from, to);
  1179. if (!from.delete()) {
  1180. throw new IOException("Failed to delete " + from
  1181. + " while trying to rename it.");
  1182. }
  1183. }
  1184. }
  1185. /**
  1186. * get the granularity of file timestamps.
  1187. * The choice is made on OS, which is incorrect -it should really be
  1188. * by filesystem. We do not have an easy way to probe for file systems,
  1189. * however.
  1190. * @return the difference, in milliseconds, which two file timestamps must have
  1191. * in order for the two files to be given a creation order.
  1192. */
  1193. public long getFileTimestampGranularity() {
  1194. if (Os.isFamily("dos")) {
  1195. return FAT_FILE_TIMESTAMP_GRANULARITY;
  1196. } else {
  1197. return UNIX_FILE_TIMESTAMP_GRANULARITY;
  1198. }
  1199. }
  1200. /**
  1201. * Returns true if the source is older than the dest.
  1202. * If the dest file does not exist, then the test returns false; it is
  1203. * implicitly not up do date.
  1204. * @param source source file (should be the older)
  1205. * @param dest dest file (should be the newer)
  1206. * @param granularity an offset added to the source time.
  1207. * @return true if the source is older than the dest, taking the
  1208. * granularity into account
  1209. * @since Ant1.7
  1210. */
  1211. public boolean isUpToDate(File source, File dest, long granularity) {
  1212. //do a check for the destination file existing
  1213. if (!dest.exists()) {
  1214. //if it does not, then the file is not up to date.
  1215. return false;
  1216. }
  1217. long sourceTime = source.lastModified();
  1218. long destTime = dest.lastModified();
  1219. return isUpToDate(sourceTime, destTime, granularity);
  1220. }
  1221. /**
  1222. * returns true if the source is older than the dest
  1223. * @param source source file (should be the older)
  1224. * @param dest dest file (should be the newer)
  1225. * @return true if the source is older than the dest, taking the granularity into account
  1226. * @since Ant1.7
  1227. */
  1228. public boolean isUpToDate(File source, File dest) {
  1229. return isUpToDate(source, dest, getFileTimestampGranularity());
  1230. }
  1231. /**
  1232. * compare two timestamps for being up to date, use granularity too.,
  1233. *
  1234. * @param sourceTime timestamp of source file
  1235. * @param destTime timestamp of dest file
  1236. * @param granularity os/filesys granularity
  1237. * @return true if the dest file is considered up to date
  1238. */
  1239. public boolean isUpToDate(long sourceTime, long destTime, long granularity) {
  1240. if (destTime == -1) {
  1241. return false;
  1242. }
  1243. return destTime >= sourceTime + granularity;
  1244. }
  1245. /**
  1246. * compare two timestamps for being up to date, use the
  1247. * current granularity
  1248. *
  1249. * @param sourceTime timestamp of source file
  1250. * @param destTime timestamp of dest file
  1251. * @return true if the dest file is considered up to date
  1252. */
  1253. public boolean isUpToDate(long sourceTime, long destTime) {
  1254. return isUpToDate(sourceTime, destTime, getFileTimestampGranularity());
  1255. }
  1256. /**
  1257. * close a writer without throwing any exception if something went wrong.
  1258. * Do not attempt to close it if the file is null
  1259. * @param device output writer, can be null
  1260. */
  1261. public static void close(Writer device) {
  1262. if (device != null) {
  1263. try {
  1264. device.close();
  1265. } catch (IOException ioex) {
  1266. //ignore
  1267. }
  1268. }
  1269. }
  1270. /**
  1271. * close a stream without throwing any exception if something went wrong.
  1272. * Do not attempt to close it if the file is null
  1273. *
  1274. * @param device stream, can be null
  1275. */
  1276. public static void close(Reader device) {
  1277. if (device != null) {
  1278. try {
  1279. device.close();
  1280. } catch (IOException ioex) {
  1281. //ignore
  1282. }
  1283. }
  1284. }
  1285. /**
  1286. * close a stream without throwing any exception if something went wrong.
  1287. * Do not attempt to close it if the file is null
  1288. *
  1289. * @param device stream, can be null
  1290. */
  1291. public static void close(OutputStream device) {
  1292. if (device != null) {
  1293. try {
  1294. device.close();
  1295. } catch (IOException ioex) {
  1296. //ignore
  1297. }
  1298. }
  1299. }
  1300. /**
  1301. * close a stream without throwing any exception if something went wrong.
  1302. * Do not attempt to close it if the file is null
  1303. *
  1304. * @param device stream, can be null
  1305. */
  1306. public static void close(InputStream device) {
  1307. if (device != null) {
  1308. try {
  1309. device.close();
  1310. } catch (IOException ioex) {
  1311. //ignore
  1312. }
  1313. }
  1314. }
  1315. /**
  1316. * Delete the file with {@link File#delete()} if the argument is not null.
  1317. * Do nothing on a null argument
  1318. * @param file file to delete
  1319. */
  1320. public static void delete(File file) {
  1321. if (file != null) {
  1322. file.delete();
  1323. }
  1324. }
  1325. }