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

ExportUtil.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*
  2. Copyright (c) 2007 Health Market Science, Inc.
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with this library; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  14. USA
  15. You can contact Health Market Science at info@healthmarketscience.com
  16. or at the following address:
  17. Health Market Science
  18. 2700 Horizon Drive
  19. Suite 200
  20. King of Prussia, PA 19406
  21. */
  22. package com.healthmarketscience.jackcess;
  23. import java.io.BufferedWriter;
  24. import java.io.File;
  25. import java.io.FileWriter;
  26. import java.io.IOException;
  27. import java.util.ArrayList;
  28. import java.util.Collection;
  29. import java.util.HashSet;
  30. import java.util.Iterator;
  31. import java.util.List;
  32. import java.util.Map;
  33. import java.util.regex.Pattern;
  34. import org.apache.commons.logging.Log;
  35. import org.apache.commons.logging.LogFactory;
  36. /**
  37. *
  38. * @author Frank Gerbig
  39. */
  40. public class ExportUtil {
  41. private static final Log LOG = LogFactory.getLog(ExportUtil.class);
  42. public static final String DEFAULT_DELIMITER = ",";
  43. public static final char DEFAULT_QUOTE_CHAR = '"';
  44. public static final String DEFAULT_FILE_EXT = "csv";
  45. private ExportUtil() {
  46. }
  47. /**
  48. * Copy all tables into new delimited text files <br>
  49. * Equivalent to: {@code exportAll(db, dir, "csv");}
  50. *
  51. * @param db
  52. * Database the table to export belongs to
  53. * @param dir
  54. * The directory where the new files will be created
  55. *
  56. * @see #exportAll(Database,File,String)
  57. */
  58. public static void exportAll(Database db, File dir)
  59. throws IOException {
  60. exportAll(db, dir, DEFAULT_FILE_EXT);
  61. }
  62. /**
  63. * Copy all tables into new delimited text files <br>
  64. * Equivalent to: {@code exportFile(db, name, f, false, null, '"',
  65. * SimpleExportFilter.INSTANCE);}
  66. *
  67. * @param db
  68. * Database the table to export belongs to
  69. * @param dir
  70. * The directory where the new files will be created
  71. * @param ext
  72. * The file extension of the new files
  73. *
  74. * @see #exportFile(Database,String,File,boolean,String,char,ExportFilter)
  75. */
  76. public static void exportAll(Database db, File dir,
  77. String ext) throws IOException {
  78. for (String tableName : db.getTableNames()) {
  79. exportFile(db, tableName, new File(dir, tableName + "." + ext), false,
  80. DEFAULT_DELIMITER, DEFAULT_QUOTE_CHAR, SimpleExportFilter.INSTANCE);
  81. }
  82. }
  83. /**
  84. * Copy all tables into new delimited text files <br>
  85. * Equivalent to: {@code exportFile(db, name, f, false, null, '"',
  86. * SimpleExportFilter.INSTANCE);}
  87. *
  88. * @param db
  89. * Database the table to export belongs to
  90. * @param dir
  91. * The directory where the new files will be created
  92. * @param ext
  93. * The file extension of the new files
  94. * @param header
  95. * If <code>true</code> the first line contains the column names
  96. *
  97. * @see #exportFile(Database,String,File,boolean,String,char,ExportFilter)
  98. */
  99. public static void exportAll(Database db, File dir,
  100. String ext, boolean header)
  101. throws IOException {
  102. for (String tableName : db.getTableNames()) {
  103. exportFile(db, tableName, new File(dir, tableName + "." + ext), header,
  104. DEFAULT_DELIMITER, DEFAULT_QUOTE_CHAR, SimpleExportFilter.INSTANCE);
  105. }
  106. }
  107. /**
  108. * Copy all tables into new delimited text files <br>
  109. * Equivalent to: {@code exportFile(db, name, f, false, null, '"',
  110. * SimpleExportFilter.INSTANCE);}
  111. *
  112. * @param db
  113. * Database the table to export belongs to
  114. * @param dir
  115. * The directory where the new files will be created
  116. * @param ext
  117. * The file extension of the new files
  118. * @param header
  119. * If <code>true</code> the first line contains the column names
  120. * @param delim
  121. * The column delimiter, <code>null</code> for default (comma)
  122. * @param quote
  123. * The quote character
  124. * @param filter
  125. * valid export filter
  126. *
  127. * @see #exportFile(Database,String,File,boolean,String,char,ExportFilter)
  128. */
  129. public static void exportAll(Database db, File dir,
  130. String ext, boolean header, String delim,
  131. char quote, ExportFilter filter)
  132. throws IOException {
  133. for (String tableName : db.getTableNames()) {
  134. exportFile(db, tableName, new File(dir, tableName + "." + ext), header,
  135. delim, quote, filter);
  136. }
  137. }
  138. /**
  139. * Copy a table into a new delimited text file <br>
  140. * Equivalent to: {@code exportFile(db, name, f, false, null, '"',
  141. * SimpleExportFilter.INSTANCE);}
  142. *
  143. * @param db
  144. * Database the table to export belongs to
  145. * @param tableName
  146. * Name of the table to export
  147. * @param f
  148. * New file to create
  149. *
  150. * @see #exportFile(Database,String,File,boolean,String,char,ExportFilter)
  151. */
  152. public static void exportFile(Database db, String tableName,
  153. File f) throws IOException {
  154. exportFile(db, tableName, f, false, DEFAULT_DELIMITER, DEFAULT_QUOTE_CHAR,
  155. SimpleExportFilter.INSTANCE);
  156. }
  157. /**
  158. * Copy a table into a new delimited text file <br>
  159. * Nearly equivalent to: {@code exportWriter(db, name, new BufferedWriter(f),
  160. * header, delim, quote, filter);}
  161. *
  162. * @param db
  163. * Database the table to export belongs to
  164. * @param tableName
  165. * Name of the table to export
  166. * @param f
  167. * New file to create
  168. * @param header
  169. * If <code>true</code> the first line contains the column names
  170. * @param delim
  171. * The column delimiter, <code>null</code> for default (comma)
  172. * @param quote
  173. * The quote character
  174. * @param filter
  175. * valid export filter
  176. *
  177. * @see #exportWriter(Database,String,BufferedWriter,boolean,String,char,ExportFilter)
  178. */
  179. public static void exportFile(Database db, String tableName,
  180. File f, boolean header, String delim, char quote,
  181. ExportFilter filter) throws IOException {
  182. BufferedWriter out = null;
  183. try {
  184. out = new BufferedWriter(new FileWriter(f));
  185. exportWriter(db, tableName, out, header, delim, quote, filter);
  186. out.close();
  187. } finally {
  188. if (out != null) {
  189. try {
  190. out.close();
  191. } catch (Exception ex) {
  192. LOG.warn("Could not close file " + f.getAbsolutePath(), ex);
  193. }
  194. }
  195. }
  196. }
  197. /**
  198. * Copy a table in this database into a new delimited text file <br>
  199. * Equivalent to: {@code exportWriter(db, name, out, false, null, '"',
  200. * SimpleExportFilter.INSTANCE);}
  201. *
  202. * @param db
  203. * Database the table to export belongs to
  204. * @param tableName
  205. * Name of the table to export
  206. * @param out
  207. * Writer to export to
  208. *
  209. * @see #exportWriter(Database,String,BufferedWriter,boolean,String,char,ExportFilter)
  210. */
  211. public static void exportWriter(Database db, String tableName,
  212. BufferedWriter out) throws IOException {
  213. exportWriter(db, tableName, out, false, DEFAULT_DELIMITER,
  214. DEFAULT_QUOTE_CHAR, SimpleExportFilter.INSTANCE);
  215. }
  216. /**
  217. * Copy a table in this database into a new delimited text file. <br>
  218. * Equivalent to: {@code exportWriter(Cursor.createCursor(db.getTable(tableName)), out, header, delim, quote, filter);}
  219. *
  220. * @param db
  221. * Database the table to export belongs to
  222. * @param tableName
  223. * Name of the table to export
  224. * @param out
  225. * Writer to export to
  226. * @param header
  227. * If <code>true</code> the first line contains the column names
  228. * @param delim
  229. * The column delimiter, <code>null</code> for default (comma)
  230. * @param quote
  231. * The quote character
  232. * @param filter
  233. * valid export filter
  234. *
  235. * @see #exportWriter(Cursor,BufferedWriter,boolean,String,char,ExportFilter)
  236. */
  237. public static void exportWriter(Database db, String tableName,
  238. BufferedWriter out, boolean header, String delim,
  239. char quote, ExportFilter filter)
  240. throws IOException
  241. {
  242. exportWriter(Cursor.createCursor(db.getTable(tableName)), out, header,
  243. delim, quote, filter);
  244. }
  245. /**
  246. * Copy a table in this database into a new delimited text file.
  247. *
  248. * @param cursor
  249. * Cursor to export
  250. * @param out
  251. * Writer to export to
  252. * @param header
  253. * If <code>true</code> the first line contains the column names
  254. * @param delim
  255. * The column delimiter, <code>null</code> for default (comma)
  256. * @param quote
  257. * The quote character
  258. * @param filter
  259. * valid export filter
  260. */
  261. public static void exportWriter(Cursor cursor,
  262. BufferedWriter out, boolean header, String delim,
  263. char quote, ExportFilter filter)
  264. throws IOException
  265. {
  266. String delimiter = (delim == null) ? DEFAULT_DELIMITER : delim;
  267. // create pattern which will indicate whether or not a value needs to be
  268. // quoted or not (contains delimiter, separator, or newline)
  269. Pattern needsQuotePattern = Pattern.compile(
  270. "(?:" + Pattern.quote(delimiter) + ")|(?:" +
  271. Pattern.quote("" + quote) + ")|(?:[\n\r])");
  272. List<Column> origCols = cursor.getTable().getColumns();
  273. List<Column> columns = new ArrayList<Column>(origCols);
  274. columns = filter.filterColumns(columns);
  275. Collection<String> columnNames = null;
  276. if(!origCols.equals(columns)) {
  277. // columns have been filtered
  278. columnNames = new HashSet<String>();
  279. for (Column c : columns) {
  280. columnNames.add(c.getName());
  281. }
  282. }
  283. // print the header row (if desired)
  284. if (header) {
  285. for (Iterator<Column> iter = columns.iterator(); iter.hasNext();) {
  286. writeValue(out, iter.next().getName(), quote, needsQuotePattern);
  287. if (iter.hasNext()) {
  288. out.write(delimiter);
  289. }
  290. }
  291. out.newLine();
  292. }
  293. // print the data rows
  294. Map<String, Object> row;
  295. Object[] unfilteredRowData = new Object[columns.size()];
  296. while ((row = cursor.getNextRow(columnNames)) != null) {
  297. // fill raw row data in array
  298. for (int i = 0; i < columns.size(); i++) {
  299. unfilteredRowData[i] = row.get(columns.get(i).getName());
  300. }
  301. // apply filter
  302. Object[] rowData = filter.filterRow(unfilteredRowData);
  303. // print row
  304. for (int i = 0; i < columns.size(); i++) {
  305. Object obj = rowData[i];
  306. if(obj != null) {
  307. String value = null;
  308. if(obj instanceof byte[]) {
  309. value = ByteUtil.toHexString((byte[])obj);
  310. } else {
  311. value = String.valueOf(rowData[i]);
  312. }
  313. writeValue(out, value, quote, needsQuotePattern);
  314. }
  315. if (i < columns.size() - 1) {
  316. out.write(delimiter);
  317. }
  318. }
  319. out.newLine();
  320. }
  321. out.flush();
  322. }
  323. private static void writeValue(BufferedWriter out, String value, char quote,
  324. Pattern needsQuotePattern)
  325. throws IOException
  326. {
  327. if(!needsQuotePattern.matcher(value).find()) {
  328. // no quotes necessary
  329. out.write(value);
  330. return;
  331. }
  332. // wrap the value in quotes and handle internal quotes
  333. out.write(quote);
  334. for (int i = 0; i < value.length(); ++i) {
  335. char c = value.charAt(i);
  336. if (c == quote) {
  337. out.write(quote);
  338. }
  339. out.write(c);
  340. }
  341. out.write(quote);
  342. }
  343. }