I use a hashMap to store data (certificate details) which is read from a file.
The key and value is stored in the hashMap but after calling the put method, ALL values have the value of the last added entry.
I guess it is also related to
hashmap.get() returning wrong values even though they are all correct in the map
but I don't see my error:
HashMap<String, String[]> certDataMap = new HashMap<String, String[]>();
String line="";
String bankName = "", validTill = "", fingerPrint = "";
File certDat = new File(certDataFile);
int cntEntries=0;
String[] data = {"dummy", "dummy"};
if (certDat.exists()) {
try {
Scanner scanner = new Scanner(certDat);
while (scanner.hasNextLine()) {
line=scanner.nextLine();
bankName=line.split("\\|")[0];
validTill=line.split("\\|")[1];
fingerPrint=line.split("\\|")[2];
logger.debug("line: {} bankName: {} validTill: {} fingerPrint: {}",line, bankName, validTill, fingerPrint);
data[0]=validTill;
data[1]=fingerPrint;
certDataMap.put(bankName, data);
debugCertMap();
cntEntries++;
}
scanner.close();
logger.debug("{} read from {}", cntEntries, certDataFile);
} catch (IOException e) {
logger.error(certDataFile,e);
}
} else
logger.error(certDataFile+" not found! New file will be created if certificates were downloaded");
The problem was the declaration of string array data outside the loop as mentioned by Jonathan:
while (scanner.hasNextLine()) {
line=scanner.nextLine();
bankName=line.split("\\|")[0];
validTill=line.split("\\|")[1];
fingerPrint=line.split("\\|")[2];
logger.debug("line: {} bankName: {} validTill: {} fingerPrint: {}",line, bankName, validTill, fingerPrint);
String[] data = {validTill, fingerPrint};
certDataMap.put(bankName, data);
debugCertMap();
cntEntries++;
An object is actually reference and you are using the same object data for each line. Use a new object.
Yes, you use same object String[] data = {"dummy", "dummy"};, where data is the reference to the array.
But look at your code. All these could be done very simply and avoid these problems.
Create data holder class, that represents single line from the file:
public static final class Data {
private final String bankName;
private final String validTill;
private final String fingerPrint;
public Data(String[] line) {
bankName = line[0];
validTill = line[1];
fingerPrint = line[2];
}
}
And provide a method that accept Path and retrieve file content with required format:
public static Map<String, Data> read(Path path) throws IOException {
return Files.lines(path)
.map(line -> new Data(line.split("\\|")))
.collect(Collectors.toMap(Data::getBankName, Function.identity()));
}
That's all!
Related
So i got a Java Class of Konto, which got:
private String navn;
private int medlemdsnummer;
private String årstal;
private String måned;
private String dag;
LocalDate localDate;
They are used like this:
ArrayList<Konto> kontoArrayList = new ArrayList<>();
And I save my ArrayList to a .txt document before the program shutdowns:
private static void saveToFile(ArrayList<Konto> kontoArrayList) throws IOException {
String content = new String(Files.readAllBytes(Paths.get("medlemmer.txt")));
PrintStream printStream = new PrintStream("medlemmer.txt");
for (int i = 0; i < kontoArrayList.size(); i++) {
printStream.println(content + kontoArrayList.get(i).getMedlemdsnummer() + ": " + kontoArrayList.get(i).getNavn() + " " +
kontoArrayList.get(i).getLocalDate());
}
}
They end up looking like this in the .txt file:
1: Kasper 1996-11-20
2: Jonas 1996-04-27
3: Jesper 1996-05-14
Okay, so far so good. Now for the question: When the program is turned on, I want to make it able to load the .txt file from the beginning and "transfer" it to an ArrayList of Konto. So that i later can use my method (addNewMember). I saw a lot of example on the internet, but they all use:
ArrayList<String> somename = new ArrayList<String>();
I want to use:
ArrayList<Konto> konto = new ArrayList<Konto>();
Is this possible, if so how do to?
If not what could i do instead?
Thanks in advance, Victor.
You can read all lines from the file as string and split this strings by spaces.
And then create new objects with parsing of options.
Something like this:
List<String> strings = Files.readAllLines(Paths.get("test.txt"));
List<Konto> kontos = new ArrayList<>();
for (String string : strings) {
String[] data = string.split(" ");
kontos.add(new Konto(data[1], new Date(data[2])));
}
Or using Streams:
List<Konto> kontos = Files.lines(Paths.get("test.txt")) // String
.map(line -> line.split(" ")) // String[]
.map(data -> new Konto(data[1], new Date(data[2])) // Konto
.collect(Collectors.toList());
Something like the following, you've got to check it
class TestParse {
public TestParse(String line) {
StringTokenizer tokenizer = new StringTokenizer(line, ",");
if(tokenizer.countTokens() != 3) {
throw new RuntimeException("error");
}
s1 = tokenizer.nextToken();
s2 = tokenizer.nextToken();
s3 = tokenizer.nextToken();
}
private String s1;
private String s2;
private String s3;
}
public class TestRead {
public static void main(String[] args) throws Exception {
List<TestParse> testParses = new ArrayList<TestParse>();
BufferedReader in = new BufferedReader(new FileReader("file.txt"));
String line;
while((line = in.readLine()) != null) {
testParses.add(new TestParse(line));
}
in.close();
}
}
I think one way you can try is read line by line, and define a Konto constructor that accept a string.
Edit: You can follow the below answer from Lucem. But I think I will do it a little different
List<String> strings = Files.readAllLines(Paths.get("fileName.txt"));
List<Konto> kontos = new ArrayList<>();
for (String s: strings) {
kontos.add (new Konto(s))
}
or using Streams:
List<Konto> kontos = Files.lines(Paths.get("fileName.txt"))
.map(line -> new Konto(line));
.collect(Collectors.toList());
And then in Konto class add a constructor that accept a string and manipulate it. Because you didn't add the class Konto here, I didn't know the exact name of your properties, so I let it be "yourPropertyNumber", "yourPropertyString" and "yourPropertyDate"
class Konto {
public Konto (String input) {
// Split based on white space
String[] dataParts = input.split(" ");
// Get rid of the semicolon
String number = dataParts[0].substring(0, dataParts[0].length - 1);
yourPropertyNumber = parseInt(number);
yourPropertyString = dataParts[1];
yourPropertyDate = new Date(dataParts[2]);
}
// Your other code here
}
The reason I want to pass a String to a constructor rather than parse the string where I read the file is that I think it is easier to debug or make change in the way it reads the string.
Hope this help.
I have a CSV file which contains rules and ruleversions. The CSV file looks like this:
CSV FILE:
#RULENAME, RULEVERSION
RULE,01-02-01
RULE,01-02-02
RULE,01-02-34
OTHER_RULE,01-02-04
THIRDRULE, 01-02-04
THIRDRULE, 01-02-04
As you can see, 1 rule can have 1 or more rule versions. What I need to do is read this CSV file and put them in an array. I am currently doing that with the following script:
private static List<String[]> getRulesFromFile() {
String csvFile = "rulesets.csv";
BufferedReader br = null;
String line = "";
String delimiter = ",";
List<String[]> input = new ArrayList<String[]>();
try {
br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) {
if (!line.startsWith("#")) {
String[] rulesetEntry = line.split(delimiter);
input.add(rulesetEntry);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return input;
}
But I need to adapt the script so that it saves the information in the following format:
ARRAY (
=> RULE => 01-02-01, 01-02-02, 01-02-04
=> OTHER_RULE => 01-02-34
=> THIRDRULE => 01-02-01, 01-02-02
)
What is the best way to do this? Multidimensional array? And how do I make sure it doesn't save the rulename more than once?
You should use a different data structure, for example an HashMap, like this.
HashMap<String, List<String>> myMap = new HashMap<>();
try {
br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) {
if (!line.startsWith("#")) {
String[] parts = string.split(delimiter);
String key = parts[0];
String value = parts[1];
if (myMap.containsKey(key)) {
myMap.get(key).add(value);
} else {
List<String> values = new ArrayList<String>();
values.add(value);
myMap.put(key, values);
}
}
}
This should work!
See using an ArrayList is not a good data structure of choice here.
I would personally suggest you to use a HashMap> for this particular purpose.
The rules will be your keys and rule versions will be your values which will be a list of strings.
While traversing your original file, just check if the rule (key) is present, then add the value to the list of rule versions (values) already present, otherwise add a new key and add the value to it.
For instance like this:
public List<String> removeDuplicates(List<String> myList) {
Hashtable<String, String> hashtable=new Hashtable<String, String>();
for(String s:myList) {
hashtable.put(s, s);
}
return new ArrayList<String>(hashtable.values());
}
This is exactly what key - value pairs can be used for. Just take a look at the Map Interface. There you can define a unique key containing various elements as value, perfectly for your issue.
Code:
// This collection will take String type as a Key
// and Prevent duplicates in its associated values
Map<String, HashSet<String>> map = new HashMap<String,HashSet<String>>();
// Check if collection contains the Key you are about to enter
// !REPLACE! -> "rule" with the Key you want to enter into your collection
// !REPLACE! -> "whatever" with the Value you want to associate with the key
if(!map.containsKey("rule")){
map.put("rule", new HashSet<String>());
}
else{
map.get("rule").add("whatever");
}
Reference:
Set
Map
The code given below takes two different inputs but I want to pass only single input that is the path of folder "test" and rest of the functioning as it is.
And also the final.tbl which is generation it should generate in the same input folder path:
public class Migrator {
private static final String KEY1 = "post_tran_id";
private static final String KEY2 = "post_tran_cust_id";
void migrate(String post_tran, String post_tran_cust) throws IOException {
Map<String, Map<String, String>> h1 = loadFile(post_tran, KEY1);
Map<String, Map<String, String>> h2 = loadFile(post_tran_cust, KEY2);
PrintStream out = new PrintStream("final.tbl");
for (Map.Entry<String, Map<String, String>> entry : h1.entrySet()) {
Map<String, String> data = entry.getValue();
String k = data.get(KEY2);
if (k != null && h2.containsKey(k)) {
print(out, KEY1, data.get(KEY1));
print(out, KEY2, data.get(KEY2));
// Print remaining rows in any order
for (String key : data.keySet()) {
if ( ! key.equals(KEY1) && ! key.equals(KEY2) ) {
print(out, key, data.get(key));
}
}
data = h2.get(k);
for (String key : data.keySet()) {
if ( ! key.equals(KEY2) ) {
print(out, key, data.get(key));
}
}
out.println(); // Record separator
}
}
}
private void print(PrintStream out, String key, String data) {
out.print("[name]");
out.print(key);
out.print("[/name]");
out.print("=");
out.print("[data]");
out.print(data);
out.print("[/data]");
out.println();
}
private Map<String, Map<String, String>> loadFile(String fileName, String key) throws
IOException {
Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>
();
BufferedReader br = new BufferedReader(new FileReader(fileName));
String line;
do {
Map<String, String> data = new HashMap<String, String>();
while ((line = br.readLine()) != null && !line.isEmpty()) {
data.put(getKey(line), getData(line));
}
result.put(data.get(key), data);
} while (line != null);
br.close();
return result;
}
private String getKey(String line) {
String[] tokens = line.split("=");
int length = tokens[0].length();
return tokens[0].substring(6, length - 7);
}
private String getData(String line) {
String[] tokens = line.split("=");
int length = tokens[1].length();
return tokens[1].substring(6, length - 7);
}
public static void main(String[] args) throws IOException { Migrator mg =
new Migrator();
mg.migrate("D:\\test\\post_tran.tbl",
"D:\\test\\post_tran_cust.tbl"); }
}
To make your migrate method take 1 argument but be able to work with many paths, you can always append all the paths into one string and parse them inside the migrate method.
Example:
String appendedArgument = "D:\\test\\post_tran.tbl;D:\\test\\post_tran_cust.tbl";
Notice the semi-colon separating both paths.
Then you can call you method:
mg.migrate(appendedArgument);
And parse it on the other side:
void migrate(String argument) throws IOException
{
String[] splitArgument.split(";");
String post_tran = splitArgument[0];
String post_tran_cust = splitArgument[1];
Map<String, Map<String, String>> h1 = loadFile(post_tran, KEY1);
Map<String, Map<String, String>> h2 = loadFile(post_tran_cust, KEY2);
}
Using this kind of method you can send as many paths into your migrate method as you want, this enables you (in this particular case) to also send the path where you want to store the final.tbl file.
That would make the appendedArgument string to look like:
String appendedArgument = "D:\\test\\;D:\\test\\post_tran.tbl;D:\\test\\post_tran_cust.tbl";
And then you would need to parse it accordingly inside the migrate method.
i making a program where I would read data from text files and store them in tables in mysql.
In my program the user would give the directory of where the files are, then the program would find only the .txt files and would continue. Afterwards a table would be created and it would have 2 fields and in these fields I would insert the values from the text file.
My issue is that i don't know how! I would explain you what I mean! In my program I would create table with fields (ID, Name). The values of these fields must be taken from the text file. All the files are as the below:
As you can see the ID is in the third row of the file and the Name is in the fifth. Could anyone help me how can I import the values for ID and Name in the table?How can i get only these values each time from the files?
The code for doing the first steps is:
public static void main(String args[]) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection con = (Connection) DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb", "", "");
String dirpath = "";
Scanner scanner1 = new Scanner(System.in);
while (true) {
System.out.println("Please give the directory:");
dirpath = scanner1.nextLine();
File fl = new File(dirpath);
if (fl.canRead())
break;
System.out.println("Error:Directory does not exists");
}
try {
String files;
File folder = new File(dirpath);
File[] listOfFiles = folder.listFiles();
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
files = listOfFiles[i].getName();
if (files.endsWith(".txt") || files.endsWith(".TXT")) {
List<File> txtFiles = new ArrayList<File>();
txtFiles.add(listOfFiles[i]);
String[] parts = files.split("\\.");
String tablename = parts[0];
for (File txtFile : txtFiles) {
List sheetData = new ArrayList();
try {
FileReader in = new FileReader(txtFile);
BufferedReader br = new BufferedReader(in);
String line = br.readLine();
while (line != null) {
System.out.println(line);
line = br.readLine();
}
in.close();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
getCreateTable1(con, tablename);
importData(con, txtFile, tablename);
}
}
}
}
} catch (Exception e) {
System.out.println();
}
}
private static String getCreateTable1(Connection con, String tablename) {
try {
Class.forName("com.mysql.jdbc.Driver");
Statement stmt = con.createStatement();
String createtable = "CREATE TABLE "
+ tablename
+ " ( ID INT , name VARCHAR(255)";
System.out.println("Create a new table in the database");
stmt.executeUpdate(createtable);
} catch (Exception e) {
System.out.println(((SQLException) e).getSQLState());
System.out.println(e.getMessage());
e.printStackTrace();
}
return null;
}
BufferedReader br = new BufferedReader(new FileReader(new File("path/to/file")));
String currentLine = br.readLine();
Map<Integer, String> nameByID = new HashMap<Integer, String>();
while (currentLine != null) {
String[] tokens = currentLine.split("\t");
int id = Integer.parseInt(tokens[2]);
String name = tokens[4];
nameByID.put(id, name);
currentLine = br.readLine();
}
br.close();
nameByID will have the names and IDs you need.
Note that some exception handling is required for calls to create a new BufferedReader, for calls to readLine(), and to close the BufferedReader. I didn't insert this because I couldn't remember it off the top of my head but your IDE should prompt you to insert if you're using something like Netbeans or Eclipse
You should try not to reinvent the wheel.
Use a FileNameExtensionFilter to filter the .txt files, this class is from swing but it's fine to use in plain java.
Check if each line matches a regex pattern, that way you can digest the line at the same time as verifying it.
Create a Person object that holds this information and return a Collection of Person - that way you encapsulate your file reading behavior away from your database access layer.
Put all this in a class called, say, FileReader and you have something like the following:
public class FileReader {
private final Pattern linePattern = Pattern.compile("^(\\w++)\\s++(\\w++)\\s*+$");
private final Pattern lineBreakPattern = Pattern.compile("\r?\n");
private final FileFilter txtFilter = new FileNameExtensionFilter("*.txt", "txt");
private final File txtFolder;
public FileReader(File txtFolder) {
this.txtFolder = txtFolder;
}
public List<Person> readFiles() {
final List<Person> people = new LinkedList<>();
for (final File txtFile : txtFolder.listFiles()) {
if (txtFilter.accept(txtFile)) {
people.add(readFile(txtFile));
}
}
return people;
}
private Person readFile(File txtFile) {
try (final Scanner scanner = new Scanner(txtFile)) {
scanner.useDelimiter(lineBreakPattern);
final Person person = new Person();
while (scanner.hasNext()) {
final String line = scanner.next();
final Matcher matcher = linePattern.matcher(line);
if (matcher.matches()) {
switch (matcher.group(1).toUpperCase()) {
case "ID":
person.setId(Integer.parseInt(matcher.group(2)));
break;
case "NAME":
person.setName(matcher.group(2));
break;
default:
throw new IOException("Illegal line '" + matcher.group() + "'.");
}
}
}
return person;
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public static final class Person {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
So you would create a FileReader with the folder that contains the files and then call readFiles, you then save the returned List<Person> in the database.
Lets go through this class.
The readFiles method loops over all files in the directory and checks whether each one of them matches the txtFilter - this filters out any non .txt file.
The readFiles method also creates and returns a List<Person, this is the result of reading the files. The List is populated by the readFile(File txtFile) method. That method is responsible for reading the individual files and parsing them to a Person.
The Person class is a very simple data transfer object, holding on properties and accessors. No logic.
The readFile method creates a Scanner in a Java 7 try-with-resources construct. It sets the delimiter to a platform independent linebreak pattern (\r?\n means that it matches \r\n or \n) and then loops over the scanner output.
Each line is processed with the linePattern, this probably warrants some explanation:
^(\\w++)\\s++(\\w++)\\s*+$
^ is the "start anchor", i.e. the line starts here
(\\w++) means capture any number of word characters
\\s++ means skip any number of whitespace characters
(\\w++) same as above
\\s*+ means skip zero or more whitespace characters
$ is the "end anchor", i.e. the end of the line
So, if the pattern matches we have a valid line. Moreover, when verifying we grabbed to "groups" of characters, these are our key and value.
Next we use a switch on the first group, this is using Java 7 switches with Strings. We populate the person depending on the value of the key, parsing the int where needed.
Finally we return the populated person.
This class should get you well on your way to accomplishing you goal - the sql insertion of the Person objects into a database is trivial.
You may want to add more verification during the file reading process, for example check that both a NAME and ID were found. I leave this as an exercise.
Ive been working on this code for quite sometime and just want to be given the simple heads up if im routing down a dead end. The point where im at now is to mathch identical cells from diffrent .csv files and copy one row into another csv file. The question really is would it be possible to write at specfic lines say for example if the the 2 cells match at row 50 i wish to write back on to row 50. Im assuming that i would maybe extract everything to a hashmap, write it in there then write back to the .csv file? is there a easier way?
for example i have one Csv that has person details, and the other has property details of where the actual person lives, i wish to copy the property details to the person csv, aswell as match them up with the correct person detail. hope this makes sense
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;
}
Just be careful if you read all of the addresses and person details into memory first (as Thomas has suggested) - if you're only dealing with small CSV files then it's fine, but you may run out of memory if you're dealing with larger files.
As an alternative, I've put together an example that reads the addresses in first, then writes the combined person/address details while it reads in the person details.
Just a few things to note:
I've used CsvMapReader and CsvMapWriter because you were - this meant I've had to use a Map containing a Map for storing the addresses. Using CsvBeanReader/CsvBeanWriter would make this a bit more elegant.
The code from your question doesn't actually use Super CSV to read the CSV (you're using Scanner and String.split()). You'll run into issues if your CSV contains commas in the data (which is quite possible with addresses), so it's a lot safer to use Super CSV, which will handle escaped commas for you.
Example:
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);
}
}
Output:
id,firstName,lastName,address,country
1,philip,fry,address 1,USA
2,amy,wong,address 2,UK
3,hubert,farnsworth,address 3,AUS
From your comment, it seems like you have the following situation:
File 1 contains persons
File 2 contains addresses
You then want to match persons and addresses by some key ( one or more fields) and write the combination back to a CSV file.
Thus the simplest approach might be something like this:
//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
Note that PersonKey might just be a String or a wrapper object ( Integer etc.) if you can match persons and addresses by one field. If you have more fields you might need a custom PersonKey object with equals() and hashCode() properly overridden.