Обратная запись в CSV с Java с использованием Super CSV
Я уже давно работаю над этим кодом и просто хочу, чтобы мне давали простые советы, если я пройду тупик. Суть, в которой я сейчас нахожусь, состоит в том, чтобы собрать одинаковые ячейки из разных CSV-файлов и скопировать одну строку в другой CSV-файл. Вопрос на самом деле заключается в том, можно ли написать по конкретным строкам, скажем, например, если 2 строки совпадают в строке 50, я хочу записать обратно в строку 50. Я предполагаю, что я, возможно, извлеку все в хэш-карту, запишите это в тогда что тогда напишу обратно в файл.csv? Есть ли более простой способ?
например, у меня есть один CSV, в котором есть данные о человеке, а у другого есть данные о свойствах, где проживает реальный человек, я хочу скопировать данные об имуществе в CSV человека, а также сопоставить их с правильными данными о человеке. надеюсь, что это имеет смысл
public class Old {
public static void main(String [] args) throws IOException
{
List<String[]> cols;
List<String[]> cols1;
int row =0;
int count= 0;
boolean b;
CsvMapReader Reader = new CsvMapReader(new FileReader("file1.csv"), CsvPreference.EXCEL_PREFERENCE);
CsvMapReader Reader2 = new CsvMapReader(new FileReader("file2.csv"), CsvPreference.EXCEL_PREFERENCE);
try {
cols = readFile("file1.csv");
cols1 = readFile("fiel2.csv");
String [] headers = Reader.getCSVHeader(true);
headers = header(cols1,headers
} catch (IOException e) {
e.printStackTrace();
return;
}
for (int j =1; j<cols.size();j++) //1
{
for (int i=1;i<cols1.size();i++){
if (cols.get(j)[0].equals(cols1.get(i)[0]))
{
}
}
}
}
private static List<String[]> readFile(String fileName) throws IOException
{
List<String[]> values = new ArrayList<String[]>();
Scanner s = new Scanner(new File(fileName));
while (s.hasNextLine()) {
String line = s.nextLine();
values.add(line.split(","));
}
return values;
}
public static void csvWriter (String fileName, String [] nameMapping ) throws FileNotFoundException
{
ICsvListWriter writer = new CsvListWriter(new PrintWriter(fileName),CsvPreference.STANDARD_PREFERENCE);
try {
writer.writeHeader(nameMapping);
} catch (IOException e) {
e.printStackTrace();
}
}
public static String[] header(List<String[]> cols1, String[] headers){
List<String> list = new ArrayList<String>();
String [] add;
int count= 0;
for (int i=0;i<headers.length;i++){
list.add(headers[i]);
}
boolean c;
c= true;
while(c) {
add = cols1.get(0);
list.add(add[count]);
if (cols1.get(0)[count].equals(null))// this line is never read errpr
{
c=false;
break;
} else
count ++;
}
String[] array = new String[list.size()];
list.toArray(array);
return array;
}
2 ответа
Просто будьте осторожны, если вы сначала прочитаете все адреса и личные данные (как предположил Томас) - если вы имеете дело только с небольшими CSV-файлами, то это нормально, но вам может не хватить памяти, если вы имеете дело с большие файлы.
В качестве альтернативы я собрал пример, который сначала читает адреса, а затем записывает объединенные данные о человеке / адресе, а он считывает данные о человеке.
Просто несколько вещей, чтобы отметить:
Я использовал CsvMapReader и CsvMapWriter, потому что вы были - это означало, что мне пришлось использовать карту, содержащую карту, для хранения адресов. Использование CsvBeanReader/CsvBeanWriter сделало бы это немного более элегантным.
Код из вашего вопроса на самом деле не использует Super CSV для чтения CSV (вы используете
Scanner
а такжеString.split()
). Вы столкнетесь с проблемами, если ваш CSV содержит запятые в данных (что вполне возможно с адресами), поэтому гораздо безопаснее использовать Super CSV, который будет обрабатывать экранированные запятые для вас.
Пример:
package example;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import org.supercsv.io.CsvMapReader;
import org.supercsv.io.CsvMapWriter;
import org.supercsv.io.ICsvMapReader;
import org.supercsv.io.ICsvMapWriter;
import org.supercsv.prefs.CsvPreference;
public class CombiningPersonAndAddress {
private static final String PERSON_CSV = "id,firstName,lastName\n"
+ "1,philip,fry\n2,amy,wong\n3,hubert,farnsworth";
private static final String ADDRESS_CSV = "personId,address,country\n"
+ "1,address 1,USA\n2,address 2,UK\n3,address 3,AUS";
private static final String[] COMBINED_HEADER = new String[] { "id",
"firstName", "lastName", "address", "country" };
public static void main(String[] args) throws Exception {
ICsvMapReader personReader = null;
ICsvMapReader addressReader = null;
ICsvMapWriter combinedWriter = null;
final StringWriter output = new StringWriter();
try {
// set up the readers/writer
personReader = new CsvMapReader(new StringReader(PERSON_CSV),
CsvPreference.STANDARD_PREFERENCE);
addressReader = new CsvMapReader(new StringReader(ADDRESS_CSV),
CsvPreference.STANDARD_PREFERENCE);
combinedWriter = new CsvMapWriter(output,
CsvPreference.STANDARD_PREFERENCE);
// map of personId -> address (inner map is address details)
final Map<String, Map<String, String>> addresses =
new HashMap<String, Map<String, String>>();
// read in all of the addresses
Map<String, String> address;
final String[] addressHeader = addressReader.getCSVHeader(true);
while ((address = addressReader.read(addressHeader)) != null) {
final String personId = address.get("personId");
addresses.put(personId, address);
}
// write the header
combinedWriter.writeHeader(COMBINED_HEADER);
// read each person
Map<String, String> person;
final String[] personHeader = personReader.getCSVHeader(true);
while ((person = personReader.read(personHeader)) != null) {
// copy address details to person if they exist
final String personId = person.get("id");
final Map<String, String> personAddress = addresses.get(personId);
if (personAddress != null) {
person.putAll(personAddress);
}
// write the combined details
combinedWriter.write(person, COMBINED_HEADER);
}
} finally {
personReader.close();
addressReader.close();
combinedWriter.close();
}
// print the output
System.out.println(output);
}
}
Выход:
id,firstName,lastName,address,country
1,philip,fry,address 1,USA
2,amy,wong,address 2,UK
3,hubert,farnsworth,address 3,AUS
Из вашего комментария кажется, что у вас следующая ситуация:
- Файл 1 содержит лиц
- Файл 2 содержит адреса
Затем вы хотите сопоставить людей и адреса по некоторому ключу (одному или нескольким полям) и записать комбинацию обратно в файл CSV.
Таким образом, самый простой подход может быть что-то вроде этого:
//use a LinkedHashMap to preserve the order of the persons as found in file 1
Map<PersonKey, String[]> persons = new LinkedHashMap<>();
//fill in the persons from file 1 here
Map<PersonKey, String[]> addresses = new HashMap<>();
//fill in the addresses from file 2 here
List<String[]> outputLines = new ArrayList<>(persons.size());
for( Map.Entry<PersonKey, String[]> personEntry: persons.entrySet() ) {
String[] person = personEntry.getValue();
String[] address = addresses.get( personEntry.getKey() );
//merge the two arrays and put them into outputLines
}
//write outputLines to a file
Обратите внимание, что PersonKey
может быть просто String
или объект-обертка (Integer
и т. д.), если вы можете сопоставить людей и адреса по одному полю. Если у вас есть больше полей, вам может понадобиться PersonKey
объект с equals()
а также hashCode()
правильно переопределено.