You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
When try use CsvReader<CsvRecord> records second time in separate method then records is empty #106
changed the title [-]When try use CsvReader<CsvRecord> records in private method then records is empty[/-][+]When try use CsvReader<CsvRecord> records second time in separate method then records is empty[/+]on Jan 17, 2024
The first loop displays all records, but the second loop is empty. This is expected, and FastCSV evidently requires additional documentation in this regard.
The call to CsvReader.builder().ofCsvRecord(file) returns an Iterable of CsvRecord (CsvReader). With each iteration of the loop, you read (consume) one record from the file. After all records are read, there are no more records.
If you truly want to store all records of the file for repeated access, you'd have to collect them:
try (CsvReader<CsvRecord> csv = CsvReader.builder().ofCsvRecord(file)) {
finalList<CsvRecord> records = csv.stream().toList();
// first loopfor (CsvRecordr : records) {
System.out.println(r);
}
// second loopfor (CsvRecordr : records) {
System.out.println(r);
}
}
Keep in mind that with this approach, all records of the file have to be kept in memory, while the streaming approach of FastCSV allows you to read huge CSV files with only a little memory consumption.
The fastest way would be a custom callback handler – see this example. But I wouldn't recommend that way unless you absolutely need the last bit of performance.
A very fast and maintainable way would be something like this:
privatestaticvoidreadFile(Pathfile) throwsIOException {
// Make sure we have the same number of fields in each recordCsvReader.CsvReaderBuilderbuilder = CsvReader.builder()
.ignoreDifferentFieldCount(false);
try (CloseableIterator<CsvRecord> it = builder.ofCsvRecord(file).iterator()) {
if (!it.hasNext()) {
thrownewIllegalStateException("No header found");
}
List<String> header = it.next().getFields();
if (!it.hasNext()) {
thrownewIllegalStateException("No data types found");
}
List<String> dataTypes = it.next().getFields();
while (it.hasNext()) {
YourCustomRecordyourCustomRecord = mapRecord(header, dataTypes, it.next());
// do something with your recordSystem.out.println(yourCustomRecord);
}
}
}
privatestaticYourCustomRecordmapRecord(List<String> header, List<String> dataTypes, CsvRecordrecord) {
// Map the record to your needs with the given header and data typesreturnnewYourCustomRecord(record.getField(0), Integer.parseInt(record.getField(1)));
}
privaterecordYourCustomRecord(Strings, inti) {
}
You may also use NamedCsvRecords (.ofNamedCsvRecord(file)) if you want to access the fields by name.
The efficiency of your mapRecord implementation will crucial to the performance of the whole process. But that highly depends on your exact needs.
In the future, with Stream Gatherers (JEP 461, a Preview Feature of Java 22) we'll also be able to implement this using Java streams. The following codes uses build 22-ea+31-2314 of OpenJDK:
privatestaticvoidreadFile(Pathfile) throwsIOException {
// Make sure we have the same number of fields in each recordCsvReader.CsvReaderBuilderbuilder = CsvReader.builder()
.ignoreDifferentFieldCount(false);
try (Stream<CsvRecord> stream = builder.ofCsvRecord(file).stream()) {
stream
.gather(Gatherer.ofSequential(newYourCustomIntegrator()))
.forEach(yourCustomRecord -> {
// do something with your recordSystem.out.println(yourCustomRecord);
});
}
}
privatestaticclassYourCustomIntegratorimplementsGatherer.Integrator<Void, CsvRecord, YourCustomRecord> {
privateList<String> header;
privateList<String> dataTypes;
@Overridepublicbooleanintegrate(Voidstate, CsvRecordelement,
Gatherer.Downstream<? superYourCustomRecord> downstream) {
if (dataTypes != null) {
returndownstream.push(mapRecord(header, dataTypes, element));
}
if (header == null) {
header = element.getFields();
} else {
dataTypes = element.getFields();
}
returntrue;
}
}
Activity
[-]When try use CsvReader<CsvRecord> records in private method then records is empty[/-][+]When try use CsvReader<CsvRecord> records second time in separate method then records is empty[/+]osiegmar commentedon Jan 17, 2024
Your example demonstrates the following:
The used for-each loop is a short version of the following:
The first loop displays all records, but the second loop is empty. This is expected, and FastCSV evidently requires additional documentation in this regard.
The call to
CsvReader.builder().ofCsvRecord(file)returns an Iterable of CsvRecord (CsvReader). With each iteration of the loop, you read (consume) one record from the file. After all records are read, there are no more records.If you truly want to store all records of the file for repeated access, you'd have to collect them:
Keep in mind that with this approach, all records of the file have to be kept in memory, while the streaming approach of FastCSV allows you to read huge CSV files with only a little memory consumption.
Clarify/Document iterative read process #106
stbischof commentedon Jan 17, 2024
When i remember currently the Usercase is to handle csv with typed columns.
col1,col2
String,int
Foo,1
Bar,987
...
there you need information from header and line 2.
Then run fast over all the following lines.
What woulr be fastest way to handle this?
osiegmar commentedon Jan 18, 2024
The fastest way would be a custom callback handler – see this example. But I wouldn't recommend that way unless you absolutely need the last bit of performance.
A very fast and maintainable way would be something like this:
You may also use NamedCsvRecords (
.ofNamedCsvRecord(file)) if you want to access the fields by name.The efficiency of your
mapRecordimplementation will crucial to the performance of the whole process. But that highly depends on your exact needs.In the future, with Stream Gatherers (JEP 461, a Preview Feature of Java 22) we'll also be able to implement this using Java streams. The following codes uses build 22-ea+31-2314 of OpenJDK:
dbulahov commentedon Jan 18, 2024
Thank you very much for your help