How do I read a CSV File with JAVA - java

I have a probem, and I didnt find any solution yet. Following Problem: I have to read a CSV File which has to look like this:
First Name,Second Name,Age,
Lucas,Miller,17,
Bob,Jefferson,55,
Andrew,Washington,31,
The assignment is to read this CSV File with JAVA and display it like this:
First Name: Lucas
Second Name: Miller
Age: 17
The Attribut Names are not always the same, so it also could be:
Street,Number,Postal Code,ID,
Schoolstreet,93,20000,364236492,
("," has to be replaced with ";")
Also the file Adress is not always the same.
I already have the view etc. I only need the MODEL.
Thanks for your help. :))
I already have a FileChooser class in Controller, which returns an URI.

If your CSV file(s) always contains a Header Line which indicates the Table Column Names then it's just a matter of catching this line and splitting it so as to place those column names into a String Array (or collection, or whatever). The length of this array determines the amount of data expected to be available for each record data line. Once you have the Column Names it's gets relatively easy from there.
How you acquire your CSV file path and it's format type is obviously up to you but here is a general concept how to carry out the task at hand:
public static void readCsvToConsole(String csvFilePath, String csvDelimiter) {
String line; // To hold each valid data line.
String[] columnNames = new String[0]; // To hold Header names.
int dataLineCount = 0; // Count the file lines.
StringBuilder sb = new StringBuilder(); // Used to build the output String.
String ls = System.lineSeparator(); // Use System Line Seperator for output.
// 'Try With Resources' to auto-close the reader
try (BufferedReader br = new BufferedReader(new FileReader(csvFilePath))) {
while ((line = br.readLine()) != null) {
// Skip Blank Lines (if any).
if (line.trim().equals("")) {
continue;
}
dataLineCount++;
// Deal with the Header Line. Line 1 in most CSV files is the Header Line.
if (dataLineCount == 1) {
/* The Regular Expression used in the String#split()
method handles any delimiter/spacing situation.*/
columnNames = line.split("\\s{0,}" + csvDelimiter + "\\s{0,}");
continue; // Don't process this line anymore. Continue loop.
}
// Split the file data line into its respective columnar slot.
String[] lineParts = line.split("\\s{0,}" + csvDelimiter + "\\s{0,}");
/* Iterate through the Column Names and buld a String
using the column names and its' respective data along
with a line break after each Column/Data line. */
for (int i = 0; i < columnNames.length; i++) {
sb.append(columnNames[i]).append(": ").append(lineParts[i]).append(ls);
}
// Display the data record in Console.
System.out.println(sb.toString());
/* Clear the StringBuilder object to prepare for
a new string creation. */
sb.delete(0, sb.capacity());
}
}
// Trap these Exceptions
catch (FileNotFoundException ex) {
System.err.println(ex.getMessage());
}
catch (IOException ex) {
System.err.println(ex.getMessage());
}
}
With this method you can have 1 to thousands of columns, it doesn't matter (not that you would ever have thousands of data columns in any given record but hey....you never know... lol). And to use this method:
// Read CSV To Console Window.
readCsvToConsole("test.csv", ",");

Here is some code that I recently worked on for an interview that might help: https://github.com/KemarCodes/ms3_csv/blob/master/src/main/java/CSVProcess.java
If you always have 3 attributes, I would read the first line of the csv and set values in an object that has three fields: attribute1, attribute2, and attribute3. I would create another class to hold the three values and read all the lines after, creating a new instance each time and reading them in an array list. To print I would just print the values in the attribute class each time alongside each set of values.

Related

Read file using delimiter and add to array

I am trying to read from a text file that is in my project workspace then;
Create an object depending on the first element on the first line of the file
Set some variables within the object
Then add it to my arrayList
I seem to be reading the file ok but am struggling to create the different objects based off what the first element on each line in the text file is
Text file is like this
ul,1,gg,0,33.0
sl,2,hh,0,44.0
My expected result is to create an UltimateLanding object or StrongLanding object based on the first element in the text above file example
Disclaimer - I know the .equals is not correct to use in the IF statement, i've tried many ways to resolve this
My Code -
Edited -
It seems the program is now reading the file and correctly and adding to the array. However, it is only doing this for the first line in the file? There should be 2 objects created as there are 2 lines in the text file.
Scanner myFile = new Scanner(fr);
String line;
myFile.useDelimiter(",");
while (myFile.hasNext()) {
line = myFile.next();
if (line.equals("sl")) {
StrongLanding sl = new StrongLanding();
sl.setLandingId(Integer.parseInt(myFile.next()));
sl.setLandingDesc(myFile.next());
sl.setNumLandings(Integer.parseInt(myFile.next()));
sl.setCost(Double.parseDouble(myFile.next()));
landings.add(sl);
} else if (line.equals("ul")) {
UltimateLanding ul = new UltimateLanding();
ul.setLandingId(Integer.parseInt(myFile.next()));
ul.setLandingDesc(myFile.next());
ul.setNumLandings(Integer.parseInt(myFile.next()));
ul.setCost(Double.parseDouble(myFile.next()));
landings.add(ul);
}
}
TIA
There are multiple issues with your current code.
myFile.equals("sl") compares your Scanner object with a String. You would actually want to compare your read string line, not your Scanner object. So line.equals("sl").
nextLine() will read the whole line. So line will never be equal to "sl". You should split the line using your specified delimiter, then use the split parts to build your object. This way, you will not have to worry about newline in combination with next().
Currently, your evaluation of the read input is outside of the while loop, so you will read all the content of the file, but only evaluate the last line (currently). You should move the evaluation of the input and creation of your landing objects inside the while loop.
All suggestions implemented:
...
Scanner myFile = new Scanner(fr);
// no need to specify a delimiter, since you want to read line by line
String line;
String[] splitLine;
while (myFile.hasNextLine()) {
line = myFile.nextLine();
splitLine = line.split(","); // split the line by ","
if (splitLine[0].equals("sl")) {
StrongLanding sl = new StrongLanding();
sl.setLandingId(Integer.parseInt(splitLine[1]));
sl.setLandingDesc(splitLine[2]);
sl.setNumLandings(Integer.parseInt(splitLine[3]));
sl.setCost(Double.parseDouble(splitLine[4]));
landings.add(sl);
} else if (splitLine[0].equals("ul")) {
UltimateLanding ul = new UltimateLanding();
ul.setLandingId(Integer.parseInt(splitLine[1]));
ul.setLandingDesc(splitLine[2]);
ul.setNumLandings(Integer.parseInt(splitLine[3]));
ul.setCost(Double.parseDouble(splitLine[4]));
landings.add(ul);
}
}
...
However, if you don't want to read the contents line by line (due to whatever requirement you have), you can keep reading it via next(), but you have to specify the delimiter correctly:
...
Scanner myFile = new Scanner(fr);
String line; // variable naming could be improved, since it's not the line
myFile.useDelimiter(",|\\n"); // comma and newline as delimiters
while (myFile.hasNext()) {
line = myFile.next();
if (line.equals("sl")) {
StrongLanding sl = new StrongLanding();
sl.setLandingId(Integer.parseInt(myFile.next()));
sl.setLandingDesc(myFile.next());
sl.setNumLandings(Integer.parseInt(myFile.next()));
sl.setCost(Double.parseDouble(myFile.next()));
landings.add(sl);
} else if (line.equals("ul")) {
UltimateLanding ul = new UltimateLanding();
ul.setLandingId(Integer.parseInt(myFile.next()));
ul.setLandingDesc(myFile.next());
ul.setNumLandings(Integer.parseInt(myFile.next()));
ul.setCost(Double.parseDouble(myFile.next()));
landings.add(ul);
}
}
...
A solution.
List<Landing> landings = Files.lines(Paths.get("LandingsData.txt")).map(line -> {
String[] split = line.split(",");
if (split[0].equals("sl")) {
StrongLanding sl = new StrongLanding();
sl.setLandingId(Integer.parseInt(split[1]));
sl.setLandingDesc(split[2]);
sl.setNumLandings(split[3]);
sl.setCost(Double.parseDouble(split[4]));
return sl;
} else if (split[0].equals("ul")) {
UltimateLanding ul = new UltimateLanding();
ul.setLandingId(Integer.parseInt(split[1]));
ul.setLandingDesc(split[2]);
ul.setNumLandings(split[3]);
ul.setCost(Double.parseDouble(split[4]));
return ul;
}
return null;
}).filter(t -> t!= null).collect(Collectors.toList());

How to delete a specific row from a CSV file using search string

I am working on java project where I have to delete a specific row from a CSV file using java. Currently I am using opencsv. I am trying to achieve the below scenario where I have to delete the 3rd row from the list and I have two strings as input.
String 1 : cat
String 2 : mars
I am able to get the exact row and its number with my current code. How can I delete this row?
Here is my code:
private static void updateCsv(String string1 , String String2) throws IOException {
try {
CSVReader reader = new CSVReader(new FileReader(OUTPUTFILE), ',');
List<String[]> myEntries = reader.readAll();
reader.close();
//Iterate through my array to find the row the user input is located on
int i = 1;
for (String[] line : myEntries) {
String textLine = Arrays.toString(line).replaceAll("\\[|\\]", "");
//here i am checking for the two strings
if (textLine.contains(string1) && textLine.contains(string2) ) {
//here i am able to get the count the row as 3
System.out.println("Found - Your item is on row: ...:" + i);
// how can i delete the row that i have now ?
} else {
//System.out.println("Not found");
}
i++;
}
} catch (IOException e) {
System.out.println(e);
}
}
List<String[]> filtered = myEntries.stream()
.filter(entry -> !entry[1].equals(string1) &&
!entry[2].equals(string2)
.collect(Collectors.toList());
FileWriter fw = new FileWriter("result.csv");
CSVWriter w = new CSVWriter(fw);
filtered.forEach(line -> w.writeNext(line));
You can't delete a line from a file in java.
In the code in your question you load the entire contents of the CSV file into a List. What you want is to write all the List entries to a file except the line that contains string1 and string2.
According to the sample data in your question, string1 is compared with column B and string2 is compared with column C. Column B corresponds to the element at index 1 in the String array that contains a single line from the CSV file. Similarly, column C corresponds to index 2.
Using the stream API, that was introduced in Java 8, you simply filter out the unwanted line. The resulting list contains all the lines that you want to keep, so just write them to another file. After that, if you like, you can delete the original CSV file and rename the resulting file (which I named "result.csv" in my code, above).

How to replace a data in arff file?

I have an arff file that needs to be modified while keeping the same structure of the file each time I run the code.
For example I have the following arff file
#relation australian
#attribute A1 numeric
#attribute A2 numeric
#attribute A3 numeric
#attribute A4 numeric
#attribute A5 numeric
#attribute A6 numeric
#attribute A7 {0,1}
#data
1,3,5,2,4,3,1
3,5,1,2,5,6,0
6,1,4,2,3,4,1
I need to replace the three lines of data with another three lines each time I run the code
I use the following code but it appends the new data to the old data not replacing it.
BufferedReader reader = new BufferedReader(new FileReader("aa.txt"));
String toWrite = "";
String line = null;
while ((line = reader.readLine()) != null) {
toWrite += line;
// System.out.println(toWrite);
}
FileWriter fw = new FileWriter("colon.arff",true);
fw.write(toWrite);
fw.close();
To clear up a couple things:
FileWriter fw = new FileWriter("colon.arff", true);
In your FileWriter declaration you utilize the boolean append flag as true which enables appending to the file supplied. I'm not sure this is really what you want considering the fact that you want the data being written to the file to be the very same format as the file being read. You wouldn't want the chance of anything to be appended to that file therefore distorting the original content format.
toWrite += line;
Doing concatenations like this within a loop is never really a good idea (yes, I still do it from time to time for simple things and demo purposes). Simple concatenations outside of a loop is fine since the compiler utilizes StringBuilder anyways if it thinks it will be more beneficial. It's just better to use the StringBuilder class for the following reason:
In Java, string objects are immutable, which means once it is created, you cannot change it. So when we concatenate one string with another, a new string is created, and the older one is marked for the garbage collector. Let's say we need to concatenate a million strings. Then, we are creating 1 million extra strings which will eventually be garbage collected.
To solve this problem, the StringBuilder class is used. It works like a mutable String object. The StringBuilder#append() method helps to avoid all the copying required in string concatenation. To utilize StringBuilder in your case you would declare the builder above the while loop:
StringBuilder toWrite = new StringBuilder();
and then within the loop:
toWrite.append(line).append(System.lineSeparator());
Notice the additional append(System.lineSeparator())? When you want to write a finished line to a file with FileWriter you need to add a Line Break ("\n" or "\r\n" depending on the OS) so that the next line that will need to be written will be on a new line within the file. In this case you are actually building the String that will be written to the file on a single write so if an appended string needs to be on a new line within the file then a line break needs to also be appended. The System.lineSeparator() method returns the Operating System dependent Line Break character(s).
The code below will do what you're asking:
// Demo data to replace in file...
String[] newData = {"4,2,13,1,4,2,0",
"1,3,3,5,2,4,1",
"7,7,2,1,5,8,1"};
// 'Try With Resourses' is used here to auto-close the reader and writer.
try (BufferedReader reader = new BufferedReader(new FileReader("aa.txt"));
FileWriter fw = new FileWriter("colon.arff")) {
String ls = System.lineSeparator(); // The Line Break use by OS.
StringBuilder toWrite = new StringBuilder(); // A String builder object
int skip = 0; // Used for skipping old file data for placement of the new data
String line = null; // Use to hold file lines read (one at a time)
// Start reading file...
while ((line = reader.readLine()) != null) {
/* If skip is greater than 0 then read in next line and
decrement skip by 1. This is used in case the data
in file contains more rows of data than what you are
replacing. */
if (skip > 0) {
skip--;
continue;
}
// Append the file line read into the StringBuilder object
toWrite.append(line).append(ls);
// If the file line read equals "#data"
if (line.trim().equals("#data")) {
/* Append the new data to the toWrite variable here,
for example: if the new data was in a string array
named newData (see above declaration)... */
for (int i = 0; i < newData.length; i++) {
/* Perform new data Validation...
Make sure all values are string representations
of numerical data and that the 7th column of data
is no less than 0 and no more than 1. */
String[] ndParts = newData[i].split("\\s{0,},\\s{0,}"); // Split the current data row
boolean isValid = true; // flag
for (int v = 0; v < ndParts.length; v++) {
if (!ndParts[v].matches("\\d+") ||
(v == 6 && (!ndParts[v].equals("0") &&
!ndParts[v].equals("1")))) {
isValid = false;
System.err.println("Invalid numerical value supplied on Row " +
(i+1) + " in Column " + (v+1) + ". (Data: " + newData[i] + ")" +
ls + "Not writing data line to file!");
break;
}
}
/* If the current new data row is valid then append
it to the build and increment skip by 1. */
if (isValid) {
toWrite.append(newData[i]).append(ls);
skip++;
}
}
}
}
// Write the entire built string to file.
fw.write(toWrite.toString());
}
catch (FileNotFoundException ex) {
System.err.println(ex.getMessage());
}
catch (IOException ex) {
System.err.println(ex.getMessage());
}

Searching a text file in java and Listing the results

I've really searched around for ideas on how to go about this, and so far nothing's turned up.
I need to search a text file via keywords entered in a JTextField and present the search results to a user in an array of columns, like how google does it. The text file has a lot of content, about 22,000 lines of text. I want to be able to sift through lines not containing the words specified in the JTextField and only present lines containing at least one of the words in the JTextField in rows of search results, each row being a line from the text file.
Anyone has any ideas on how to go about this? Would really appreciate any kind of help. Thank you in advance
You can read the file line by line and search in every line for your keywords. If you find one, store the line in an array.
But first split you text box String by whitespaces and create the array:
String[] keyWords = yourTextBoxString.split(" ");
ArrayList<String> results = new ArrayList<String>();
Reading the file line by line:
void readFileLineByLine(File file) {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
processOneLine(line);
}
br.close();
}
Processing the line:
void processOneLine(String line) {
for (String currentKey : keyWords) {
if (line.contains(currentKey) {
results.add(line);
break;
}
}
}
I have not testst this, but you should get a overview on how you can do this.
If you need more speed, you can also use a RegularExpression to search for the keywords so you don't need this for loop.
Read in file, as per the Oracle tutorial, http://docs.oracle.com/javase/tutorial/essential/io/file.html#textfiles Iterate through each line and search for your keyword(s) using String's contain method. If it contains the search phrase, place the line and line number in a results List. When you've finished you can display the results list to the user.
You need a method as follows:
List<String> searchFile(String path, String match){
List<String> linesToPresent = new ArrayList<String>();
File f = new File(path);
FileReader fr;
try {
fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
String line;
do{
line = br.readLine();
Pattern p = Pattern.compile(match);
Matcher m = p.matcher(line);
if(m.find())
linesToPresent.add(line);
} while(line != null);
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return linesToPresent;
}
It searches a file line by line and checks with regex if a line contains a "match" String. If you have many Strings to check you can change the second parameter to String[] match and with a foreach loop check for each String match.
You can use :
FileUtils
This will read each line and return you a List<String>.
You can iterate over this List<String> and check whether the String contains the word entered by the user, if it contains, add it to another List<String>. then at the end you will be having another List<String> which contains all the lines which contains the word entered by the user. You can iterate this List<String> and display the result to the user.

How to parse a text file and create a database record from it

I'm trying to basically make a simple Test Generator. I want a button to parse a text file and add the records to my database. The questions and answers are in a text file. I have been searching the net for examples but I can't find one that matches my situation.
The text file has header information that I want to ignore up until the line that starts with "~ End of Syllabus". I want "~ End of Syllabus" to indicate the beginning of the questions. A couple of lines after that look for a line with a "(" in the seventh character position. I want that to indicate the Question Number line. The Question Number line is unique in that the "(" is in the seventh character position. I want to use that as an indicator to mark the start of a new question. In the Question Number line, the first three characters together "T1A" are the Question Group. The last part of the T1A*01* is the question number within that group.
So, as you can see I will also need to get the actual question text line and the answer lines as well. Also typically after the four Answer lines is the Question Terminator indicated by "~~". I don't know how I would be able to do this for all the questions in the text file. Do I keep adding them to an array String? How would I access this information from the file and add it to a database. This is very confusing for me and the way I feel I could learn how this works is by seeing an example that covers my situation. Here is a link to the text file I'm talking about:http://pastebin.com/3U3uwLHN
Code:
public static void main(String args[]) {
String endOfSyllabus = "~ End of Syllabus";
Path objPath = Paths.get("2014HamTechnician.txt");
String[] restOfTextFile = null;
if (Files.exists(objPath)){
File objFile = objPath.toFile();
try(BufferedReader in = new BufferedReader(
new FileReader(objFile))){
String line = in.readLine();
List<String> linesFile = new LinkedList<>();
while(line != null){
linesFile.add(line);
line = in.readLine();
}
System.out.println(linesFile);
}
catch(IOException e){
System.out.println(e);
}
}
else{
System.out.println(
objPath.toAbsolutePath() + " doesn't exist");
}
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new A19015_Form().setVisible(true);
}
});
}
Reading a text file in Java is straight forward (and there are sure to be other, more creative/efficient ways to do this):
try (BufferedReader reader = new BufferedReader(new FileReader(path))) { //try with resources needs JDK 7
int lineNum = 0;
String readLine;
while ((readLine = reader.readLine()) != null) { //read until end of stream
Skipping an arbitrary amount of lines can be accomplished like this:
if (lineNum == 0) {
lineNum++;
continue;
}
Your real problem is the text to split on. Had you been using CSV you could use String[] nextLine = readLine.split("\t"); to split each line into its respective cells based on tab separation. But your not, so you'll be stuck with reading each line, and than find something to split on.
It seems like you're in control of the text file format. If you are, go to an easier to consume format such as CSV, otherwise you're going to be designing a custom parser for your format.
A bonus to using CSV is it can mirror a database very effectivly. I.e. your CSV header column = database column.
As far as databases go, using JDBC is easy enough, just make sure you use prepared statements to insert your data to prevent against SQL injection:
public Connection connectToDatabase(){
String url = "jdbc:postgresql://url";
return DriverManager.getConnection(url);
}
Connection conn = connectToDatabase();
PreparedStatement pstInsert = conn.prepareStatement(cInsert);
pstInsert.setTimestamp(1, fromTS1);
pstInsert.setString(2, nextLine[1]);
pstInsert.execute();
pstInsert.close();
conn.close();
--Edit--
I didn't see your pastebin earlier on. It doesn't appear that you're in charge of the file format, so you're going to need to split on spaces ( each word ) and rely on regular expressions to determine if this is a question or not. Fortunately it seems the file is fairly consistent so you should be able to do this without too much problem.
--Edit 2--
As a possible solution you can try this untested code:
try{
BufferedReader reader = new BufferedReader(new FileReader("file.txt")); //try with resources needs JDK 7
boolean doRegex = false;
String readLine;
while ((readLine = reader.readLine()) != null) { //read until end of stream
if(readLine.startsWith("~~ End of Syllabus")){
doRegex = true;
continue; //immediately goto the next iteration
}
if(doRegex){
String[] line = readLine.split(" "); //split on spaces
if(line[0].matches("your regex here")){
//answer should be line[1]
//do logic with your answer here
}
}
}
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}

Categories

Resources