All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.beanio.stream.fixedlength.FixedLengthReader Maven / Gradle / Ivy

Go to download

A Java un/marshalling library for CSV, XML, delimited and fixed length stream formats.

There is a newer version: 2.1.0
Show newest version
/*
 * Copyright 2010-2011 Kevin Seim
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.beanio.stream.fixedlength;

import java.io.*;

import org.beanio.stream.*;
import org.beanio.stream.util.CommentReader;

/**
 * A FixedLengthReader is used to read records from a fixed length
 * file or input stream.  A fixed length record is represented using the
 * {@link String} class.  Records must be terminated by a single 
 * configurable character, or by default, any of the following: line feed (LF), 
 * carriage return (CR), or CRLF combination.
 * 

* If a record may span multiple lines, a single line continuation * character may be configured. The line continuation character must immediately * precede the record termination character. Note that line continuation characters * are not included in the record text. * * @author Kevin Seim * @since 1.0 */ public class FixedLengthReader implements RecordReader { private char lineContinuationChar = '\\'; private boolean multilineEnabled = false; private char recordTerminator = 0; private CommentReader commentReader = null; private transient Reader in; private transient String recordText; private transient int recordLineNumber; private transient int lineNumber = 0; private transient boolean skipLF = false; private transient boolean eof = false; /** * Constructs a new FixedLengthReader. By default, line * continuation is disabled. * @param in the input stream to read from */ public FixedLengthReader(Reader in) { this(in, (FixedLengthParserConfiguration) null); } /** * Constructs a new FixedLengthReader. * @param in the input stream to read from * @param config the reader configuration settings or null to accept defaults * @throws IllegalArgumentException if a configuration setting is invalid * @since 1.2 */ public FixedLengthReader(Reader in, FixedLengthParserConfiguration config) throws IllegalArgumentException { if (config == null) { config = new FixedLengthParserConfiguration(); } this.in = in; if (config.getRecordTerminator() != null) { String s = config.getRecordTerminator(); if ("\n\r".equals(s)) { // use default } else if (s.length() == 1) { this.recordTerminator = s.charAt(0); } else if (s.length() > 1) { throw new IllegalArgumentException("Record terminator must be a single character"); } } if (config.getLineContinuationCharacter() == null) { this.multilineEnabled = false; } else { this.multilineEnabled = true; this.lineContinuationChar = config.getLineContinuationCharacter(); if (recordTerminator != 0 && lineContinuationChar == recordTerminator) { throw new IllegalArgumentException("The line continuation character and record terminator cannot match."); } } if (config.isCommentEnabled()) { commentReader = new CommentReader(in, config.getComments(), this.recordTerminator); } } /* * (non-Javadoc) * @see org.beanio.line.RecordReader#getRecordLineNumber() */ public int getRecordLineNumber() { if (recordLineNumber < 0) { return recordLineNumber; } return recordTerminator == 0 ? recordLineNumber : 0; } /* * (non-Javadoc) * @see org.beanio.line.RecordReader#getRecordText() */ public String getRecordText() { return recordText; } /* * (non-Javadoc) * @see org.beanio.line.RecordReader#read() */ public String read() throws IOException, RecordIOException { if (eof) { recordText = null; recordLineNumber = -1; return null; } ++lineNumber; // skip commented lines if (commentReader != null) { int lines = commentReader.skipComments(skipLF); if (lines > 0) { if (commentReader.isEOF()) { eof = true; recordText = null; recordLineNumber = -1; return null; } else { lineNumber += lines; skipLF = commentReader.isSkipLF(); } } } int lineOffset = 0; boolean continued = false; // line continuation boolean eol = false; // end of record flag StringBuilder text = new StringBuilder(); StringBuilder record = new StringBuilder(); int n; while (!eol && (n = in.read()) != -1) { char c = (char) n; // skip '\n' after a '\r' if (skipLF) { skipLF = false; if (c == '\n') { continue; } } // handle line continuation if (continued) { continued = false; text.append(c); if (endOfRecord(c)) { ++lineNumber; ++lineOffset; continue; } else { record.append(lineContinuationChar); } } if (multilineEnabled && c == lineContinuationChar) { continued = true; } else if (endOfRecord(c)) { eol = true; } else { text.append(c); record.append(c); } } // update the record line number recordLineNumber = lineNumber - lineOffset; recordText = text.toString(); // if eol is true, we're done; if not, then the end of file was reached // and further validation is needed if (eol) { return record.toString(); } if (continued) { throw new RecordIOException("Unexpected end of stream after line continuation at line " + lineNumber); } if (recordText.length() == 0) { eof = true; recordText = null; recordLineNumber = -1; return null; } else { eof = true; return record.toString(); } } /** * Returns true if the given character matches the record separator. This * method also updates the internal skipLF flag. * @param c the character to test * @return true if the character signifies the end of the record */ private boolean endOfRecord(char c) { if (recordTerminator == 0) { if (c == '\r') { skipLF = true; return true; } else if (c == '\n') { return true; } return false; } else { return c == recordTerminator; } } /* * (non-Javadoc) * @see org.beanio.line.RecordReader#close() */ public void close() throws IOException { in.close(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy