001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-present, by David Gilbert 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-present, by David Gilbert. 031 * 032 * Original Author: David Gilbert; 033 * Contributor(s): -; 034 * 035 */ 036 037package org.jfree.data.io; 038 039import java.io.BufferedReader; 040import java.io.IOException; 041import java.io.Reader; 042import java.util.List; 043 044import org.jfree.data.category.CategoryDataset; 045import org.jfree.data.category.DefaultCategoryDataset; 046 047/** 048 * A utility class for reading {@link CategoryDataset} data from a CSV file. 049 * This initial version is very basic, and won't handle errors in the data 050 * file very gracefully. 051 */ 052public class CSV { 053 054 /** The field delimiter. */ 055 private char fieldDelimiter; 056 057 /** The text delimiter. */ 058 private char textDelimiter; 059 060 /** 061 * Creates a new CSV reader where the field delimiter is a comma, and the 062 * text delimiter is a double-quote. 063 */ 064 public CSV() { 065 this(',', '"'); 066 } 067 068 /** 069 * Creates a new reader with the specified field and text delimiters. 070 * 071 * @param fieldDelimiter the field delimiter (usually a comma, semi-colon, 072 * colon, tab or space). 073 * @param textDelimiter the text delimiter (usually a single or double 074 * quote). 075 */ 076 public CSV(char fieldDelimiter, char textDelimiter) { 077 this.fieldDelimiter = fieldDelimiter; 078 this.textDelimiter = textDelimiter; 079 } 080 081 /** 082 * Reads a {@link CategoryDataset} from a CSV file or input source. 083 * 084 * @param in the input source. 085 * 086 * @return A category dataset. 087 * 088 * @throws IOException if there is an I/O problem. 089 */ 090 public CategoryDataset readCategoryDataset(Reader in) throws IOException { 091 092 DefaultCategoryDataset dataset = new DefaultCategoryDataset(); 093 BufferedReader reader = new BufferedReader(in); 094 List columnKeys = null; 095 int lineIndex = 0; 096 String line = reader.readLine(); 097 while (line != null) { 098 if (lineIndex == 0) { // first line contains column keys 099 columnKeys = extractColumnKeys(line); 100 } 101 else { // remaining lines contain a row key and data values 102 extractRowKeyAndData(line, dataset, columnKeys); 103 } 104 line = reader.readLine(); 105 lineIndex++; 106 } 107 return dataset; 108 109 } 110 111 /** 112 * Extracts the column keys from a string. 113 * 114 * @param line a line from the input file. 115 * 116 * @return A list of column keys. 117 */ 118 private List extractColumnKeys(String line) { 119 List keys = new java.util.ArrayList(); 120 int fieldIndex = 0; 121 int start = 0; 122 for (int i = 0; i < line.length(); i++) { 123 if (line.charAt(i) == this.fieldDelimiter) { 124 if (fieldIndex > 0) { // first field is ignored, since 125 // column 0 is for row keys 126 String key = line.substring(start, i); 127 keys.add(removeStringDelimiters(key)); 128 } 129 start = i + 1; 130 fieldIndex++; 131 } 132 } 133 String key = line.substring(start); 134 keys.add(removeStringDelimiters(key)); 135 return keys; 136 } 137 138 /** 139 * Extracts the row key and data for a single line from the input source. 140 * 141 * @param line the line from the input source. 142 * @param dataset the dataset to be populated. 143 * @param columnKeys the column keys. 144 */ 145 private void extractRowKeyAndData(String line, 146 DefaultCategoryDataset dataset, 147 List columnKeys) { 148 Comparable rowKey = null; 149 int fieldIndex = 0; 150 int start = 0; 151 for (int i = 0; i < line.length(); i++) { 152 if (line.charAt(i) == this.fieldDelimiter) { 153 if (fieldIndex == 0) { // first field contains the row key 154 String key = line.substring(start, i); 155 rowKey = removeStringDelimiters(key); 156 } 157 else { // remaining fields contain values 158 Double value = Double.valueOf( 159 removeStringDelimiters(line.substring(start, i)) 160 ); 161 dataset.addValue( 162 value, rowKey, 163 (Comparable) columnKeys.get(fieldIndex - 1) 164 ); 165 } 166 start = i + 1; 167 fieldIndex++; 168 } 169 } 170 Double value = Double.valueOf( 171 removeStringDelimiters(line.substring(start)) 172 ); 173 dataset.addValue( 174 value, rowKey, (Comparable) columnKeys.get(fieldIndex - 1) 175 ); 176 } 177 178 /** 179 * Removes the string delimiters from a key (as well as any white space 180 * outside the delimiters). 181 * 182 * @param key the key (including delimiters). 183 * 184 * @return The key without delimiters. 185 */ 186 private String removeStringDelimiters(String key) { 187 String k = key.trim(); 188 if (k.charAt(0) == this.textDelimiter) { 189 k = k.substring(1); 190 } 191 if (k.charAt(k.length() - 1) == this.textDelimiter) { 192 k = k.substring(0, k.length() - 1); 193 } 194 return k; 195 } 196 197}