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:
parent
7af334d7d5
commit
f78b5a14ca
|
@ -454,11 +454,11 @@ public class CSVFormat implements Serializable {
|
||||||
*
|
*
|
||||||
* @param in
|
* @param in
|
||||||
* the input stream
|
* the input stream
|
||||||
* @return a stream of CSVRecord
|
* @return a parser over a stream of {@link #CSVRecord}s.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* If an I/O error occurs
|
* If an I/O error occurs
|
||||||
*/
|
*/
|
||||||
public Iterable<CSVRecord> parse(final Reader in) throws IOException {
|
public CSVParser parse(final Reader in) throws IOException {
|
||||||
return new CSVParser(in, this);
|
return new CSVParser(in, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,6 +236,9 @@ public class CSVParser implements Iterable<CSVRecord>, Closeable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes resources.
|
* Closes resources.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* If an I/O error occurs
|
||||||
*/
|
*/
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (lexer != null) {
|
if (lexer != null) {
|
||||||
|
@ -309,6 +312,9 @@ public class CSVParser implements Iterable<CSVRecord>, Closeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
|
if (isClosed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (current == null) {
|
if (current == null) {
|
||||||
current = getNextRecord();
|
current = getNextRecord();
|
||||||
}
|
}
|
||||||
|
@ -317,6 +323,9 @@ public class CSVParser implements Iterable<CSVRecord>, Closeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CSVRecord next() {
|
public CSVRecord next() {
|
||||||
|
if (isClosed()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
CSVRecord next = current;
|
CSVRecord next = current;
|
||||||
current = null;
|
current = null;
|
||||||
|
|
||||||
|
@ -337,4 +346,8 @@ public class CSVParser implements Iterable<CSVRecord>, Closeable {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return lexer.isClosed();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,8 @@ final class ExtendedBufferedReader extends BufferedReader {
|
||||||
/** The count of EOLs (CR/LF/CRLF) seen so far */
|
/** The count of EOLs (CR/LF/CRLF) seen so far */
|
||||||
private long eolCounter = 0;
|
private long eolCounter = 0;
|
||||||
|
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created extended buffered reader using default buffer-size
|
* 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
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,6 +148,10 @@ abstract class Lexer implements Closeable {
|
||||||
|
|
||||||
abstract Token nextToken(Token reusableToken) throws IOException;
|
abstract Token nextToken(Token reusableToken) throws IOException;
|
||||||
|
|
||||||
|
boolean isClosed() {
|
||||||
|
return in.isClosed();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the given char is a whitespace character
|
* @return true if the given char is a whitespace character
|
||||||
*/
|
*/
|
||||||
|
@ -197,10 +201,11 @@ abstract class Lexer implements Closeable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes resources.
|
* Closes resources.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* If an I/O error occurs
|
||||||
*/
|
*/
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (in != null) {
|
|
||||||
in.close();
|
in.close();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -395,6 +394,19 @@ public class CSVParserTest {
|
||||||
assertEquals(4, records.size());
|
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
|
@Test
|
||||||
public void testCarriageReturnEndings() throws IOException {
|
public void testCarriageReturnEndings() throws IOException {
|
||||||
final String code = "foo\rbaar,\rhello,world\r,kanu";
|
final String code = "foo\rbaar,\rhello,world\r,kanu";
|
||||||
|
@ -605,22 +617,22 @@ public class CSVParserTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetLineNumberWithLF() throws Exception {
|
public void testGetLineNumberWithLF() throws Exception {
|
||||||
validateLineNumbers(String.valueOf(LF));
|
this.validateLineNumbers(String.valueOf(LF));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetLineNumberWithCRLF() throws Exception {
|
public void testGetLineNumberWithCRLF() throws Exception {
|
||||||
validateLineNumbers(CRLF);
|
this.validateLineNumbers(CRLF);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetLineNumberWithCR() throws Exception {
|
public void testGetLineNumberWithCR() throws Exception {
|
||||||
validateLineNumbers(String.valueOf(CR));
|
this.validateLineNumbers(String.valueOf(CR));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetRecordNumberWithLF() throws Exception {
|
public void testGetRecordNumberWithLF() throws Exception {
|
||||||
validateRecordNumbers(String.valueOf(LF));
|
this.validateRecordNumbers(String.valueOf(LF));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -649,17 +661,17 @@ public class CSVParserTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetRecordNumberWithCRLF() throws Exception {
|
public void testGetRecordNumberWithCRLF() throws Exception {
|
||||||
validateRecordNumbers(CRLF);
|
this.validateRecordNumbers(CRLF);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetRecordNumberWithCR() throws Exception {
|
public void testGetRecordNumberWithCR() throws Exception {
|
||||||
validateRecordNumbers(String.valueOf(CR));
|
this.validateRecordNumbers(String.valueOf(CR));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testInvalidFormat() throws Exception {
|
public void testInvalidFormat() throws Exception {
|
||||||
CSVFormat invalidFormat = CSVFormat.DEFAULT.withDelimiter(CR);
|
final CSVFormat invalidFormat = CSVFormat.DEFAULT.withDelimiter(CR);
|
||||||
new CSVParser((Reader) null, invalidFormat);
|
new CSVParser((Reader) null, invalidFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue