PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/sys/java/fan/sys/File.java

https://bitbucket.org/bedlaczech/fan-1.0
Java | 483 lines | 346 code | 85 blank | 52 comment | 58 complexity | 43ffcf7dd69a930f98c33346a6fe0f45 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2006, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 26 Mar 06 Brian Frank Creation
  7. //
  8. package fan.sys;
  9. import java.net.*;
  10. /**
  11. * File represents a file or directory in a file system.
  12. */
  13. public abstract class File
  14. extends FanObj
  15. {
  16. //////////////////////////////////////////////////////////////////////////
  17. // Construction
  18. //////////////////////////////////////////////////////////////////////////
  19. public static File make(Uri uri) { return make(uri, true); }
  20. public static File make(Uri uri, boolean checkSlash)
  21. {
  22. java.io.File f = LocalFile.uriToFile(uri);
  23. if (f.isDirectory() && !checkSlash && !uri.isDir())
  24. uri = uri.plusSlash();
  25. return new LocalFile(uri, f);
  26. }
  27. public static File os(String osPath)
  28. {
  29. return new LocalFile(new java.io.File(osPath));
  30. }
  31. public static List osRoots()
  32. {
  33. List list = new List(Sys.FileType);
  34. java.io.File[] roots = java.io.File.listRoots();
  35. for (int i=0; i<roots.length; ++i)
  36. list.add(new LocalFile(roots[i], true));
  37. return list;
  38. }
  39. public static File createTemp() { return createTemp(null, null, null); }
  40. public static File createTemp(String prefix) { return createTemp(prefix, null, null); }
  41. public static File createTemp(String prefix, String suffix) { return createTemp(prefix, suffix, null); }
  42. public static File createTemp(String prefix, String suffix, File dir)
  43. {
  44. if (prefix == null || prefix.length() == 0) prefix = "fan";
  45. if (prefix.length() == 1) prefix = prefix + "xx";
  46. if (prefix.length() == 2) prefix = prefix + "x";
  47. if (suffix == null) suffix = ".tmp";
  48. java.io.File d = null;
  49. if (dir != null)
  50. {
  51. if (!(dir instanceof LocalFile)) throw IOErr.make("Dir is not on local file system: " + dir);
  52. d = ((LocalFile)dir).file;
  53. }
  54. try
  55. {
  56. return new LocalFile(java.io.File.createTempFile(prefix, suffix, d));
  57. }
  58. catch (java.io.IOException e)
  59. {
  60. throw IOErr.make(e);
  61. }
  62. }
  63. protected static void makeNew$(File self, Uri uri)
  64. {
  65. self.uri = uri;
  66. }
  67. protected File(Uri uri) { this.uri = uri; }
  68. protected File() {}
  69. //////////////////////////////////////////////////////////////////////////
  70. // Identity
  71. //////////////////////////////////////////////////////////////////////////
  72. public final boolean equals(Object obj)
  73. {
  74. if (obj instanceof File)
  75. {
  76. return uri.equals(((File)obj).uri);
  77. }
  78. return false;
  79. }
  80. public final int hashCode() { return uri.hashCode(); }
  81. public final long hash() { return uri.hash(); }
  82. public final String toStr() { return uri.toStr(); }
  83. public Type typeof() { return Sys.FileType; }
  84. //////////////////////////////////////////////////////////////////////////
  85. // Uri
  86. //////////////////////////////////////////////////////////////////////////
  87. public final Uri uri() { return uri; }
  88. public final boolean isDir() { return uri.isDir(); }
  89. public final List path() { return uri.path(); }
  90. public final String pathStr() { return uri.pathStr(); }
  91. public final String name() { return uri.name(); }
  92. public final String basename() { return uri.basename(); }
  93. public final String ext() { return uri.ext(); }
  94. public final MimeType mimeType() { return uri.mimeType(); }
  95. //////////////////////////////////////////////////////////////////////////
  96. // Access
  97. //////////////////////////////////////////////////////////////////////////
  98. public abstract boolean exists();
  99. public abstract Long size();
  100. public boolean isEmpty()
  101. {
  102. if (isDir()) return list().isEmpty();
  103. Long size = this.size();
  104. return size == null || size.longValue() <= 0;
  105. }
  106. public abstract DateTime modified();
  107. public abstract void modified(DateTime time);
  108. public abstract String osPath();
  109. public abstract File parent();
  110. public abstract List list();
  111. public List listDirs()
  112. {
  113. List list = list();
  114. for (int i=list.sz()-1; i>=0; --i)
  115. if (!((File)list.get(i)).isDir())
  116. list.removeAt(i);
  117. return list;
  118. }
  119. public List listFiles()
  120. {
  121. List list = list();
  122. for (int i=list.sz()-1; i>=0; --i)
  123. if (((File)list.get(i)).isDir())
  124. list.removeAt(i);
  125. return list;
  126. }
  127. public void walk(Func c)
  128. {
  129. c.call(this);
  130. if (isDir())
  131. {
  132. List list = list();
  133. for (int i=0; i<list.sz(); ++i)
  134. ((File)list.get(i)).walk(c);
  135. }
  136. }
  137. public abstract File normalize();
  138. public File plus(Uri uri) { return plus(uri, true); }
  139. public abstract File plus(Uri uri, boolean checkSlash);
  140. File plus(String uri) { return plus(Uri.fromStr(uri)); }
  141. File plusNameOf(File x)
  142. {
  143. String name = x.name();
  144. if (x.isDir()) name += "/";
  145. return plus(name);
  146. }
  147. public FileStore store()
  148. {
  149. throw UnsupportedErr.make(typeof().qname() + ".store");
  150. }
  151. //////////////////////////////////////////////////////////////////////////
  152. // Management
  153. //////////////////////////////////////////////////////////////////////////
  154. public abstract File create();
  155. public File createFile(String name)
  156. {
  157. if (!isDir()) throw IOErr.make("Not a directory: " + this);
  158. return this.plus(Uri.fromStr(name)).create();
  159. }
  160. public File createDir(String name)
  161. {
  162. if (!isDir()) throw IOErr.make("Not a directory: " + this);
  163. if (!name.endsWith("/")) name = name + "/";
  164. return this.plus(Uri.fromStr(name)).create();
  165. }
  166. public abstract void delete();
  167. public abstract File deleteOnExit();
  168. //////////////////////////////////////////////////////////////////////////
  169. // Copy
  170. //////////////////////////////////////////////////////////////////////////
  171. public final File copyTo(File to) { return copyTo(to, null); }
  172. public File copyTo(File to, Map options)
  173. {
  174. // sanity
  175. if (isDir() != to.isDir())
  176. {
  177. if (isDir())
  178. throw ArgErr.make("copyTo must be dir `" + to + "`");
  179. else
  180. throw ArgErr.make("copyTo must not be dir `" + to + "`");
  181. }
  182. // options
  183. Object exclude = null, overwrite = null;
  184. if (options != null)
  185. {
  186. exclude = options.get("exclude");
  187. overwrite = options.get("overwrite");
  188. }
  189. // recurse
  190. doCopyTo(to, exclude, overwrite);
  191. return to;
  192. }
  193. private void doCopyTo(File to, Object exclude, Object overwrite)
  194. {
  195. // check exclude
  196. if (exclude instanceof Regex)
  197. {
  198. if (((Regex)exclude).matches(uri.toStr())) return;
  199. }
  200. else if (exclude instanceof Func)
  201. {
  202. if (((Func)exclude).callBool(this)) return;
  203. }
  204. // check for overwrite
  205. if (to.exists())
  206. {
  207. if (overwrite instanceof Boolean)
  208. {
  209. if (!((Boolean)overwrite).booleanValue()) return;
  210. }
  211. else if (overwrite instanceof Func)
  212. {
  213. if (!((Func)overwrite).callBool(this)) return;
  214. }
  215. else
  216. {
  217. throw IOErr.make("No overwrite policy for `" + to + "`");
  218. }
  219. }
  220. // copy directory
  221. if (isDir())
  222. {
  223. to.create();
  224. List kids = list();
  225. for (int i=0; i<kids.sz(); ++i)
  226. {
  227. File kid = (File)kids.get(i);
  228. kid.doCopyTo(to.plusNameOf(kid), exclude, overwrite);
  229. }
  230. }
  231. // copy file contents
  232. else
  233. {
  234. OutStream out = to.out();
  235. try
  236. {
  237. in().pipe(out);
  238. }
  239. finally
  240. {
  241. out.close();
  242. }
  243. copyPermissions(this, to);
  244. }
  245. }
  246. public final File copyInto(File dir) { return copyInto(dir, null); }
  247. public File copyInto(File dir, Map options)
  248. {
  249. if (!dir.isDir())
  250. throw ArgErr.make("Not a dir: `" + dir + "`");
  251. return copyTo(dir.plusNameOf(this), options);
  252. }
  253. private static void copyPermissions(File from, File to)
  254. {
  255. // if both are LocaleFiles, try to hack the file
  256. // permissions until we get 1.7 support
  257. try
  258. {
  259. if (from instanceof LocalFile && to instanceof LocalFile)
  260. {
  261. java.io.File jfrom = ((LocalFile)from).file;
  262. java.io.File jto = ((LocalFile)to).file;
  263. jto.setReadable(jfrom.canRead(), false);
  264. jto.setWritable(jfrom.canWrite(), false);
  265. jto.setExecutable(jfrom.canExecute(), false);
  266. }
  267. }
  268. catch (NoSuchMethodError e) {} // ignore if not on 1.6
  269. }
  270. //////////////////////////////////////////////////////////////////////////
  271. // Move
  272. //////////////////////////////////////////////////////////////////////////
  273. public abstract File moveTo(File to);
  274. public File moveInto(File dir)
  275. {
  276. if (!dir.isDir())
  277. throw ArgErr.make("Not a dir: `" + dir + "`");
  278. return moveTo(dir.plusNameOf(this));
  279. }
  280. public File rename(String newName)
  281. {
  282. if (isDir()) newName += "/";
  283. File parent = parent();
  284. if (parent == null)
  285. return moveTo(File.make(Uri.fromStr(newName)));
  286. else
  287. return moveTo(parent.plus(newName));
  288. }
  289. //////////////////////////////////////////////////////////////////////////
  290. // IO
  291. //////////////////////////////////////////////////////////////////////////
  292. public Buf open() { return open("rw"); }
  293. public abstract Buf open(String mode);
  294. public Buf mmap() { return mmap("rw", 0L, null); }
  295. public Buf mmap(String mode) { return mmap(mode, 0L, null); }
  296. public Buf mmap(String mode, long pos) { return mmap(mode, pos, null); }
  297. public abstract Buf mmap(String mode, long pos, Long size);
  298. public InStream in() { return in(FanInt.Chunk); }
  299. public abstract InStream in(Long bufSize);
  300. public OutStream out() { return out(false, FanInt.Chunk); }
  301. public OutStream out(boolean append) { return out(append, FanInt.Chunk); }
  302. public abstract OutStream out(boolean append, Long bufSize);
  303. public final Buf readAllBuf()
  304. {
  305. return in(FanInt.Chunk).readAllBuf();
  306. }
  307. public final List readAllLines()
  308. {
  309. return in(FanInt.Chunk).readAllLines();
  310. }
  311. public final void eachLine(Func f)
  312. {
  313. in(FanInt.Chunk).eachLine(f);
  314. }
  315. public final String readAllStr() { return readAllStr(true); }
  316. public final String readAllStr(boolean normalizeNewlines)
  317. {
  318. return in(FanInt.Chunk).readAllStr(normalizeNewlines);
  319. }
  320. public final Map readProps()
  321. {
  322. return in(FanInt.Chunk).readProps();
  323. }
  324. public final void writeProps(Map props)
  325. {
  326. out(false, FanInt.Chunk).writeProps(props, true);
  327. }
  328. public final Object readObj() { return readObj(null); }
  329. public final Object readObj(Map options)
  330. {
  331. InStream in = in();
  332. try
  333. {
  334. return in.readObj(options);
  335. }
  336. finally
  337. {
  338. in.close();
  339. }
  340. }
  341. public final void writeObj(Object obj) { writeObj(obj, null); }
  342. public final void writeObj(Object obj, Map options)
  343. {
  344. OutStream out = out();
  345. try
  346. {
  347. out.writeObj(obj, options);
  348. }
  349. finally
  350. {
  351. out.close();
  352. }
  353. }
  354. //////////////////////////////////////////////////////////////////////////
  355. // Java URL
  356. //////////////////////////////////////////////////////////////////////////
  357. /**
  358. * Map a sys::File to Java's twised URL, URLStreamHandler, URLConnection model
  359. */
  360. public URL toJavaURL()
  361. {
  362. try
  363. {
  364. Long port = uri.port();
  365. if (port == null) port = Long.valueOf(-1);
  366. return new URL(uri.scheme(), uri.host(), port.intValue(), uri.pathStr(), new FileURLStreamHandler(this));
  367. }
  368. catch (Exception e)
  369. {
  370. throw Err.make(e);
  371. }
  372. }
  373. static class FileURLStreamHandler extends URLStreamHandler
  374. {
  375. FileURLStreamHandler(File file) { this.file = file; }
  376. protected URLConnection openConnection(URL url)
  377. {
  378. return new FileURLConnection(url, file);
  379. }
  380. private final File file;
  381. }
  382. static class FileURLConnection extends URLConnection
  383. {
  384. FileURLConnection(URL url, File file) { super(url); this.file = file; }
  385. public void connect() {}
  386. public java.io.InputStream getInputStream()
  387. {
  388. return SysInStream.java(file.in());
  389. }
  390. private final File file;
  391. }
  392. //////////////////////////////////////////////////////////////////////////
  393. // Fields
  394. //////////////////////////////////////////////////////////////////////////
  395. public static final String sep = java.io.File.separator;
  396. public static final String pathSep = java.io.File.pathSeparator;
  397. Uri uri;
  398. }