/razpub/src/com/razie/pub/base/files/SSFilesRazie.java

http://razpub.googlecode.com/ · Java · 456 lines · 299 code · 71 blank · 86 comment · 62 complexity · d12b973d1d0a52a5533233358f56669e MD5 · raw file

  1. /**
  2. * Razvan's public code. Copyright 2008 based on Apache license (share alike) see LICENSE.txt for
  3. * details.
  4. */
  5. package com.razie.pub.base.files;
  6. import java.io.File;
  7. import java.io.FileFilter;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. import java.util.regex.Pattern;
  11. import javax.xml.parsers.SAXParser;
  12. import javax.xml.parsers.SAXParserFactory;
  13. import org.xml.sax.Attributes;
  14. import org.xml.sax.SAXException;
  15. import org.xml.sax.helpers.DefaultHandler;
  16. import com.razie.pub.FileUtils;
  17. import com.razie.pub.base.log.Log;
  18. import com.razie.pubstage.data.JStrucList;
  19. import com.razie.pubstage.data.JStrucTree;
  20. import com.razie.pubstage.data.JStructure;
  21. import com.razie.pubstage.data.TreeImplNode;
  22. import com.razie.pubstage.life.BeingDyingRtException;
  23. import com.razie.pubstage.life.Worker;
  24. /**
  25. * utility helper for working with files - especially finding files
  26. *
  27. * @author $Author: razvanc $
  28. */
  29. public class SSFilesRazie {
  30. public static interface FileFoundCback {
  31. void fileFound(File file);
  32. }
  33. /**
  34. * @param start the path to look in
  35. * @param filter - a filter, see Reg* classes defined here
  36. * @param recurse if true will search recursively through directories
  37. * @return a list of xml file names in the given path with the given mask, having the root tag
  38. * and root attribute matching an expression. It may be empty but not null
  39. */
  40. public static JStrucList<File> listFiles(String start, FileFilter filter, boolean recurse,
  41. FileFoundCback... cback) {
  42. JStrucList<File> l = new JStrucList.Impl<File>(null);
  43. ifindFiles(start, l, filter, recurse, cback);
  44. return l;
  45. }
  46. /**
  47. * @param start the path to look in
  48. * @param filter - a filter, see Reg* classes defined here
  49. * @param recurse if true will search recursively through directories
  50. * @return a list of xml file names in the given path with the given mask, having the root tag
  51. * and root attribute matching an expression. It may be empty but not null
  52. */
  53. public static JStrucTree<File> treeFiles(String start, FileFilter filter, boolean recurse,
  54. FileFoundCback... cback) {
  55. JStrucTree<File> l = new JStrucTree.ImplNode<File>(null);
  56. ifindFiles(start, l, filter, recurse, cback);
  57. return l;
  58. }
  59. /**
  60. * @param start the path to look in
  61. * @param filter - a filter, see Reg* classes defined here
  62. * @param recurse if true will search recursively through directories
  63. * @return a list of xml file names in the given path with the given mask, having the root tag
  64. * and root attribute matching an expression. It may be empty but not null
  65. */
  66. public static void ifindFiles(String start, JStructure<File> l, FileFilter filter, boolean recurse,
  67. FileFoundCback... cback) {
  68. if (start == null)
  69. return;
  70. String dir = start;
  71. if (!dir.endsWith("/") && !dir.endsWith("\\")) {
  72. dir += "/";
  73. }
  74. File f = new File(dir);
  75. if (f.isDirectory() && l instanceof JStrucTree)
  76. ((JStrucTree.ImplNode<File>) l).setContents(f);
  77. findFiles(f, l, filter, recurse, 2, 100, cback);
  78. Log.logThis(l.toString());
  79. }
  80. private static JStructure<File> add(JStructure<File> l, File f, boolean isDirectory) {
  81. if (l instanceof JStrucTree) {
  82. if (isDirectory)
  83. return ((JStrucTree.ImplNode<File>) l).addNode(f);
  84. else
  85. ((JStrucTree.ImplNode<File>) l).addLeaf(f);
  86. } else if (!isDirectory) {
  87. JStrucList.Impl<File> tree = (JStrucList.Impl<File>) l;
  88. tree.add(f);
  89. return tree;
  90. } else return l;
  91. return null;
  92. }
  93. /**
  94. * TODO SECURITY add a filter for the directory name
  95. *
  96. * @param dir the directory to start the search in
  97. * @param files will add files to this list
  98. * @param filter the filter for files
  99. * @param recurse if true will search recursively
  100. */
  101. public static void findFiles(File dir, JStructure<File> files, FileFilter filter, boolean recurse,
  102. int min, int max, FileFoundCback... cback) {
  103. if (Worker.dying()) {
  104. throw new BeingDyingRtException();
  105. }
  106. try {
  107. File[] s = filter != null ? dir.listFiles(filter) : dir.listFiles();
  108. if (s != null) {
  109. for (int i = 0; s != null && i < s.length; i++) {
  110. add(files, s[i], false);
  111. if (cback.length > 0) {
  112. cback[0].fileFound(s[i]);
  113. }
  114. }
  115. }
  116. // TODO optimize this so we only find directories
  117. if (recurse) {
  118. File[] dirs = dir.listFiles();
  119. if (dirs == null) {
  120. return;
  121. }
  122. int noDirs = 0;
  123. for (int i = 0; i < dirs.length; i++) {
  124. if (dirs[i].isDirectory()) {
  125. noDirs++;
  126. }
  127. }
  128. if (noDirs > 0) {
  129. int curDirNo = 0;
  130. for (int i = 0; i < dirs.length; i++) {
  131. if (dirs[i].isDirectory()) {
  132. findFiles(dirs[i], add(files, dirs[i], true), filter, recurse, min
  133. + (int) ((max - min) * (curDirNo * 1.0 / noDirs)), min
  134. + (int) ((max - min) * ((curDirNo + 1) * 1.0 / noDirs)), cback);
  135. curDirNo++;
  136. Worker.updateProgress(min + (int) ((max - min) * (curDirNo * 1.0 / noDirs)),
  137. dirs[i].getName());
  138. }
  139. }
  140. }
  141. }
  142. } catch (SecurityException ex) {
  143. // do nothing here
  144. }
  145. }
  146. /**
  147. * return nice string with filesize
  148. *
  149. * @param size a file size in bytes
  150. * @return a nice string in K/M/G
  151. */
  152. public static String niceFileSize(long size) {
  153. float f = size;
  154. if (size > G) {
  155. return String.valueOf(formatFloat(f / G, 3)) + " Gb";
  156. } else if (size > M) {
  157. return String.valueOf(formatFloat(f / M, 3)) + " Mb";
  158. } else if (size > K) {
  159. return String.valueOf(formatFloat(f / K, 3)) + " Kb";
  160. } else {
  161. return String.valueOf(size) + " bytes";
  162. }
  163. }
  164. /**
  165. * format a float as string with the given no of digits
  166. *
  167. * @param f the float to format
  168. * @param nbDigits no of digits after .
  169. * @return nice float string
  170. */
  171. private static String formatFloat(float f, int nbDigits) {
  172. String s = "" + f;
  173. int idx = s.indexOf('.');
  174. if ((idx >= 0) && (idx + nbDigits + 1 < s.length()))
  175. s = s.substring(0, idx + nbDigits + 1);
  176. return s;
  177. }
  178. public static String getRootAttrFromFile(File file, String rootAttrNm) {
  179. RootElementChecker handler = new RootElementChecker();
  180. try {
  181. SAXParserFactory parserFactory = SAXParserFactory.newInstance();
  182. parserFactory.setValidating(false);
  183. SAXParser parser = parserFactory.newSAXParser();
  184. parser.parse(file, handler);
  185. } catch (FirstElementFoundException e) {
  186. // do nothing
  187. } catch (Exception e) {
  188. return null;
  189. }
  190. String attrVal = rootAttrNm == null ? null : handler.elementAttributes.getValue(rootAttrNm);
  191. return attrVal;
  192. }
  193. /** SAX handler to stop parsing at the first element and get its attributes */
  194. private static class RootElementChecker extends DefaultHandler {
  195. String elementName;
  196. Attributes elementAttributes;
  197. public RootElementChecker() {
  198. }
  199. public void startElement(String uri, String localName, String qName, Attributes attributes)
  200. throws SAXException {
  201. elementAttributes = attributes;
  202. elementName = qName;
  203. throw new FirstElementFoundException("First Element found");
  204. }
  205. }
  206. /** specific exception thrown when first element found */
  207. static class FirstElementFoundException extends SAXException {
  208. public FirstElementFoundException(String message) {
  209. super(message);
  210. }
  211. }
  212. /**
  213. * a regexp based file filter, will filter files based on their name, if it matches the given
  214. * regular expression
  215. */
  216. public static class ORFileFilter implements FileFilter, Cloneable {
  217. protected List<FileFilter> filters = new ArrayList<FileFilter>();
  218. public ORFileFilter() {
  219. }
  220. public ORFileFilter(ORFileFilter f) {
  221. this.filters.addAll(f.filters);
  222. }
  223. public boolean accept(File pathname) {
  224. for (FileFilter ff : filters) {
  225. if (ff.accept(pathname)) {
  226. return true;
  227. }
  228. }
  229. return false;
  230. }
  231. public void add(FileFilter f) {
  232. this.filters.add(f);
  233. }
  234. public Object clone() {
  235. return new ORFileFilter(this);
  236. }
  237. public String toString() {
  238. return "SmpFiles.OrFileFilter " + Log.tryToString("", this.filters);
  239. }
  240. }
  241. public static class ANDFileFilter extends ORFileFilter {
  242. public ANDFileFilter() {
  243. }
  244. public ANDFileFilter(ANDFileFilter f) {
  245. super(f);
  246. }
  247. public boolean accept(File pathname) {
  248. for (FileFilter ff : filters) {
  249. if (!ff.accept(pathname)) {
  250. return false;
  251. }
  252. }
  253. return true;
  254. }
  255. public Object clone() {
  256. return new ANDFileFilter(this);
  257. }
  258. public String toString() {
  259. return "SmpFiles.ANDFileFilter " + Log.tryToString("", this.filters);
  260. }
  261. }
  262. public static class NOTFileFilter implements FileFilter {
  263. FileFilter filter;
  264. public NOTFileFilter() {
  265. }
  266. public NOTFileFilter(NOTFileFilter f) {
  267. this.filter = f.filter;
  268. }
  269. public boolean accept(File pathname) {
  270. if (filter.accept(pathname)) {
  271. return false;
  272. }
  273. return true;
  274. }
  275. public void setFilter(FileFilter f) {
  276. filter = f;
  277. }
  278. public Object clone() {
  279. return new NOTFileFilter(this);
  280. }
  281. public String toString() {
  282. return "SmpFiles.NOTFileFilter " + Log.tryToString("", this.filter);
  283. }
  284. }
  285. /**
  286. * a regexp based file filter, will filter files based on their name, if it matches the given
  287. * regular expression
  288. */
  289. public static class RegExpFileFilter implements FileFilter {
  290. protected String regExp;
  291. protected Pattern pattern;
  292. public RegExpFileFilter(String regExp) {
  293. this.regExp = regExp;
  294. pattern = Pattern.compile(regExp);
  295. }
  296. public boolean accept(File pathname) {
  297. boolean b = pathname.isFile() && pattern.matcher(pathname.getName()).matches();
  298. if (b && SSFilesRazie.logger.isTraceLevel(3)) {
  299. // SmpFilesRazie.logger.trace(3, "RegExpFileFilter accepted file: " +
  300. // pathname.getName());
  301. } else if ((!b) && SSFilesRazie.logger.isTraceLevel(3)) {
  302. // SmpFilesRazie.logger.trace(3, "RegExpFileFilter REJECTED file: " +
  303. // pathname.getName());
  304. }
  305. return b;
  306. }
  307. public Object clone() {
  308. return new RegExpFileFilter(regExp);
  309. }
  310. public String toString() {
  311. return "SmpFiles.RegExpFileFilter(regExp=" + this.regExp + ")";
  312. }
  313. }
  314. /**
  315. * a regexp based XML file filter, will filter files based on their name, if it matches the
  316. * given regular expression and if it contains a specific root tag and/or root attribute
  317. * name/value
  318. */
  319. public static class RegExpXmlFileFilter extends RegExpFileFilter implements FileFilter {
  320. private String rootTag, rootAttrNm, rootAttrRegExp;
  321. /**
  322. * c-tor
  323. *
  324. * @param regexp regexp for filename. cannot be null
  325. * @param rootTag root tag name - can be null (no check for root tag but will check for root
  326. * attr)
  327. * @param rootAttrNm root attr name - can be null (no check for root attr)
  328. * @param rootAttrRegExp regexp for root attr value - can be null (no check for root attr)
  329. */
  330. public RegExpXmlFileFilter(String regexp, String rootTag, String rootAttrNm, String rootAttrRegExp) {
  331. super(regexp);
  332. this.rootTag = rootTag;
  333. this.rootAttrNm = rootAttrNm;
  334. this.rootAttrRegExp = rootAttrRegExp;
  335. }
  336. public String toString() {
  337. return "SmpFiles.RegExpXmlFileFilter(regExp=" + this.regExp + ", rootTag=" + this.rootTag
  338. + ", rootAttrNm=" + rootAttrNm + ", rootAttrRegExp=" + this.rootAttrRegExp + ")";
  339. }
  340. public boolean accept(File pathname) {
  341. boolean b = pathname.isFile() && pattern.matcher(pathname.getName()).matches()
  342. && checkRoot(pathname);
  343. if (b && SSFilesRazie.logger.isTraceLevel(1)) {
  344. SSFilesRazie.logger.trace(1, "RegExpXmlFileFilter accepted file: " + pathname.getName());
  345. } else if ((!b) && SSFilesRazie.logger.isTraceLevel(3)) {
  346. SSFilesRazie.logger.trace(3, "RegExpXmlFileFilter REJECTED file: " + pathname.getName());
  347. }
  348. return b;
  349. }
  350. public boolean checkRoot(File file) {
  351. RootElementChecker handler = new RootElementChecker();
  352. try {
  353. SAXParserFactory parserFactory = SAXParserFactory.newInstance();
  354. parserFactory.setValidating(false);
  355. SAXParser parser = parserFactory.newSAXParser();
  356. parser.parse(file, handler);
  357. } catch (FirstElementFoundException e) {
  358. // do nothing
  359. } catch (Exception e) {
  360. return false;
  361. }
  362. String attrVal = rootAttrNm == null ? null : handler.elementAttributes.getValue(rootAttrNm);
  363. // TODO i don't handle rootAttrNm==null && rootAttrRegExp!=null, i.e. there is at least
  364. // an attribute matching the exp
  365. return (rootTag == null || rootTag.equals(handler.elementName))
  366. && (rootAttrRegExp == null || ((attrVal != null) && attrVal.matches(rootAttrRegExp)));
  367. }
  368. public Object clone() {
  369. return new RegExpXmlFileFilter(regExp, rootTag, rootAttrNm, rootAttrRegExp);
  370. }
  371. }
  372. public static void main(String args[]) throws Exception {
  373. RegExpXmlFileFilter filter = new RegExpXmlFileFilter("", "script", "test", "vall.*");
  374. System.out.println(filter.checkRoot(new File("c:/work/gigi.xml")));
  375. String fn = "file:/c:/gugu\\./vasile/..\\ionel.xml";
  376. System.out.println("canonical (" + fn + ") = " + FileUtils.toCanonicalPath(fn));
  377. fn = "file:/c:/gugu\\./vasile\\ionel.xml";
  378. System.out.println("canonical (" + fn + ") = " + FileUtils.toCanonicalPath(fn));
  379. }
  380. /** formatting file sizes */
  381. private static float K = 1024;
  382. private static float M = K * 1024;
  383. private static float G = M * 1024;
  384. public static final Log logger = Log.factory.create("", SSFilesRazie.class.getName());
  385. }