001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * -------- 028 * CSV.java 029 * -------- 030 * (C) Copyright 2003-2008, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * Changes 036 * ------- 037 * 24-Nov-2003 : Version 1 (DG); 038 * 039 */ 040 041package org.jfree.data.io; 042 043import java.io.BufferedReader; 044import java.io.IOException; 045import java.io.Reader; 046import java.util.List; 047 048import org.jfree.data.category.CategoryDataset; 049import org.jfree.data.category.DefaultCategoryDataset; 050 051/** 052 * A utility class for reading {@link CategoryDataset} data from a CSV file. 053 * This initial version is very basic, and won't handle errors in the data 054 * file very gracefully. 055 */ 056public class CSV { 057 058 /** The field delimiter. */ 059 private char fieldDelimiter; 060 061 /** The text delimiter. */ 062 private char textDelimiter; 063 064 /** 065 * Creates a new CSV reader where the field delimiter is a comma, and the 066 * text delimiter is a double-quote. 067 */ 068 public CSV() { 069 this(',', '"'); 070 } 071 072 /** 073 * Creates a new reader with the specified field and text delimiters. 074 * 075 * @param fieldDelimiter the field delimiter (usually a comma, semi-colon, 076 * colon, tab or space). 077 * @param textDelimiter the text delimiter (usually a single or double 078 * quote). 079 */ 080 public CSV(char fieldDelimiter, char textDelimiter) { 081 this.fieldDelimiter = fieldDelimiter; 082 this.textDelimiter = textDelimiter; 083 } 084 085 /** 086 * Reads a {@link CategoryDataset} from a CSV file or input source. 087 * 088 * @param in the input source. 089 * 090 * @return A category dataset. 091 * 092 * @throws IOException if there is an I/O problem. 093 */ 094 public CategoryDataset readCategoryDataset(Reader in) throws IOException { 095 096 DefaultCategoryDataset dataset = new DefaultCategoryDataset(); 097 BufferedReader reader = new BufferedReader(in); 098 List columnKeys = null; 099 int lineIndex = 0; 100 String line = reader.readLine(); 101 while (line != null) { 102 if (lineIndex == 0) { // first line contains column keys 103 columnKeys = extractColumnKeys(line); 104 } 105 else { // remaining lines contain a row key and data values 106 extractRowKeyAndData(line, dataset, columnKeys); 107 } 108 line = reader.readLine(); 109 lineIndex++; 110 } 111 return dataset; 112 113 } 114 115 /** 116 * Extracts the column keys from a string. 117 * 118 * @param line a line from the input file. 119 * 120 * @return A list of column keys. 121 */ 122 private List extractColumnKeys(String line) { 123 List keys = new java.util.ArrayList(); 124 int fieldIndex = 0; 125 int start = 0; 126 for (int i = 0; i < line.length(); i++) { 127 if (line.charAt(i) == this.fieldDelimiter) { 128 if (fieldIndex > 0) { // first field is ignored, since 129 // column 0 is for row keys 130 String key = line.substring(start, i); 131 keys.add(removeStringDelimiters(key)); 132 } 133 start = i + 1; 134 fieldIndex++; 135 } 136 } 137 String key = line.substring(start, line.length()); 138 keys.add(removeStringDelimiters(key)); 139 return keys; 140 } 141 142 /** 143 * Extracts the row key and data for a single line from the input source. 144 * 145 * @param line the line from the input source. 146 * @param dataset the dataset to be populated. 147 * @param columnKeys the column keys. 148 */ 149 private void extractRowKeyAndData(String line, 150 DefaultCategoryDataset dataset, 151 List columnKeys) { 152 Comparable rowKey = null; 153 int fieldIndex = 0; 154 int start = 0; 155 for (int i = 0; i < line.length(); i++) { 156 if (line.charAt(i) == this.fieldDelimiter) { 157 if (fieldIndex == 0) { // first field contains the row key 158 String key = line.substring(start, i); 159 rowKey = removeStringDelimiters(key); 160 } 161 else { // remaining fields contain values 162 Double value = Double.valueOf( 163 removeStringDelimiters(line.substring(start, i)) 164 ); 165 dataset.addValue( 166 value, rowKey, 167 (Comparable) columnKeys.get(fieldIndex - 1) 168 ); 169 } 170 start = i + 1; 171 fieldIndex++; 172 } 173 } 174 Double value = Double.valueOf( 175 removeStringDelimiters(line.substring(start, line.length())) 176 ); 177 dataset.addValue( 178 value, rowKey, (Comparable) columnKeys.get(fieldIndex - 1) 179 ); 180 } 181 182 /** 183 * Removes the string delimiters from a key (as well as any white space 184 * outside the delimiters). 185 * 186 * @param key the key (including delimiters). 187 * 188 * @return The key without delimiters. 189 */ 190 private String removeStringDelimiters(String key) { 191 String k = key.trim(); 192 if (k.charAt(0) == this.textDelimiter) { 193 k = k.substring(1); 194 } 195 if (k.charAt(k.length() - 1) == this.textDelimiter) { 196 k = k.substring(0, k.length() - 1); 197 } 198 return k; 199 } 200 201}