Apache Commons CSV
Я позволил библиотеке Apache Commons CSV выполнять работу по чтению моих текстовых файлов.(Примечание: JavaDoc здесь здесь - их ссылка на домашней странице не работает.)
Я начинаю с определения формата CSVFormat.TDF
, затем изменяю его, ожидая VERTICAL BAR (труба,|
), а не символ Tab в качестве разделителя.
Я использовал enum для именования всех полей ваших входных данных.Но это необязательно, вы могли бы использовать строковые имена.
Остерегайтесь типа с плавающей запятой double
точность обмена для скорости выполнения.Если вы хотите, чтобы ваши числа оставались нетронутыми, используйте BigDecimal
.
Используя объекты, а не примитивы, мы можем использовать null
, чтобы показать, где в вашем вводе отсутствуют данные.
Я использовал троичный оператор для проверки значений NULL.Тернар - это просто оператор if-the-else
, свернутый в одну строку с использованием синтаксиса:
result = test ? valueToUseIfTestIsTrue : valueToUseIfTestIsFalse ;
Пример. Если высота в метрах - пустая строка, запишите значение NULL.Иначе, проанализируйте входящую строку как объект Integer
.
Integer ELEV_IN_M = record.get( FIELD.ELEV_IN_M ).isBlank() ? null : Integer.valueOf( record.get( FIELD.ELEV_IN_M ) );
String::isBlank
метод впервые введен в Java 11. Он проверяет наличие пустой строки или строки, состоящей полностью из пробельных символов.Для более ранней версии Java замените на String::isEmpty
в Java 6 и более поздних версиях.Ваши данные, кажется, имеют только пустые строки, без пробелов, но я не проверил это наблюдение.
Пропустить методы получения / установки.Просто используйте public
переменные-члены, пока весь остальной код не заработает, и пока у вас нет особой причины использовать методы доступа.
Чтобы ускорить написание этого демонстрационного кода, я просто скопировал скопированные имена ваших файлов данных как есть, все в верхнем регистре.Я не удосужился перейти на верблюжий кейс для канонической Java.
Вот полный рабочий пример в одном большом классе с демонстрацией в методе main
.
package work.basil.example;
import org.apache.commons.csv.*;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.math.BigDecimal;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;
public class Gis
{
public enum FIELD
{
FEATURE_ID, FEATURE_NAME, FEATURE_CLASS, STATE_ALPHA, STATE_NUMERIC, COUNTY_NAME, COUNTY_NUMERIC, PRIMARY_LAT_DMS, PRIM_LONG_DMS, PRIM_LAT_DEC, PRIM_LONG_DEC, SOURCE_LAT_DMS, SOURCE_LONG_DMS, SOURCE_LAT_DEC, SOURCE_LONG_DEC, ELEV_IN_M, ELEV_IN_FT, MAP_NAME, DATE_CREATED, DATE_EDITED
}
public String FEATURE_NAME, FEATURE_CLASS, STATE_ALPHA, STATE_NUMERIC, COUNTY_NAME, COUNTY_NUMERIC, PRIMARY_LAT_DMS, PRIM_LONG_DMS, SOURCE_LAT_DMS, SOURCE_LONG_DMS, MAP_NAME;
public Integer FEATURE_ID, ELEV_IN_M, ELEV_IN_FT;
public BigDecimal PRIM_LAT_DEC, PRIM_LONG_DEC, SOURCE_LAT_DEC, SOURCE_LONG_DEC;
public LocalDate DATE_CREATED, DATE_EDITED;
// Constructor
public Gis ( Integer FEATURE_ID , String FEATURE_NAME , String FEATURE_CLASS , String STATE_ALPHA , String STATE_NUMERIC , String COUNTY_NAME , String COUNTY_NUMERIC , String PRIMARY_LAT_DMS , String PRIM_LONG_DMS , BigDecimal PRIM_LAT_DEC , BigDecimal PRIM_LONG_DEC , String SOURCE_LAT_DMS , String SOURCE_LONG_DMS , BigDecimal SOURCE_LAT_DEC , BigDecimal SOURCE_LONG_DEC , Integer ELEV_IN_M , Integer ELEV_IN_FT , String MAP_NAME , LocalDate DATE_CREATED , LocalDate DATE_EDITED )
{
Objects.requireNonNull( FEATURE_ID ); // … and so on.
this.FEATURE_ID = FEATURE_ID;
this.FEATURE_NAME = FEATURE_NAME;
this.FEATURE_CLASS = FEATURE_CLASS;
this.STATE_ALPHA = STATE_ALPHA;
this.STATE_NUMERIC = STATE_NUMERIC;
this.COUNTY_NAME = COUNTY_NAME;
this.COUNTY_NUMERIC = COUNTY_NUMERIC;
this.PRIMARY_LAT_DMS = PRIMARY_LAT_DMS;
this.PRIM_LONG_DMS = PRIM_LONG_DMS;
this.PRIM_LAT_DEC = PRIM_LAT_DEC;
this.PRIM_LONG_DEC = PRIM_LONG_DEC;
this.SOURCE_LAT_DMS = SOURCE_LAT_DMS;
this.SOURCE_LONG_DMS = SOURCE_LONG_DMS;
this.SOURCE_LAT_DEC = SOURCE_LAT_DEC;
this.SOURCE_LONG_DEC = SOURCE_LONG_DEC;
this.ELEV_IN_M = ELEV_IN_M;
this.ELEV_IN_FT = ELEV_IN_FT;
this.MAP_NAME = MAP_NAME;
this.DATE_CREATED = DATE_CREATED;
this.DATE_EDITED = DATE_EDITED;
}
// -------| Object |-----------------------
@Override
public String toString ()
{
return new StringJoiner( " | " , Gis.class.getSimpleName() + "{ " , " }" )
.add( "FEATURE_ID='" + this.FEATURE_ID + "'" )
.add( "FEATURE_NAME='" + this.FEATURE_NAME + "'" )
.toString();
}
// -------| Parsing |----------------------
static public List < Gis > parseFile ( final String path )
{
ArrayList < Gis > list = new ArrayList <>();
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu" );
try
{
Reader reader = new FileReader( path );
CSVFormat format = CSVFormat.TDF.withHeader( Gis.FIELD.class ).withFirstRecordAsHeader().withTrim().withDelimiter( '|' ); // Must pass a `char` to `withDelimiter` not a `String`, so use single-quote not double-quote.
Iterable < CSVRecord > records = format.parse( reader );
for ( CSVRecord record : records )
{
// FEATURE_ID|FEATURE_NAME|FEATURE_CLASS|STATE_ALPHA|STATE_NUMERIC|COUNTY_NAME|COUNTY_NUMERIC|PRIMARY_LAT_DMS|PRIM_LONG_DMS|PRIM_LAT_DEC|PRIM_LONG_DEC|SOURCE_LAT_DMS|SOURCE_LONG_DMS|SOURCE_LAT_DEC|SOURCE_LONG_DEC|ELEV_IN_M|ELEV_IN_FT|MAP_NAME|DATE_CREATED|DATE_EDITED
Integer FEATURE_ID = Integer.valueOf( record.get( FIELD.FEATURE_ID ) );
String FEATURE_NAME = record.get( FIELD.FEATURE_NAME );
String FEATURE_CLASS = record.get( FIELD.FEATURE_CLASS );
String STATE_ALPHA = record.get( FIELD.STATE_ALPHA );
String STATE_NUMERIC = record.get( FIELD.STATE_NUMERIC );
String COUNTY_NAME = record.get( FIELD.COUNTY_NAME );
String COUNTY_NUMERIC = record.get( FIELD.COUNTY_NUMERIC );
String PRIMARY_LAT_DMS = record.get( FIELD.PRIM_LONG_DMS );
String PRIM_LONG_DMS = record.get( FIELD.PRIM_LONG_DMS );
BigDecimal PRIM_LAT_DEC = record.get( FIELD.PRIM_LAT_DEC ).isBlank() ? null : new BigDecimal( record.get( FIELD.PRIM_LAT_DEC ) );
BigDecimal PRIM_LONG_DEC = record.get( FIELD.PRIM_LONG_DEC ).isBlank() ? null : new BigDecimal( record.get( FIELD.PRIM_LONG_DEC ) );
String SOURCE_LAT_DMS = record.get( FIELD.SOURCE_LAT_DMS );
String SOURCE_LONG_DMS = record.get( FIELD.SOURCE_LONG_DMS );
BigDecimal SOURCE_LAT_DEC = record.get( FIELD.SOURCE_LAT_DEC ).isBlank() ? null : new BigDecimal( record.get( FIELD.SOURCE_LAT_DEC ) );
BigDecimal SOURCE_LONG_DEC = record.get( FIELD.SOURCE_LONG_DEC ).isBlank() ? null : new BigDecimal( record.get( FIELD.SOURCE_LONG_DEC ) );
Integer ELEV_IN_M = record.get( FIELD.ELEV_IN_M ).isBlank() ? null : Integer.valueOf( record.get( FIELD.ELEV_IN_M ) );
Integer ELEV_IN_FT = record.get( FIELD.ELEV_IN_FT ).isBlank() ? null : Integer.valueOf( record.get( FIELD.ELEV_IN_FT ) );
String MAP_NAME = record.get( FIELD.MAP_NAME );
LocalDate DATE_CREATED = record.get( FIELD.DATE_CREATED ).isBlank() ? null : LocalDate.parse( record.get( FIELD.DATE_CREATED ) , f );
LocalDate DATE_EDITED = record.get( FIELD.DATE_EDITED ).isBlank() ? null : LocalDate.parse( record.get( FIELD.DATE_EDITED ) , f );
Gis gis = new Gis( FEATURE_ID , FEATURE_NAME , FEATURE_CLASS , STATE_ALPHA , STATE_NUMERIC , COUNTY_NAME , COUNTY_NUMERIC , PRIMARY_LAT_DMS , PRIM_LONG_DMS , PRIM_LAT_DEC , PRIM_LONG_DEC , SOURCE_LAT_DMS , SOURCE_LONG_DMS , SOURCE_LAT_DEC , SOURCE_LONG_DEC , ELEV_IN_M , ELEV_IN_FT , MAP_NAME , DATE_CREATED , DATE_EDITED );
list.add( gis );
}
} catch ( FileNotFoundException e )
{
e.printStackTrace();
} catch ( IOException e )
{
e.printStackTrace();
}
list.trimToSize();
return list;
}
// ---------| Demo (psvm) |------------------------------------------
public static void main ( String[] args )
{
if ( false ) // Experiment on a small file, a subset of data. If that works, run the huge file.
{
String path = "/Users/basilbourque/gis-small.txt";
List < Gis > list = Gis.parseFile( path );
System.out.println( "list.size(): " + list.size() );
System.out.println( "list: " + list );
} else
{
String path = "/Users/basilbourque/gis.txt";
List < Gis > list = Gis.parseFile( path );
System.out.println( "list.size(): " + list.size() );
System.out.println( "list.sublist( 0 , 10 ): " + list.subList( 0 , 10 ) );
System.out.println( "list.sublist (last 10): " + list.subList( list.size()-10 ,list.size()) );
}
}
}
Когдазапустите.
list.size (): 122669
list.sublist (0, 10): [Gis {FEATURE_ID = '2928' |FEATURE_NAME = 'Мост через Киболу'}, Гис {FEATURE_ID = '6185' |FEATURE_NAME = 'Императорский национальный заповедник дикой природы'}, Гис {FEATURE_ID = '8164' |FEATURE_NAME = 'Мохаве Каньон'}, Гис {FEATURE_ID = '8174' |FEATURE_NAME = 'Долина Мохаве'}, Гис {FEATURE_ID = '9144' |FEATURE_NAME = 'Пало-Верде-Дам'}, Гис {FEATURE_ID = '9146' |FEATURE_NAME = 'Пало Верде' ', Гис {FEATURE_ID =' 9227 '|FEATURE_NAME = 'Parker Valley'}, Гис {FEATURE_ID = '12628' |FEATURE_NAME = 'Топок Ущелье'}, Гис {FEATURE_ID = '14114' |FEATURE_NAME = 'Главный канал Юмы'}, Гис {FEATURE_ID = '22751' |FEATURE_NAME = 'Национальный заповедник дикой природы Сибола'}]
list.sublist (последние 10): [Gis {FEATURE_ID = '27833610' |FEATURE_NAME = 'Почтовое отделение рекрутского корпуса морской пехоты'}, Гис {FEATURE_ID = '27833611' |FEATURE_NAME = 'MCAS Miramar Post Office'}, Гис {FEATURE_ID = '27833612' |FEATURE_NAME = 'Почтовое отделение Mount McCoy'}, Гис {FEATURE_ID = '27833613' |FEATURE_NAME = 'Почтовое отделение Северного острова NAS'}, Гис {FEATURE_ID = '27833614' |FEATURE_NAME = 'Pala Post Office'}, Гис {FEATURE_ID = '27833615' |FEATURE_NAME = 'Почтовое отделение Пинон Хиллс'}, Гис {FEATURE_ID = '27833616' |FEATURE_NAME = 'Yermo Post Office'}, Гис {FEATURE_ID = '27833617' |FEATURE_NAME = 'Федеральное почтовое отделение в Ковине'}, Гис {FEATURE_ID = '27833618' |FEATURE_NAME = 'Почтовое отделение Монтальво'}, Гис {FEATURE_ID = '27833619' |FEATURE_NAME = 'Почтовое отделение Беверли-Хиллз'}]
В реальной работе я бы переместил материал анализа в свой собственный класс, оставив класс Gis
только для проверки и хранения данных.