Разбор ошибок из-за различий CSV до / после сохранения (Java с Apache Commons CSV)
У меня есть файл CSV с 37 столбцами, который я анализирую на Java с помощью Apache Commons CSV 1.2. Мой установочный код выглядит следующим образом:
//initialize FileReader object
FileReader fileReader = new FileReader(file);
//intialize CSVFormat object
CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER_MAPPING);
//initialize CSVParser object
CSVParser csvFileParser = new CSVParser(fileReader, csvFileFormat);
//Get a list of CSV file records
List<CSVRecord> csvRecords = csvFileParser.getRecords();
// process accordingly
Моя проблема в том, что, когда я копирую CSV для обработки в целевой каталог и запускаю программу синтаксического анализа, я получаю следующую ошибку:
Exception in thread "main" java.lang.IllegalArgumentException: Index for header 'Title' is 7 but CSVRecord only has 6 values!
at org.apache.commons.csv.CSVRecord.get(CSVRecord.java:110)
at launcher.QualysImport.createQualysRecords(Unknown Source)
at launcher.QualysImport.importQualysRecords(Unknown Source)
at launcher.Main.main(Unknown Source)
Однако, если я скопирую файл в целевой каталог, открою и сохраню его, а затем снова попробую программу, она заработает. Открытие и сохранение файла CSV добавляет запятые, необходимые в конце, поэтому моя программа не скомпрометирует отсутствие достаточного количества заголовков для чтения.
Для контекста, вот пример строки до / после сохранения:
До (сбой): "данные", "данные", "данные", "данные"
После (работы): "данные", "данные",,,, "данные",,, "данные",,,,,,
Итак, мой вопрос: почему формат CSV меняется, когда я открываю и сохраняю его? Я не изменяю никакие значения или кодировку, и поведение сохраняется для MS-DOS или обычного формата.csv при сохранении. Кроме того, я использую Excel для копирования / открытия / сохранения в моем тестировании.
Нужно ли использовать кодировку или формат? Могу ли я решить это программно?
Заранее спасибо!
РЕДАКТИРОВАНИЕ № 1:
Для дополнительного контекста, когда я впервые просматриваю пустую строку в исходном файле, у него просто есть новая строка ^M, например:
^M
После открытия в Excel и сохранения это выглядит так со всеми 37 моими пустыми полями:
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,^M
Это несоответствие кодировки Windows?
3 ответа
Может быть, это проблема совместимости с тем, что изначально создавало файл. Похоже, что Excel принимает пустую строку в качестве допустимой строки с пустыми строками в каждом столбце, причем количество столбцов совпадает с некоторыми другими строками. Затем он сохраняет его в соответствии с соглашениями CSV с разделителем столбцов. (^M - это символ возврата каретки; в системах Microsoft он предшествует символу перевода строки в конце строки в текстовых файлах)
Возможно, вы можете справиться с этим, создав собственный подкласс Reader, который будет находиться между FileReader и CSVParser. Ваш читатель прочтет строку, и если она не заполнена, верните строку с правильным количеством запятых. В противном случае просто верните строку как есть.
Например:
class MyCSVCompatibilityReader extends BufferedReader
{
private final BufferedReader delegate;
public MyCSVCompatibilityReader(final FileReader fileReader)
{
this.delegate = new BufferedReader(fileReader);
}
@Override
public String readLine()
{
final String line = this.delegate.readLine();
if ("".equals(line.trim())
{ return ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"; }
else
{ return line; }
}
}
Есть много других деталей, которые нужно правильно реализовать при реализации интерфейса. Вам нужно будет пройти через вызовы ко всем другим методам (закрыть, подготовить, сбросить, пропустить и т. Д.) И убедиться, что каждый из различных read()
методы работают правильно. Может быть проще, если файл легко помещается в памяти, просто прочитать файл и записать фиксированную версию в новый StringWriter, а затем создать StringReader для CSVParser.
Или, может быть, попробовать с AllowMissingColumnNames?
//intialize CSVFormat object
CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER_MAPPING).withAllowMissingColumnNames();
Возможно попробуйте это: Создает парсер для данного файла. синтаксический анализ (файл, кодировка Charset, формат CSVFormat)
// импорт импорт java.nio.charset.StandardCharsets; //StandardCharsets.UTF_8
Примечание. Этот метод внутренне создает FileReader с использованием FileReader.FileReader(java.io.File), который, в свою очередь, опирается на кодировку по умолчанию для JVM, которая выполняет код.