Java csv header iteration dynamically - java

I have a requirement like:
My input will be a csv file where I will be having values like below:
action, userId, firstName, email, lastName
1,2,sample,abc#gmail.com,test
2,3,justtest,def#gmail.com,test
I have to read this csv file based on headers. Say for ex: if action =1 and email is null, then I have to change from action to 2 or email to null or something like this.
I have no idea on how to read and parse the values based on the headers. This is my code what I tried:
String csvFile = "C:\\Test.csv";
// create BufferedReader to read csv file
BufferedReader br;
String line = "";
br = new BufferedReader(new FileReader(csvFile));
br.readLine();
// Read the file line by line starting from the second line
while ((line = br.readLine()) != null) {
// Get all tokens available in line
String[] tokens = line.split(",");
if (tokens.length > 0) {
for (int i = 0; i < tokens.length; i++) {
System.out.println("All Rows ------->" + tokens[i]);
}
}
}
This is just printing all the values in new line like below:
All Rows ------->1411184866
All Rows ------->category
All Rows ------->123456
All Rows ------->Test
All Rows ------->TestFullName
All Rows ------->rsap#gmail.com
All Rows ------->3423131
Please help me completing this code. Thanks in advance.

For parsing the CSV file into a post-processable format, I would first create an enum that models the columns of the file, in correct order:
enum Column {
ACTION, USERID, FIRSTNAME, EMAIL, LASTNAME;
public static final Column[] VALUES = values();
}
Then, I would read the file into a mapping of columns into lists of column values (this data structure is also called a "multimap"):
Map<Column, List<String>> columns =
new LinkedHashMap<>();
// initialize the map
for (Column c : Column.VALUES) {
columns.put(c, new ArrayList<>());
}
String csvFile = "C:\\Test.csv";
String line = "";
// create BufferedReader to read csv file
BufferedReader br = new BufferedReader(new FileReader(csvFile));
br.readLine();
// Read the file line by line starting from the second line
while ((line = br.readLine()) != null) {
// Get all tokens available in line
String[] tokens = line.split(",");
if (tokens.length > 0) {
for (int i = 0; i < tokens.length; i++) {
columns.get(Column.VALUES[i]).add(tokens[i].trim());
}
}
}
Now that you have the data ordered, you can start post-processing the values based on your business rules. Of course you can also apply the rules while reading the file, but this might hurt readability of the code. Accessing individual cells in the file is easy; e.g. the email address on the second row can be retrieved using columns.get(Column.EMAIL).get(1).
Running
System.out.println(columns);
with your example file outputs this:
{ACTION=[1, 2], USERID=[2, 3], FIRSTNAME=[sample, justtest],
EMAIL=[abc#gmail.com, def#gmail.com], LASTNAME=[test, test]}

Use Apache Common CSV libraries (or any other suitable libraries) to read the CSV files and then apply the business logic in the program.
https://commons.apache.org/proper/commons-csv/
It will give you the list of rows in the form of CSVRecord and then you just need to apply business logic based on the values by iterarting over the list. The first element in the list will be your header.
Reader in = new FileReader("File Name");
CSVParser parser = new CSVParser(in, CSVFormat.EXCEL);
List<CSVRecord> csvRecords = parser.getRecords();

Related

how to import a txt file into a JTable and make the first column auto increment according to the number of lines of the file

i'm doing some java coding and i have to import a file into a Jtable that has 4 columns while my file has 3 (separated by whitespaces, i need the first column of each line to be auto increment, here is my code:
try {
FileReader files = new FileReader(file);
BufferedReader buf = new BufferedReader(files);
String line = null;
String tokens[] = null;
while ((line = buf.readLine()) != null) {
tokens = line.split("\\p{javaWhitespace}+");
//System.out.println( Arrays.toString( tokens ));
model.addRow(tokens);
}
}
and this is what I'm getting :
and this is my file :
Simply add an additional token to the front of your data. This is easiest using a Vector and not an array. The first item in the vector is your row index, the next itmes are filled from your tokens array. For example:
try {
FileReader files = new FileReader(file);
BufferedReader buf = new BufferedReader(files);
String line = null;
String tokens[] = null;
int count = 0;
while ((line = buf.readLine()) != null) {
tokens = line.split("\\p{javaWhitespace}+");
Vector<Object> row = new Vector<>();
row.add(count);
count++;
for (String text: tokens) {
row.add(text);
}
model.addRow(row); // add the Vector, not the tokens array
}
}
There are other ways, including extending the table model such that it automatically does this, and these may need to be done, depending on your needs -- for example, are the rows to renumber if one row is deleted or added during the running of the program? If so the logic needs to be within the table model.

Java - Most efficient way to read in a CSV file with various data types

I'm attempting to read in a CSV file with various data types.
A row of the sheet would be like below:
Single, Monthly, Accelerated, John, Smith, 08/15/1951, Yes
I then need to assign each field to a variable name, preform some calculations, print an output and then move onto the next line in the excel sheet
Up until now, I've been using the below
ArrayList<String> lines = new ArrayList<>();
try {
BufferedReader reader = new BufferedReader(new FileReader(fileName));
String line = null;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
But this creates an array with each slot containing a long string with the text (including comma) of the corresponding excel row.
This seems inefficient and impractical as i then have to traverse each slot/string to extract the values.
Once I have the methodology, I wont have any issue writing the code but i don't know the best way to go about it
Is it better to read each cell separately and assign to a variable ?
Or is it better to read in a file once and traverse it afterwards?
Perhaps there is a more efficient way to do this task
Edit : I also though of attempting to read in the entire CSV file as a 2D array, but the different data types could be an issue..?
You can try something similar to this. Use StringTokenizer to split the line by comma and add those elements to another List as strings in each iteration.
ArrayList<ArrayList<String>> lines = new ArrayList<>();
try {
BufferedReader reader = new BufferedReader(new FileReader(fileName));
String line = null;
while ((line = reader.readLine()) != null) {
ArrayList<String> tokens = new ArrayList<>();
StringTokenizer st = new StringTokenizer(line, ",");
while (st2.hasMoreElements()) {
tokens.add(st2.nextElement());
}
lines.add(tokens);
}
}
Now you can use proper casts to convert them to types you want. For example, to get the date,
DateFormat format = new SimpleDateFormat("mm/dd/yyyy", Locale.ENGLISH);
String dateString = lines.get(0).get(5);
Date date = format.parse(dateString);
You don't need to store the lines. Instead create a class that represents each row and add them to a list.
Something like :
class MyData
{
String status;
String salary;
String accelerated;
String firstName;
String lastName;
String date;
String trueOrFalse;
}
You could keep them without any access qualifier or make them private and add getter/setters.
In your file reader, split the line using the separator used in csv which is by default a comma ( , )
ArrayList<MyData> datas = new ArrayList<MyData>();
while ((line = reader.readLine()) != null) {
String[] columns = line.split( "," );
MyData data = new MyData();
data.status = columns[0];
data.salary = columns[1];
.
.
data.trueOrFalse = columns[6];
datas.add( data );
}
OR
If you want to just perform some calculations and print, you don't need a separate class or even ArrayList<String> lines.
Just do :
while ((line = reader.readLine()) != null) {
String[] columns = line.split( "," );
// Perform calculations with columns
// Print.
}
No need to store information if that is the case.

How to read and store data from a text file in which the first line are titles, and the other lines are related data

I have a text file with 300 lines or so. And the format is like:
Name Amount Unit CountOfOrder
A 1 ml 5000
B 1 mgm 4500
C 4 gm 4200
// more data
I need to read the text file line by line because each line of data should be together for further processing.
Now I just use string array for each line and access the data by index.
for each line in file:
array[0] = {data from the 'Name' column}
array[1] = {data from the 'Amount' column}
array[2] = {data from the 'Unit' column}
array[3] = {data from the 'CountOfOrder' column}
....
someOtherMethods(array);
....
However, I realized that if the text file changes its format (e.g. switch two columns, or insert another column), it would break my program (accessing through index might be wrong or even cause exception).
So I would like to use the title as reference to access each column. Maybe HashMap is a good option, but since I have to keep each line of data together, if I build a HashMap for each line, that would be too expensive.
Does anyone have any thought on this? Please help!
you only need a single hash map to map your column names to the proper column index. you fill the arrays by indexing with integers as you did before, to retrieve a column by name you'd use array[hashmap.get("Amount")].
You can read the file using opencsv.
CSVReader reader = new CSVReader(new FileReader("yourfile.txt"), '\t');
List<String[]> lines = reader.readAll();
The fist line contains the headers.
you can read each line of the file and assuming that the first line of the file has the column header you can parse that line to get all the names of the columns.
String[] column_headers = firstline.split("\t");
This will give you the name of all the columns now you just read through splitting on tabs and they will all line up.
You could do something like this:
BufferedReader in = new BufferedReader(new InputStreamReader(
new FileInputStream(FILE)));
String line = null;
String[] headers = null;
String[] data = null;
Map<String, List<String>> contents = new HashMap<String, List<String>>();
if ((line = in.readLine()) != null) {
headers = line.split("\t");
}
for(String h : headers){
contents.put(h, new ArrayList<String>());
}
while ((line = in.readLine()) != null) {
data = line.split("\t");
if(data.length != headers.length){
throw new Exception();
}
for(int i = 0; i < data.length; i++){
contents.get(headers[i]).add(data[i]);
}
}
It would give you flexibility, and would only require making the map once. You can then get the data lists from the map, so it should be a convenient data structure for the rest of your program to use.
This will give you individual list of columns.
public static void main(String args[]) throws FileNotFoundException, IOException {
List<String> headerList = new ArrayList<String>();
List<String> column1 = new ArrayList<String>();
List<String> column2 = new ArrayList<String>();
List<String> column3 = new ArrayList<String>();
List<String> column4 = new ArrayList<String>();
int lineCount=0;
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
String tokens[];
while (line != null) {
tokens = line.split("\t");
if(lineCount != 0)
{
int count = 0;
column1.add(tokens[count]); ++count;
column2.add(tokens[count]); ++count;
column3.add(tokens[count]); ++count;
column4.add(tokens[count]); ++count;
continue;
}
if(lineCount==0){
for(int count=0; count<tokens.length; count++){
headerList.add(tokens[count]);
lineCount++;
}
}
}
} catch (IOException e) {
} finally {
br.close();
}
}
using standard java.util.Scanner
String aa = " asd 9 1 3 \n d -1 4 2";
Scanner ss = new Scanner(aa);
ss.useDelimiter("\n");
while ( ss.hasNext()){
String line = ss.next();
Scanner fs = new Scanner(line);
System.out.println( "1>"+ fs.next()+" " +fs.nextInt() +" " +fs.nextLong()+" " +fs.nextBigDecimal());
}
using a bunch of hashmap's is ok...i won't be afraid ;)
if you need to process a lot of data...then try to translate your problem into a dataprocessing transformation
for example:
read all of you data into a hashmap's, but store them in a database using some JPA implementation....then you can go round'a'round your data ;)\

Join two csv files into one in java

I have two csv files with multiple columns from multiple tables.I am using opencsv to make csv files.
I want to make one csv file containing all the columns from both files.
There is one common column in both the files.
But number of records are not same.
Please suggest something. Any help would be appreciated.
P.S.: Joining two files simply mean i want to add all the columns in one file..It is not the database join .
I want the combined csv file and use it to in some tool to generate a pdf
Load one file into a dictionary keyed by the common column value, then append all the records of the 2nd file to the respective entry in the dictionary (again by common column value).
Finally, write all dictionary k,v pairs to a new file.
improvised example:
CSVReader r1 = ...; // reader of 1st file
CSVReader r2 = ...; // reader of 2nd file
HashMap<String,String[]> dic = new HashMap<String,String[]>();
int commonCol = 1; // index of the commonColumn
r1.readNext(); // skip header
String[] line = null;
while ((line = r1.readNext()) != null)
{
dic.add(line[commonCol],line)
}
commonCol = 2; // index of the commonColumn in the 2nd file
r2.readNext(); // skip header
String[] line = null;
while ((line = r2.readNext()) != null)
{
if (dic.keySet().contains(line[commonCol])
{
// append line to existing entry
}
else
{
// create a new entry and pre-pend it with default values
// for the columns of file1
}
}
foreach (String[] line : dic.valueSet())
{
// write line to the output file.
}
We can do something like this if we know which columns have the duplicate data
int n1,n2;//stores the serial number of the column that has the duplicate data
BufferedReader br1=new BufferedReader(new InputStreamReader(new FileInputStream(f1)));
BufferedReader br2=new BufferedReader(new InputStreamReader(new FileInputStream(f2)));
String line1,line2;
while((line1=br1.readLine())!=null && (line2=br2.readLine())!=null){
String line=line1+","+line2;
String newL="";
StringTokenizer st=new StringTokenizer(line,",");
for(int i=1;i<=st.countTokens();i++){
if((i==n1)||(i==n1+n2))
continue;
else
newL=newL+","+st.nextToken();
}
String l=newL.substring(1);
//write this line to the output file
}

Using BufferedReader to count rows in a multi-dimensional array

I'm using BufferedReader to read a .csv file. I have no problem reading the file and extracting the data. However, the problem that I do have is that I have to hard-code my array declaration. For example:
String[][] numbers=new String[5258][16];
The .csv file I was using had 5258 rows and 16 columns. I'd like to be able to do something like this though:
String[][] numbers=new String[rowsInFile][16];
In other words, I want the variable 'rowsInFile' to be equivalent to the amount of rows in the file (I don't want to count the columns, because every .csv file I will be running through this program has 16 columns).
Here's the code I have so far:
int row = 0;
int col = 0;
String fileInput = JOptionPane.showInputDialog(null,
"Please enter the path of the CSV file to read:");
File file = new File(fileInput);
BufferedReader bufRdr;
bufRdr = new BufferedReader(new FileReader(file));
String line = null;
//get rows in the file
int rowsInFile = 0;
while(bufRdr.readLine() != null) {
rowsInFile++;
row++;
}
String[][] numbers=new String[rowsInFile][16];
//read each line of text file
row = 0;
while((line = bufRdr.readLine()) != null) {
StringTokenizer st = new StringTokenizer(line,",");
col=0;
while (st.hasMoreTokens()) {
//get next token and store it in the array
numbers[row][col] = st.nextToken();
col++;
}
row++;
}
However, I'm getting a null pointer exception. Any ideas of what I should do?
P.S. Yes, this code is surrounded by a try/catch statement.
The problem is, once you go through the BufferedReader once, you can't go back through it again. In other words, you have to use a new BufferedReader.
bufRdr = new BufferedReader(new FileReader(file));
row = 0;
while((line = bufRdr.readLine()) != null) {
Alternatively, you could use a dynamic array structure like an ArrayList<String[]> or a LinkedList<String[]> to store the rows.
LinkedList<String[]> numbers = new LinkedList<String[]>();
while( (line = bufRdr.readLine()) != null ) {
numbers.add(line.split(","));
}
Then instead of doing numbers[i][j], you use numbers.get(i)[j].
Instead of an array use something dynamic like a List. For example:
List<String[]> data = new ArrayList<String[]>();
Also using String's split() method will simplify the loading of the row.
Your problem is that BufferedReaders work by reading until the end of a file, and then they get stuck there. Your code requires reading through the file twice, but because you already reached an EOF, the BufferedReader is stuck returning null. I tend to solve this by stuffing the lines into an ArrayList, and using the size() method to get the number of lines. The source code looks something like this:
int rowsInFile=0;
ArrayList<String> lines = new ArrayList<String>();
String tmp = "";
while(tmp=bugRdr.readLine())
{
lines.add(tmp);
}
rowsInFile = lines.size();
String[][] numbers = new String[rowsInFile][16];
int row = 0;
for(String line : lines)
{
StringTokenizer st = new StringTokenizer(line,",");
col=0;
while (st.hasMoreTokens()) {
//get next token and store it in the array
numbers[row][col] = st.nextToken();
col++;
}
row++;
}

Categories

Resources