Похоже, у вас есть текстовый файл в формате CSV, в котором есть определенные строки столбчатых данных, разделенных запятыми. Однако обычно CSV-файл начинается со строки Header , указывающей имена столбцов (хотя и не всегда), в которых вы, как представляется, не нуждаетесь, поэтому мы можем игнорировать эту часть.
Я думаю, что идеальной ситуацией в данном конкретном случае был бы метод, который считывает текстовый файл и может извлекать все или определенные столбцы данных из каждой строки, когда этот файл читается. Полученные данные затем записываются в предоставленный выходной файл.
Небольшая проблема заключается в том, что некоторые столбцовые данные находятся в кавычках ("..."), некоторые из которых также содержат тот же самый разделитель, который разделяет все остальные столбцы в любой данной строке записи. Это может создать проблему, поэтому необходимо соблюдать осторожность, чтобы справиться с этой ситуацией при извлечении данных, в противном случае неполные данные могут быть получены и записаны в нужный выходной файл и возвращены в 2D String Array.
Пример кода, который я предоставляю нижеделает все это в рамках одного метода. Он является относительно базовым, поэтому вам придется иметь дело с какими-либо конкретными улучшениями, если это потребуется. Метод содержит три параметра, два типа String и один из необязательных int args [], и возвращает двумерный массив строк, содержащий полученные данные. Если вы не хотите, чтобы метод возвращал что-либо, код может быть несколько уменьшен.
Вот метод getFromCSV () . Это хорошо прокомментировано:
/**
* This is a very basic parsing type method.<br><br>
*
* Usage: {@code String[][] data = getFromCSV("Data.txt", "DataOutput.txt", 13, 16, 17, 28, 29); }
*
* @param csvFilePath (String) The full path and file name of the Data file.<br>
*
* @param destinationPath (String) The full path and file name of the desired output file.
* the retrieved data will be store there.<br>
*
* @param desiredLiteralColumns (Optional - Integer Args or int[] Array) The literal
* data columns to acquire row data from. The arguments can be provided in any desired
* order. The returned Array will hold the required data in the order your provided.<br>
*
* @return (2D String Array) Containing columnar data from each data row.
*/
public static String[][] getFromCSV(String csvFilePath, String destinationPath,
int... desiredLiteralColumns) {
String ls = System.lineSeparator(); // The Line-Separator used for current OS.
/* Does the destination Path exist?
If not create it before file is created. */
File destPath = new File(destinationPath);
if (!destinationPath.trim().equals("") && destPath.getParentFile() == null) {
String fPath = destPath.getAbsolutePath().substring(0, destPath.getAbsolutePath().lastIndexOf("\\"));
new File(fPath).mkdirs();
}
else {
destPath.getParentFile().mkdirs();
}
ArrayList<String[]> list = new ArrayList<>();
ArrayList<String> lineData = new ArrayList<>();
File cisStaffHours = new File(csvFilePath);
// 'Try With Resources' is used here to auto-close the reader.
try (Scanner reader = new Scanner(cisStaffHours)) {
String fileLine = "";
// 'Try With Resources' is used here to auto-close the writer.
try (PrintWriter writer = new PrintWriter(new FileWriter(destPath))) {
while (reader.hasNextLine()) {
/* Read lines one at a time. Trim each read in
line of leading or trailing white-spaces (if any). */
fileLine = reader.nextLine().trim();
// Skip blank lines (if any).
if (fileLine.equals("")) {
continue;
}
/* Split the line based on a comma (,) delimiter)...
(DO NOT split on commas within quotation marks!).
The regular expression used with the split() method
ignores any number of white-spaces before or after
the delimiter. */
String[] lineParts = fileLine.split("\\s{0,},\\s{0,}(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);
//Do we only want specific columns only?
if (desiredLiteralColumns.length > 0) {
// Yes...
lineData.clear(); // Clear the ArrayList in case it already contains something.
// Retrieve the desired columns an place them into a String ArrayList...
for (int dc : desiredLiteralColumns) {
for (int lp = 0; lp < lineParts.length; lp++) {
if (dc == (lp + 1)) {
lineData.add(lineParts[lp]);
break;
}
}
}
/* Convert the 'lineData' ArrayList to a 1D String Array
and then add that String Array to the 'list' ArrayList. */
list.add(lineData.toArray(new String[0]));
// Build and Write the acquired data to the desired output file.
String dataString = lineData.get(0).replace("\"", "") + ", " +
lineData.get(1) + " " + lineData.get(2) + " , " +
lineData.get(3).replace(".", " ") + lineData.get(4);
writer.println(dataString);
writer.flush();
}
else {
// No, we want all columns. Add all columnar data to the ArrayList...
list.add(lineParts);
// Build and Write the acquired data to the desired output file.
String dataString = lineData.get(0).replace("\"", "") + ", " +
lineData.get(1) + " " + lineData.get(2) + " , " +
lineData.get(3).replace(".", " ") + lineData.get(4);
writer.println(dataString);
writer.flush();
}
}
}
// Catch and display any exceptions,
catch (IOException ex) {
System.out.println("getFromCSV() Method Error!" + ls + ex.getMessage());
}
}
catch (FileNotFoundException ex) {
System.out.println("getFromCSV() Method Error!" + ls + ex.getMessage());
}
/* Convert list to a 2D String Array and then
return the 2D Array... */
String[][] array = new String[list.size()][];
for (int i = 0; i < list.size(); i++) {
array[i] = list.get(i);
}
return array;
}
Как видите, метод требует три параметра:
Параметр csvFilePath:
Здесь должен быть указан строковый аргумент, который указывает, где находится текстовый файл для чтения в локальной файловой системе. Если текстовый файл находится внутри Class-Path, тогда достаточно только имени файла. Если нет, то ожидается полный путь и имя файла.
Параметр destinationPath:
Здесь необходимо указать строковый аргумент, который указывает, гдевыходной текстовый файл должен быть создан и записан в локальной файловой системе. Если выходной файл должен находиться в папке проекта приложения, то достаточно только имени файла. Если нет, то ожидается полный путь и имя файла к нему. Убедитесь, что в вашей операционной системе есть разрешения для достижения этой цели. Если указанный путь назначения еще не существует в локальной файловой системе, он автоматически создается, опять же, убедитесь, что в вашей операционной системе есть разрешения для достижения этого.
Параметр requiredLiteralColumns:
Здесь можно указать либо целочисленный массив ( int [] ), либо серию целочисленных аргументов, разделенных запятыми, которые обозначают нужные литеральные столбцы для извлеченияданные из каждой строки данных файла. Под " literal " мы подразумеваем, что данные, расположенные в индексе столбца 0, являются буквально столбцом 1. Данные в индексе столбца 7 - это буквально столбец 8. Это буквальные значения, которые вы хотите указать. Вот краткий пример:
Если в файле есть строка данных, которая выглядит следующим образом:
"Doe, John", 62, "6558 Cook Road, Atlanta, Georgia", 30336, $78,564.77
, и мы хотим получить данные в 1-м столбце (имя пользователя), 3-мстолбец (адрес) и 4-й столбец (почтовый индекс), то мы могли бы предоставить следующее для getFromCSV () метод:
String[][] myData = getFromCSV("My_CSV_File.csv", "MY_Output_File.txt", 1, 3, 5);
O R
int[] columns = {1, 3, 5};
String[][] myData = getFromCSV("C:\\MyDataFile\\My_CSV_File.csv",
"C:\\MyOuputFiles\\MY_Output_File.txt",
columns);
Затем, когда код запускается, выходной файли возвращенный 2D String Array будет содержать:
"Doe, John", "6558 Cook Road, Atlanta, Georgia", 30336
Если для необязательного параметра requiredLiteralColumns не заданы аргументы, то все Получаются данные столбца, поэтому:
String[][] myData = getFromCSV("My_CSV_File.csv", "MY_Output_File.txt");
поместит следующее в выходной файл, и возвращенный 2D String Array будет содержать то же самое.
"Doe, John", 62, "6558 Cook Road, Atlanta, Georgia", 30336, $78,564.77
Я полагаю, что существуют проблемы с позиционированием разделителя в строках данных, которые вы указали в своем сообщении в качестве примера. Я думаю, что вы пропустили несколько запятых. Посмотрите на это внимательно . Как только вы это сделаете .... Чтобы построить именно то, что вам нужно, вы должны сделать что-то вроде этого:
String[][] data = getFromCSV("StaffHoursOverviewReport_10102019 (1).txt",
"outFile.txt",
13, 16, 17, 28, 29);
for (int i = 0; i < data.length; i++) {
String dataString = data[i][0].replace("\"", "") + ", " +
data[i][1] + " " + data[i][2] + " , " +
data[i][3].replace(".", " ") + data[i][4];
System.out.println(dataString);
}
Этот должен выводить на консольокно и поместите его в желаемый выходной файл:
Smith, Lehron, Billable 4.10 , Non Bill 2.57
, что составляет точно , как в примере, который вы предоставили для желаемого вывода. Испытано!