FileParser Util java method showing null pointer exception - java

I am writing a utility method for parsing csv files. For some reason, this method is showing a null pointer exception during insertion into a list of maps. I am not sure why. Can someone run your eyes on this and explain why this could be happening? This is the point of the nullpointer exception:
record.put(header[i].toString(), nextLine[i].toString());
Here is the file to parse:
id;state;city;total_pop;avg_temp
1;Florida;Miami;120000;76
2;Michigan;Detroit;330000;54
3;New Jersey;Newark;190000;34
And the code:
public class FileParserUtil {
public List<Map<String, String>> parseFile(String fileName, char seperator)
throws IOException {
CSVReader reader = new CSVReader(new FileReader(fileName), seperator);
Map<String, String> record = null;
List<Map<String, String>> rows = null;
// int colcnt = reader.readNext().length;
String[] header = reader.readNext();
String[] nextLine;
while ((nextLine = reader.readNext()) != null) {
for (int i = 0; i< nextLine.length; i++){
System.out.println(header[0]);
System.out.println(nextLine[0]);
System.out.println(header[1]);
System.out.println(nextLine[1]);
System.out.println(nextLine.length);
record.put(header[i].toString(), nextLine[i].toString());
}
rows.add(record);
}
reader.close();
return rows;
}
}

You variable header[i] probably does not have the same length of nextLine[i], so you cannot use the same index i to retrieve its elements.
Edit:
I think you forgot to initialize Map<String, String> record. Is that it?

Related

Why do I need to convert from Integer[] to int[]?

I have the following code
public static int[] readCSV() {
ArrayList<Integer> entries = new ArrayList<>();
try {
File file = new File("someDataFile.csv");
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String line = "";
String[] row;
while((line = br.readLine()) != null) {
row = line.split(",");
for(String value : row) {
int entry = Integer.parseInt(value);
entries.add(entry);
}
}
br.close();
} catch(IOException ioe) {
ioe.printStackTrace();
}
int[] IDs = entries.toArray();
return IDs;
}
Every entry of the csv is an integer stored as a string. I get the following error: "Type mismatch: cannot convert from Object[] to int[]". As far as I understand, "entries" is not an Object[] here, it's an ArrayList<Integer>.
I was using an example given on geeksforgeeks. That didn't work and I'm not sure why.
I also checked the previous answers to the same question, and the top answer works for me. That said, I still don't have an int[], I only have Integer[]. Then I have to do this to convert from Integer[] to int[]. My question is why do I have to do all that instead of int[] IDs = entries.toArray();?
If I do
int[] IDs = new int[entries.size()];
for (int i=0; i<entries.size(); i++) {
IDs[i] = entries.get(i);
}
it works fine. Why is that different from int[] IDs = entries.toArray()?
Is there a better way to get the contents of the csv file in an int[]?
First, to answer your question, because a collection (like ArrayList) can only contain object instances. That means you must use the Integer wrapper type instead of the int primitive type. However, in Java 8+, there are simple ways to perform that conversion. I would also strongly recommend a try-with-Resources over manually closing the BufferedReader. I also simplified the code a little. Like,
public static int[] readCSV() {
List<Integer> entries = new ArrayList<>();
File file = new File("someDataFile.csv");
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
String[] row = line.split("\\s*,\\s*"); // Consume white space
for (String value : row) {
entries.add(Integer.parseInt(value));
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
return entries.stream().mapToInt(Integer::intValue).toArray();
}
List#toArray always returns an Object[]. The closest you can get is entries.toArray(new Integer[0]) to get an Integer[].
To get an int[] you can use the Streams API or loop over the List and copy it over to an array.
Integer[] arr = list.toArray(new Integer[0]);
int[] arr2 = list.stream().mapToInt(i -> i).toArray();

OpenCSV - copying one csv file to another while adding a column

I am trying to read from one CSV file using OpenCSV. I then want to copy all the data from the input csv and output it to another csv file while adding a new column with information.
public void run_streets_tsv( String tsvIn, String tsvOut) throws Exception
{
CSVReader reader = null;
CSVWriter writer = null;
try
{
reader = new CSVReader((new FileReader(tsvIn)));
writer = new CSVWriter(new FileWriter(tsvOut), '\t');
String element [] = null;
List<String[]> a = new ArrayList<String[]>();
while((element = reader.readNext()) != null){
for(int i = 0; i<element.length; i++){
a.add(i, element);
//a.add("JSON"); need to add this json element at the end of each column
}
}
writer.writeAll(a);
}
catch(Exception e)
{
throw e;
}
finally
{
reader.close();
writer.close();
}
}
Another method I am trying is like this (changing the while loop, all other code remains the same):
String element [] = null;
while((element = reader.readNext()) != null){
ArrayList list = new ArrayList(Arrays.asList(reader));
list.add(element);
list.add("JSON");
writer.writeNext(element);
}
This does correctly print all the lines, but it just copies. I want to add that extra "JSON" column with its data.
The following "enlarges" the element-Array by one, enabling you to put something in the newly created last index. Then just save that array.
import java.util.Arrays;
String element[] = null;
while((element = reader.readNext()) != null){
element = Arrays.copyOf(element, element.length + 1);
element[element.length - 1] = "JSON";
writer.writeNext(element);
}
OK, you are close although I see a few errors.
'reader.readNext()' return a line from the input as a String array, we basically need to add an element to this for the output.
while((element = reader.readNext()) != null) {
String[] output = getExpandedArray(element);
a.add(output);
}
You will need to implement getExpandedArray, I will start it off.
private String[] getExpandedArray(String[] input) {
String[] output = null;
//Populate/create output from input, but with the array 1 bigger.
output[output.length -1] = "JSON";
return output;
}

Keep getting Java exception: NoSuchElementException

I keep getting this same exception when I compile. Can anyone explain why I keep getting this error and what it means or what I need to do?
I would like to know what I am doing wrong for future references.
public static void Second()
{
int n = stringList.listSize();
for(int i=0; i<n-1; i=i+2)
{
System.out.println(stringList.retrieveAt(i) + " " + stringList.retrieveAt(i+1));
}
}
public static void Display()throws IOException, FileNotFoundException
{
Scanner infile = new Scanner(new FileReader("D:\\DataFile.txt"));
StringTokenizer token = new StringTokenizer(infile.nextLine());
StringElement str = new StringElement();
while(infile.hasNext())
{
str.setString(token.nextToken());
stringList.insert(str);
}
stringList.print();
}
The exception:
Exception in thread "main" java.util.NoSuchElementException
at java.util.StringTokenizer.nextToken(StringTokenizer.java:349)
at Programmmmmm.Display(Programmmmmm.java:121)
at Programmmmmm.main(Programmmmmm.java:67)
You're calling token.nextToken() without checking whether there are in fact more tokens in token.
Instead of checking whether there infile has more elements, you should check whether token has more tokens.
Instead of
while (infile.hasNext()) { ...
You should do
while (token.hasMoreTokens()) { ...
See Oracle's Java documentation on StringTokenizer for more information and code examples.
You're crossing the streams.
You're looping over the Scanner, but checking nextToken() on the StringTokenizer.
You aren't following the Sun Java coding standards: method names should start with a lower case letter.
That one method is doing far too much:
Reading a hard coded file path.
Tokenizing each line
Printing a list of strings.
Bad idea.
Try something more like this:
public static List<String> tokenizeTextFile(String path) throws IOException, FileNotFoundException {
List<String> words = new ArrayList<String>();
BufferedReader br = null;
if (path != null && path.length() > 0) {
try {
br = new BufferedReader(new FileReader(path));
String line;
while ((line = br.nextLine()) != null) {
String [] tokens = line.split("\\s+");
for (String token : tokens) {
words.add(token);
}
} finally {
close(br); // add this method.
}
}
return words;
}

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 ;)\

Writing back to a csv with Java using super csv

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.

Categories

Resources