001 package net.sf.cpsolver.ifs.util; 002 003 import java.io.BufferedReader; 004 import java.io.File; 005 import java.io.FileReader; 006 import java.io.FileWriter; 007 import java.io.IOException; 008 import java.io.PrintWriter; 009 import java.io.Serializable; 010 import java.util.Calendar; 011 import java.util.Collection; 012 import java.util.Date; 013 import java.util.Enumeration; 014 import java.util.Hashtable; 015 import java.util.Locale; 016 import java.util.Vector; 017 018 /** Support for CSV (comma separated) text files. 019 * 020 * @version 021 * IFS 1.1 (Iterative Forward Search)<br> 022 * Copyright (C) 2006 Tomáš Müller<br> 023 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 024 * Lazenska 391, 76314 Zlin, Czech Republic<br> 025 * <br> 026 * This library is free software; you can redistribute it and/or 027 * modify it under the terms of the GNU Lesser General Public 028 * License as published by the Free Software Foundation; either 029 * version 2.1 of the License, or (at your option) any later version. 030 * <br><br> 031 * This library is distributed in the hope that it will be useful, 032 * but WITHOUT ANY WARRANTY; without even the implied warranty of 033 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 034 * Lesser General Public License for more details. 035 * <br><br> 036 * You should have received a copy of the GNU Lesser General Public 037 * License along with this library; if not, write to the Free Software 038 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 039 */ 040 041 public class CSVFile implements Serializable { 042 private static final long serialVersionUID = 1L; 043 Hashtable iHeaderMap = null; 044 CSVLine iHeader = null; 045 Vector iLines = null; 046 String iSeparator = ","; 047 String iQuotationMark = "\""; 048 049 public CSVFile() {} 050 051 public CSVFile(File file) throws IOException { 052 load(file); 053 } 054 055 public CSVFile(File file, String separator) throws IOException { 056 setSeparator(separator); 057 load(file); 058 } 059 060 public CSVFile(File file, String separator, String quotationMark) throws IOException { 061 setSeparator(separator); 062 setQuotationMark(quotationMark); 063 load(file); 064 } 065 066 public void setSeparator(String separator) { iSeparator = separator; } 067 public String getSeparator() { return iSeparator; } 068 public void setQuotationMark(String quotationMark) { iQuotationMark = quotationMark; } 069 public String getQuotationMark() { return iQuotationMark; } 070 071 public void load(File file) throws IOException { 072 BufferedReader reader = null; 073 try { 074 reader = new BufferedReader(new FileReader(file)); 075 iHeader = new CSVLine(reader.readLine()); //read header 076 iHeaderMap = new Hashtable(); 077 iLines = new Vector(); 078 int idx = 0; 079 for (Enumeration e=iHeader.fields();e.hasMoreElements();idx++) { 080 CSVField field = (CSVField)e.nextElement(); 081 iHeaderMap.put(field.toString(),new Integer(idx)); 082 } 083 String line = null; 084 while ((line=reader.readLine())!=null) { 085 if (line.trim().length()==0) continue; 086 iLines.addElement(new CSVLine(line)); 087 } 088 } finally { 089 if (reader!=null) reader.close(); 090 } 091 } 092 093 public void save(File file) throws IOException { 094 PrintWriter writer = null; 095 try { 096 writer = new PrintWriter(new FileWriter(file)); 097 if (iHeader!=null) 098 writer.println(iHeader.toString()); 099 100 if (iLines!=null) { 101 for (Enumeration e=iLines.elements();e.hasMoreElements();) { 102 Object line = e.nextElement(); 103 writer.println(line.toString()); 104 } 105 } 106 107 writer.flush(); 108 } finally { 109 if (writer!=null) writer.close(); 110 } 111 } 112 113 public CSVLine getHeader() { return iHeader; } 114 public void setHeader(CSVLine header) { iHeader = header; } 115 public Vector getLines() { return iLines; } 116 public int size() { return iLines.size(); } 117 public boolean isEmpty() { return iLines.isEmpty(); } 118 public CSVLine getLine(int idx) { return (CSVLine)iLines.elementAt(idx); } 119 public Enumeration lines() { return iLines.elements(); } 120 public void addLine(CSVLine line) { 121 if (iLines==null) iLines = new Vector(); 122 iLines.addElement(line); 123 } 124 public void addLine(String line) { 125 if (iLines==null) iLines = new Vector(); 126 iLines.addElement(line); 127 } 128 public Vector filter(CSVFilter filter) { 129 Vector ret = new Vector(); 130 for (Enumeration e=iLines.elements();e.hasMoreElements();) { 131 CSVLine line = (CSVLine)e.nextElement(); 132 if (filter.match(line)) 133 ret.addElement(line); 134 } 135 return ret; 136 } 137 138 public CSVLine addLine() { 139 CSVLine line = new CSVLine(); 140 addLine(line); 141 return line; 142 } 143 public CSVLine addLine(CSVField fields[]) { 144 CSVLine line = new CSVLine(fields); 145 addLine(line); 146 return line; 147 } 148 public CSVLine addLine(Collection fields) { 149 CSVLine line = new CSVLine(fields); 150 addLine(line); 151 return line; 152 } 153 public CSVLine setHeader(CSVField fields[]) { 154 CSVLine header = new CSVLine(fields); 155 setHeader(header); 156 return header; 157 } 158 public CSVLine setHeader(Collection fields) { 159 CSVLine header = new CSVLine(fields); 160 setHeader(header); 161 return header; 162 } 163 164 /** Representation of a line of a CSV file */ 165 public class CSVLine implements Serializable { 166 private static final long serialVersionUID = 1L; 167 Vector iFields = new Vector(iHeader==null?10:iHeader.size()); 168 169 public CSVLine(String line) { 170 int idx = 0; 171 int newIdx = 0; 172 int fromIdx = 0; 173 while ((newIdx = line.indexOf(iSeparator, fromIdx))>=0) { 174 String field = line.substring(idx, newIdx); 175 if (iQuotationMark!=null && field.startsWith(iQuotationMark) && !field.endsWith(iQuotationMark)) { 176 fromIdx = newIdx + iSeparator.length(); 177 continue; 178 } 179 iFields.addElement(new CSVField(field, iQuotationMark)); 180 idx = newIdx + iSeparator.length(); 181 fromIdx = idx; 182 } 183 iFields.addElement(new CSVField(line.substring(idx), iQuotationMark)); 184 } 185 public CSVLine() {} 186 public CSVLine(CSVField fields[]) { 187 for (int i=0;i<fields.length;i++) 188 iFields.addElement(fields[i]); 189 } 190 public CSVLine(Collection fields) { 191 iFields.addAll(fields); 192 } 193 194 public Vector getFields() { return iFields; } 195 public int size() { return iFields.size(); } 196 public boolean isEmpty() { return iFields.isEmpty(); } 197 public CSVField getField(int idx) { 198 try { 199 return (CSVField)iFields.elementAt(idx); 200 } catch (ArrayIndexOutOfBoundsException e) { 201 return null; 202 } 203 } 204 public void setField(int idx, CSVField field) { 205 iFields.setElementAt(field, idx); 206 } 207 public Enumeration fields() { return iFields.elements(); } 208 public CSVField getField(String name) { 209 Integer idx = (Integer)iHeaderMap.get(name); 210 return (idx==null?null:getField(idx.intValue())); 211 } 212 public void setField(String name, CSVField field) { 213 Integer idx = (Integer)iHeaderMap.get(name); 214 if (idx!=null) setField(idx.intValue(), field); 215 } 216 public String toString() { 217 StringBuffer sb = new StringBuffer(); 218 for (Enumeration e=iFields.elements();e.hasMoreElements();) { 219 CSVField field = (CSVField)e.nextElement(); 220 if (field!=null) 221 sb.append((iQuotationMark==null?"":iQuotationMark)+(field==null?"":field.toString())+(iQuotationMark==null?"":iQuotationMark)); 222 if (e.hasMoreElements()) sb.append(iSeparator); 223 } 224 return sb.toString(); 225 } 226 public void debug(int offset, PrintWriter out) { 227 int idx=0; 228 for (Enumeration e=iFields.elements();e.hasMoreElements();idx++) { 229 CSVField field = (CSVField)e.nextElement(); 230 if (field==null || field.toString().length()==0) continue; 231 for (int i=0;i<offset;i++) 232 out.print(" "); 233 out.println(iHeader.getField(idx)+"="+(iQuotationMark==null?"":iQuotationMark)+field+(iQuotationMark==null?"":iQuotationMark)); 234 } 235 } 236 } 237 238 /** Representation of a field of a CSV file */ 239 public static class CSVField implements Serializable { 240 private static final long serialVersionUID = 1L; 241 String iField = null; 242 public CSVField(String field, String quotationMark) { 243 field = field.trim(); 244 if (quotationMark!=null && field.startsWith(quotationMark) && field.endsWith(quotationMark)) 245 field = field.substring(1, field.length()-1); 246 iField = field.trim(); 247 } 248 public CSVField(Object field) { set(field==null?"":field.toString()); } 249 public CSVField(int field) { set(field); } 250 public CSVField(boolean field) { set(field); } 251 public CSVField(double field) { set(field); } 252 public CSVField(long field) { set(field); } 253 public CSVField(float field) { set(field); } 254 255 public void set(Object value) { iField = (value==null?"":value.toString()); } 256 public void set(int value) { iField = String.valueOf(value); } 257 public void set(boolean value) { iField = (value?"1":"0"); } 258 public void set(double value) { iField = String.valueOf(value); } 259 public void set(long value) { iField = String.valueOf(value); } 260 public void set(float value) { iField = String.valueOf(value); } 261 262 public String toString() { return (iField==null?"":iField); } 263 public boolean isEmpty() { return (iField.length()==0); } 264 public int toInt() { return toInt(0); } 265 public int toInt(int defaultValue) { 266 try { 267 return Integer.parseInt(iField); 268 } catch (NumberFormatException e) { 269 return defaultValue; 270 } 271 } 272 public long toLong() { return toLong(0); } 273 public long toLong(long defaultValue) { 274 try { 275 return Long.parseLong(iField); 276 } catch (NumberFormatException e) { 277 return defaultValue; 278 } 279 } 280 public double toDouble() { return toDouble(0); } 281 public double toDouble(double defaultValue) { 282 try { 283 return Double.parseDouble(iField); 284 } catch (NumberFormatException e) { 285 return defaultValue; 286 } 287 } 288 public Date toDate() { 289 int month = Integer.parseInt(iField.substring(0,2)); 290 int day = Integer.parseInt(iField.substring(3,5)); 291 int year = Integer.parseInt(iField.substring(6,8)); 292 Calendar c = Calendar.getInstance(Locale.US); 293 c.set(year,month-1,day,0,0,0); 294 return c.getTime(); 295 } 296 public boolean toBoolean() { return "Y".equalsIgnoreCase(iField) || "on".equalsIgnoreCase(iField) || "true".equalsIgnoreCase(iField) || "1".equalsIgnoreCase(iField); } 297 } 298 299 /** An interface for filtering lines of a CSV file */ 300 public static interface CSVFilter { 301 public boolean match(CSVLine line); 302 } 303 304 public static CSVFilter eq(String name, String value) { 305 return (new CSVFilter() { 306 String n,v; 307 public boolean match(CSVLine line) { 308 return line.getField(n).equals(v); 309 } 310 private CSVFilter set(String n, String v) { this.n=n; this.v=v; return this; } 311 }).set(name, value); 312 } 313 314 public static CSVFilter and(CSVFilter first, CSVFilter second) { 315 return (new CSVFilter() { 316 CSVFilter a,b; 317 public boolean match(CSVLine line) { 318 return a.match(line) && b.match(line); 319 } 320 private CSVFilter set(CSVFilter a, CSVFilter b) { this.a=a; this.b=b; return this; } 321 }).set(first, second); 322 } 323 324 public static CSVFilter or(CSVFilter first, CSVFilter second) { 325 return (new CSVFilter() { 326 CSVFilter a,b; 327 public boolean match(CSVLine line) { 328 return a.match(line) || b.match(line); 329 } 330 private CSVFilter set(CSVFilter a, CSVFilter b) { this.a=a; this.b=b; return this; } 331 }).set(first, second); 332 } 333 334 public static CSVFilter not(CSVFilter filter) { 335 return (new CSVFilter() { 336 CSVFilter f; 337 public boolean match(CSVLine line) { 338 return !f.match(line); 339 } 340 private CSVFilter set(CSVFilter f) { this.f=f; return this; } 341 }).set(filter); 342 } 343 }