Coverage Report - net.sf.jmatchparser.util.csv.FixedWidthCSVReader
 
Classes in this File Line Coverage Branch Coverage Complexity
FixedWidthCSVReader
50%
35/70
42%
12/28
2,176
 
 1  
 /*
 2  
  * Copyright (c) 2010 - 2011 Michael Schierl
 3  
  * 
 4  
  * All rights reserved.
 5  
  * 
 6  
  * Redistribution and use in source and binary forms, with or without
 7  
  * modification, are permitted provided that the following conditions
 8  
  * are met:
 9  
  * 
 10  
  * - Redistributions of source code must retain the above copyright notice,
 11  
  *   this list of conditions and the following disclaimer.
 12  
  *   
 13  
  * - Redistributions in binary form must reproduce the above copyright
 14  
  *   notice, this list of conditions and the following disclaimer in the
 15  
  *   documentation and/or other materials provided with the distribution.
 16  
  *   
 17  
  * - Neither name of the copyright holders nor the names of its
 18  
  *   contributors may be used to endorse or promote products derived from
 19  
  *   this software without specific prior written permission.
 20  
  *   
 21  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND THE CONTRIBUTORS
 22  
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 23  
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 24  
  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 25  
  * HOLDERS OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 26  
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 27  
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 28  
  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 29  
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 30  
  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 31  
  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 32  
  */
 33  
 package net.sf.jmatchparser.util.csv;
 34  
 
 35  
 import java.io.BufferedReader;
 36  
 import java.io.IOException;
 37  
 import java.io.InputStream;
 38  
 import java.io.InputStreamReader;
 39  
 import java.io.Reader;
 40  
 import java.io.UnsupportedEncodingException;
 41  
 
 42  
 /**
 43  
  * Class to read data from a fixed width CSV (Comma Separated Value) file, where
 44  
  * every column has a fixed width and may optionally additionally delimited by
 45  
  * separator characters.
 46  
  */
 47  
 public class FixedWidthCSVReader extends AbstractCSVReader {
 48  
 
 49  
         private final BufferedReader br;
 50  
         private final String prefix;
 51  
         private final String separator;
 52  
         private final String suffix;
 53  
         private final FixedWidthColumn[] columns;
 54  
         private final int lineLength;
 55  1
         private boolean stripComments = false;
 56  
 
 57  
         /**
 58  
          * Create a new {@link FixedWidthCSVReader} that reads from the given
 59  
          * buffered reader using left-aligned space-padded columns only and no
 60  
          * separators.
 61  
          * 
 62  
          * @param br
 63  
          *            The buffered reader to read from
 64  
          * @param widths
 65  
          *            The width of each column
 66  
          */
 67  
         public FixedWidthCSVReader(BufferedReader br, int... widths) {
 68  0
                 this(br, buildColumns(widths));
 69  0
         }
 70  
 
 71  
         static FixedWidthColumn[] buildColumns(int[] widths) {
 72  0
                 FixedWidthColumn[] result = new FixedWidthColumn[widths.length];
 73  0
                 for (int i = 0; i < widths.length; i++) {
 74  0
                         result[i] = new FixedWidthColumn(widths[i]);
 75  
                 }
 76  0
                 return result;
 77  
         }
 78  
 
 79  
         /**
 80  
          * Create a new {@link FixedWidthCSVReader} that reads from the given
 81  
          * buffered reader using columns parsed from the given column specs and no
 82  
          * separators.
 83  
          * 
 84  
          * @param br
 85  
          *            The buffered reader to read from
 86  
          * @param columnSpecs
 87  
          *            The format specification of each column
 88  
          */
 89  
         public FixedWidthCSVReader(BufferedReader br, String... columnSpecs) throws IOException {
 90  0
                 this(br, buildColumns(columnSpecs));
 91  0
         }
 92  
 
 93  
         static FixedWidthColumn[] buildColumns(String[] columnSpecs) {
 94  0
                 FixedWidthColumn[] result = new FixedWidthColumn[columnSpecs.length];
 95  0
                 for (int i = 0; i < columnSpecs.length; i++) {
 96  0
                         result[i] = FixedWidthColumn.parse(columnSpecs[i]);
 97  
                 }
 98  0
                 return result;
 99  
         }
 100  
 
 101  
         /**
 102  
          * Create a new {@link FixedWidthCSVReader} that reads from the given
 103  
          * buffered reader using the given columns and no separators.
 104  
          * 
 105  
          * @param br
 106  
          *            The buffered reader to read from
 107  
          * @param columns
 108  
          *            The format of each column
 109  
          */
 110  
         public FixedWidthCSVReader(BufferedReader br, FixedWidthColumn... columns) {
 111  0
                 this(br, "", "", "", columns);
 112  0
         }
 113  
 
 114  
         /**
 115  
          * Create a new {@link FixedWidthCSVReader} that reads from the given
 116  
          * buffered reader using the given columns and separators.
 117  
          * 
 118  
          * @param br
 119  
          *            The buffered reader to read from
 120  
          * @param prefix
 121  
          *            The prefix to add to each line
 122  
          * @param separator
 123  
          *            The separator to add between each field
 124  
          * @param suffix
 125  
          *            The suffix to add to each line
 126  
          * @param columns
 127  
          *            The format of each column
 128  
          */
 129  1
         public FixedWidthCSVReader(BufferedReader br, String prefix, String separator, String suffix, FixedWidthColumn... columns) {
 130  1
                 this.br = br;
 131  1
                 this.prefix = prefix;
 132  1
                 this.separator = separator;
 133  1
                 this.suffix = suffix;
 134  1
                 this.columns = columns;
 135  1
                 int lineLength = prefix.length() + suffix.length() + separator.length() * (columns.length - 1);
 136  3
                 for (int i = 0; i < columns.length; i++) {
 137  2
                         lineLength += columns[i].getWidth();
 138  
                 }
 139  1
                 this.lineLength = lineLength;
 140  1
         }
 141  
 
 142  
         /**
 143  
          * Create a new {@link FixedWidthCSVReader} that reads from the given reader
 144  
          * using left-aligned space-padded columns only and no separators.
 145  
          * 
 146  
          * @param r
 147  
          *            The reader to read from
 148  
          * @param widths
 149  
          *            The width of each column
 150  
          */
 151  
         public FixedWidthCSVReader(Reader r, int... widths) {
 152  0
                 this(new BufferedReader(r), widths);
 153  0
         }
 154  
 
 155  
         /**
 156  
          * Create a new {@link FixedWidthCSVReader} that reads from the given reader
 157  
          * using columns parsed from the given column specs and no separators.
 158  
          * 
 159  
          * @param r
 160  
          *            The reader to read from
 161  
          * @param columnSpecs
 162  
          *            The format specification of each column
 163  
          */
 164  
         public FixedWidthCSVReader(Reader r, String... columnSpecs) throws IOException {
 165  0
                 this(new BufferedReader(r), columnSpecs);
 166  0
         }
 167  
 
 168  
         /**
 169  
          * Create a new {@link FixedWidthCSVReader} that reads from the given reader
 170  
          * using the given columns and no separators.
 171  
          * 
 172  
          * @param r
 173  
          *            The reader to read from
 174  
          * @param columns
 175  
          *            The format of each column
 176  
          */
 177  
         public FixedWidthCSVReader(Reader r, FixedWidthColumn... columns) {
 178  0
                 this(new BufferedReader(r), columns);
 179  0
         }
 180  
 
 181  
         /**
 182  
          * Create a new {@link FixedWidthCSVReader} that reads from the given reader
 183  
          * using the given columns and separators.
 184  
          * 
 185  
          * @param r
 186  
          *            The reader to read from
 187  
          * @param prefix
 188  
          *            The prefix to add to each line
 189  
          * @param separator
 190  
          *            The separator to add between each field
 191  
          * @param suffix
 192  
          *            The suffix to add to each line
 193  
          * @param columns
 194  
          *            The format of each column
 195  
          */
 196  
         public FixedWidthCSVReader(Reader r, String prefix, String separator, String suffix, FixedWidthColumn... columns) {
 197  1
                 this(new BufferedReader(r), prefix, separator, suffix, columns);
 198  1
         }
 199  
 
 200  
         /**
 201  
          * Create a new {@link FixedWidthCSVReader} that reads from the given stream
 202  
          * using left-aligned space-padded columns only and no separators.
 203  
          * 
 204  
          * @param in
 205  
          *            The input stream to read from
 206  
          * @param charsetName
 207  
          *            Name of the charset to be used
 208  
          * @param widths
 209  
          *            The width of each column
 210  
          */
 211  
         public FixedWidthCSVReader(InputStream in, String charsetName, int... widths) throws UnsupportedEncodingException {
 212  0
                 this(new InputStreamReader(in, charsetName), widths);
 213  0
         }
 214  
 
 215  
         /**
 216  
          * Create a new {@link FixedWidthCSVReader} that reads from the given stream
 217  
          * using columns parsed from the given column specs and no separators.
 218  
          * 
 219  
          * @param in
 220  
          *            The input stream to read from
 221  
          * @param charsetName
 222  
          *            Name of the charset to be used
 223  
          * @param columnSpecs
 224  
          *            The format specification of each column
 225  
          */
 226  
         public FixedWidthCSVReader(InputStream in, String charsetName, String... columnSpecs) throws IOException {
 227  0
                 this(new InputStreamReader(in, charsetName), columnSpecs);
 228  0
         }
 229  
 
 230  
         /**
 231  
          * Create a new {@link FixedWidthCSVReader} that reads from the given stream
 232  
          * using the given columns and no separators.
 233  
          * 
 234  
          * @param in
 235  
          *            The input stream to read from
 236  
          * @param charsetName
 237  
          *            Name of the charset to be used
 238  
          * @param columns
 239  
          *            The format of each column
 240  
          */
 241  
         public FixedWidthCSVReader(InputStream in, String charsetName, FixedWidthColumn... columns) throws UnsupportedEncodingException {
 242  0
                 this(new InputStreamReader(in, charsetName), columns);
 243  0
         }
 244  
 
 245  
         /**
 246  
          * Create a new {@link FixedWidthCSVReader} that reads from the given stream
 247  
          * using the given columns and separators.
 248  
          * 
 249  
          * @param in
 250  
          *            The input stream to read from
 251  
          * @param charsetName
 252  
          *            Name of the charset to be used
 253  
          * @param prefix
 254  
          *            The prefix to add to each line
 255  
          * @param separator
 256  
          *            The separator to add between each field
 257  
          * @param suffix
 258  
          *            The suffix to add to each line
 259  
          * @param columns
 260  
          *            The format of each column
 261  
          */
 262  
         public FixedWidthCSVReader(InputStream in, String charsetName, String prefix, String separator, String suffix, FixedWidthColumn... columns) throws UnsupportedEncodingException {
 263  1
                 this(new InputStreamReader(in, charsetName), prefix, separator, suffix, columns);
 264  1
         }
 265  
 
 266  
         @Override
 267  
         public void close() throws IOException {
 268  0
                 br.close();
 269  0
         }
 270  
 
 271  
         /**
 272  
          * Set whether comments (lines starting with # or empty lines) should be
 273  
          * stripped.
 274  
          */
 275  
         public void setStripComments(boolean stripComments) {
 276  1
                 this.stripComments = stripComments;
 277  1
         }
 278  
 
 279  
         /**
 280  
          * Read a line from the fixed width CSV file.
 281  
          */
 282  
         @Override
 283  
         public String[] read() throws IOException {
 284  3
                 String line = br.readLine();
 285  3
                 if (stripComments) {
 286  0
                         while (line != null && (line.startsWith("#") || line.length() == 0))
 287  0
                                 line = br.readLine();
 288  
                 }
 289  3
                 if (line == null)
 290  1
                         return null;
 291  2
                 if (line.length() != lineLength)
 292  0
                         throw new IOException("Invalid line length: " + line);
 293  2
                 if (!line.startsWith(prefix))
 294  0
                         throw new IOException("Invalid prefix: " + line);
 295  2
                 if (!line.endsWith(suffix))
 296  0
                         throw new IOException("Invalid suffix: " + line);
 297  2
                 final String origLine = line;
 298  2
                 line = separator + line.substring(prefix.length(), line.length() - suffix.length());
 299  2
                 String[] elems = new String[columns.length];
 300  6
                 for (int i = 0; i < elems.length; i++) {
 301  4
                         if (!line.startsWith(separator))
 302  0
                                 throw new IOException("Separator for column " + i + " missing: " + line);
 303  4
                         line = line.substring(separator.length());
 304  4
                         elems[i] = columns[i].parseValue(line.substring(0, columns[i].getWidth()));
 305  4
                         line = line.substring(columns[i].getWidth());
 306  
                 }
 307  2
                 if (line.length() != 0)
 308  0
                         throw new RuntimeException("Lengths did not add up: " + origLine);
 309  2
                 return elems;
 310  
         }
 311  
 }