Change CSVFormat#Iterable<CSVRecord> parse(final Reader in) to return a CSVParser, which is compatible since CSVParser implements Iterable<CSVRecord>. This allows a caller to end the parsing by calling CSVParser#close() or to use CSVParser in a Java 7 try-with-resources, without tracking a reader or input stream.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/csv/trunk@1508509 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Gary D. Gregory 2013-07-30 16:22:07 +00:00
parent 7af334d7d5
commit f78b5a14ca
5 changed files with 72 additions and 21 deletions

View File

@ -449,16 +449,16 @@ public class CSVFormat implements Serializable {
return quoteChar != null;
}
/**
* Parses the specified content.
*
* @param in
* the input stream
* @return a stream of CSVRecord
* @throws IOException
* If an I/O error occurs
*/
public Iterable<CSVRecord> parse(final Reader in) throws IOException {
/**
* Parses the specified content.
*
* @param in
* the input stream
* @return a parser over a stream of {@link #CSVRecord}s.
* @throws IOException
* If an I/O error occurs
*/
public CSVParser parse(final Reader in) throws IOException {
return new CSVParser(in, this);
}

View File

@ -236,6 +236,9 @@ public class CSVParser implements Iterable<CSVRecord>, Closeable {
/**
* Closes resources.
*
* @throws IOException
* If an I/O error occurs
*/
public void close() throws IOException {
if (lexer != null) {
@ -309,6 +312,9 @@ public class CSVParser implements Iterable<CSVRecord>, Closeable {
}
public boolean hasNext() {
if (isClosed()) {
return false;
}
if (current == null) {
current = getNextRecord();
}
@ -317,6 +323,9 @@ public class CSVParser implements Iterable<CSVRecord>, Closeable {
}
public CSVRecord next() {
if (isClosed()) {
return null;
}
CSVRecord next = current;
current = null;
@ -337,4 +346,8 @@ public class CSVParser implements Iterable<CSVRecord>, Closeable {
};
}
public boolean isClosed() {
return lexer.isClosed();
}
}

View File

@ -41,6 +41,8 @@ final class ExtendedBufferedReader extends BufferedReader {
/** The count of EOLs (CR/LF/CRLF) seen so far */
private long eolCounter = 0;
private boolean closed;
/**
* Created extended buffered reader using default buffer-size
@ -154,4 +156,23 @@ final class ExtendedBufferedReader extends BufferedReader {
}
return eolCounter + 1; // Allow for counter being incremented only at EOL
}
public boolean isClosed() {
return closed;
}
/**
* Closes the stream.
*
* @throws IOException
* If an I/O error occurs
*/
@Override
public void close() throws IOException {
// Set ivars before calling super close() in case close() throws an IOException.
closed = true;
lastChar = END_OF_STREAM;
super.close();
}
}

View File

@ -148,6 +148,10 @@ abstract class Lexer implements Closeable {
abstract Token nextToken(Token reusableToken) throws IOException;
boolean isClosed() {
return in.isClosed();
}
/**
* @return true if the given char is a whitespace character
*/
@ -197,10 +201,11 @@ abstract class Lexer implements Closeable {
/**
* Closes resources.
*
* @throws IOException
* If an I/O error occurs
*/
public void close() throws IOException {
if (in != null) {
in.close();
}
in.close();
}
}

View File

@ -39,7 +39,6 @@ import java.util.Map;
import java.util.NoSuchElementException;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
@ -395,6 +394,19 @@ public class CSVParserTest {
assertEquals(4, records.size());
}
@Test
public void testClose() throws Exception {
final Reader in = new StringReader("# comment\na,b,c\n1,2,3\nx,y,z");
final CSVParser parser = CSVFormat.DEFAULT.withCommentStart('#').withHeader().parse(in);
final Iterator<CSVRecord> records = parser.iterator();
assertTrue(records.hasNext());
parser.close();
assertFalse(records.hasNext());
assertNull(records.next());
assertFalse(records.hasNext());
assertNull(records.next());
}
@Test
public void testCarriageReturnEndings() throws IOException {
final String code = "foo\rbaar,\rhello,world\r,kanu";
@ -605,22 +617,22 @@ public class CSVParserTest {
@Test
public void testGetLineNumberWithLF() throws Exception {
validateLineNumbers(String.valueOf(LF));
this.validateLineNumbers(String.valueOf(LF));
}
@Test
public void testGetLineNumberWithCRLF() throws Exception {
validateLineNumbers(CRLF);
this.validateLineNumbers(CRLF);
}
@Test
public void testGetLineNumberWithCR() throws Exception {
validateLineNumbers(String.valueOf(CR));
this.validateLineNumbers(String.valueOf(CR));
}
@Test
public void testGetRecordNumberWithLF() throws Exception {
validateRecordNumbers(String.valueOf(LF));
this.validateRecordNumbers(String.valueOf(LF));
}
@Test
@ -649,17 +661,17 @@ public class CSVParserTest {
@Test
public void testGetRecordNumberWithCRLF() throws Exception {
validateRecordNumbers(CRLF);
this.validateRecordNumbers(CRLF);
}
@Test
public void testGetRecordNumberWithCR() throws Exception {
validateRecordNumbers(String.valueOf(CR));
this.validateRecordNumbers(String.valueOf(CR));
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidFormat() throws Exception {
CSVFormat invalidFormat = CSVFormat.DEFAULT.withDelimiter(CR);
final CSVFormat invalidFormat = CSVFormat.DEFAULT.withDelimiter(CR);
new CSVParser((Reader) null, invalidFormat);
}