How can I read and write objects from an arraylist? - java

I´m creating an arraylist in my
UserArchive class and add User-objects from my User class:
public class UserArchive implements Serializable {
ArrayList<User> list = new ArrayList<User>();
// Inserts a new User-object
public void regCustomer(User u) {
list.add(u);
}
What is the best way to read and write this list?
I think this is the right way to write it?
public void writeFile() {
File fileName = new File("testList.txt");
try{
FileWriter fw = new FileWriter(fileName);
Writer output = new BufferedWriter(fw);
int sz = list.size();
for(int i = 0; i < sz; i++){
output.write(list.get(i).toString() +"\n");
}
output.close();
} catch(Exception e){
JOptionPane.showMessageDialog(null, "Kan ikke lage denne filen");
}
I´ve tried using BufferedReader to read the file, but can't get list.add(line) to work:
public void readFile() {
String fileName = "testList.txt";
String line;
try{
BufferedReader input = new BufferedReader(new FileReader(fileName));
if(!input.ready()){
throw new IOException();
}
while((line = input.readLine()) != null){
list.add(line);
}
input.close();
} catch(IOException e){
System.out.println(e);
}
}
I know the problem is that line is a String and should some how be a User. Is the problem that I cant use BufferedReader to do this? If so, how am I suppose to read the file?

The simplest way to do it is convert each user to csv format provided the user object is not complex.
For example your user class should look like this
public class User {
private static final String SPLIT_CHAR = ",";
private String field1;
private String field2;
private String field3;
public User(String csv) {
String[] split = csv.split(SPLIT_CHAR);
if (split.length > 0) {
field1 = split[0];
}
if (split.length > 1) {
field2 = split[1];
}
if (split.length > 2) {
field3 = split[2];
}
}
/**
* Setters and getters for fields
*
*
*/
public String toCSV() {
//check null here and pass empty strings
return field1 + SPLIT_CHAR + field2 + SPLIT_CHAR + field3;
}
}
}
While writing the object call
output.write(list.get(i).toCSV() +"\n");
and when reading you can call
list.add(new User(line));

Imagine a simple User class, like so:
public class User {
private int id;
private String username;
// Constructors, etc...
public String toString() {
StringBuilder sb = new StringBuilder("#USER $");
sb.append(id);
sb.append(" $ ");
sb.append(username);
return sb.toString();
}
}
For an user with id = 42 and username = "Dummy", the user String representation would be:
#USER $ 42 $ Dummy
At first glance, your code seems to successfully write these strings to a text file (I haven't tested it yet).
So, the problem lies in reading back the information. This, extracting meaningful information from (in this case) formatted text, is commonly known as parsing.
You want to parse this information, from the lines you read.
Adapting your code:
BufferedReader input = null;
try {
input = new BufferedReader(new FileReader(fileName));
String line;
while((line = input.readLine()) != null) {
list.add(User.parse(line));
}
} catch(IOException e) {
e.printStackTrace();
} finally {
if (input != null) { input.close(); }
}
Note the subtle difference. I've replaced list.add(line) with list.add(User.parse(line)). This is where the magic occurs. Let's go on and implement the parsing method.
public class User {
private int id;
private String username;
// ...
public static User parse(String line) throws Exception {
// Let's split the line on those $ symbols, possibly with spaces.
String[] info = line.split("[ ]*\\$[ ]*");
// Now, we must validate the info gathered.
if (info.length != 3 || !info[0].equals("#USER")) {
// Here would go some exception defined by you.
// Alternatively, handle the error in some other way.
throw new Exception("Unknown data format.");
}
// Let's retrieve the id.
int id;
try {
id = Integer.parseInt(info[1]);
} catch (NumberFormatException ex) {
throw new Exception("Invalid id.");
}
// The username is a String, so it's ok.
// Create new User and return it.
return new User(id, info[2]);
}
}
And you're done!

Related

Returning Strings from a file between 2 specified strings in java

I've been searching the web and I can't seem to find a working solution.
I have a file containing theses lines:
Room 1
Coffee
Iron
Microwave
Room_end
Room 2
Coffee
Iron
Room_end
I want to print all Strings between Room 1 and Room_end. I want my code to start when it find Room 1, print line after Room 1 and stop when it get to the first Room_end it find.
private static String LoadRoom(String fileName) {
List<String> result = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
result = reader.lines()
.dropWhile(line -> !line.equals("Room 1"))
.skip(1)
.takeWhile(line -> !line.equals("Room_end"))
.collect(Collectors.toList());
} catch (IOException ie) {
System.out.println("Unable to create " + fileName + ": " + ie.getMessage());
ie.printStackTrace();
}
for (int i = 0; i < result.size(); i++) {
System.out.println(result.get(i).getname());//error on getname because it cant work with Strings
}
}
class Model {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I am able to get a method to print all Strings of the file but not specific range of Strings. I also tried to work with Stream. My code feel quite messy, but I've been working on it for a while an it seems it only get messier.
I think there is a problem if you want to use lambda expression here:
lambda expressions are functional programming, and functional programming requires immutability, that means there should not be state related issue, you can call the function and give it same parameters and the result always will be the same, but in your case, there should be a state indicating whether you should print the line or not.
can you try this solution? I write it in python, but mainly it is just about a variable should_print that located outside of the scope
should_print = False
result = reader.lines()
for line in result:
if line == "Room end":
break
if should_print:
print(line)
if line == "Room 1":
should_print = True
keep a boolean value outside of the iteration, and check/update the value in each iteration
public static Map<String, List<String>> getRooms(String path) throws IOException {
Map<String, List<String>> result = new HashMap<>();
try (Scanner sc = new Scanner(new File(path))) {
sc.useDelimiter("(?=Room \\d+)|Room_end");
while (sc.hasNext()) {
Scanner lines = new Scanner(sc.next());
String room = lines.nextLine().trim();
List<String> roomFeatures = new ArrayList<>();
while (lines.hasNextLine()) {
roomFeatures.add(lines.nextLine());
}
if (room.length() > 0) {
result.put(room, roomFeatures);
}
}
}
return result;
}
is one way of doing it for your 'rooms file' though it should really be made more OO by making a Room bean to hold the data. Output with your file: {Room 2=[Coffee, Iron ], Room 1=[Coffee, Iron, Microwave]}
Switched my code and used this:
private static String loadRoom(String fileName) {
BufferedReader reader = null;
StringBuilder stringBuilder = new StringBuilder();
try {
reader = new BufferedReader(new FileReader(fileName));
String line = null; //we start with empty info
String ls = System.getProperty("line.separator"); //make a new line
while ((line = reader.readLine()) != null) { //consider if the line is empty or not
if (line.equals("Room 1")) { //condition start on the first line being "Room 1"
line = reader.readLine(); // read the next line, "Room 1" not added to stringBuilder
while (!line.equals("Room_end")) { //check if line String is "Room_end"
stringBuilder.append(line);//add line to stringBuilder
stringBuilder.append(ls);//Change Line in stringBuilder
line = reader.readLine();// read next line
}
}
}
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null)
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return stringBuilder.toString();
}
Here's a solution that uses a scanner and a flag. You may choose to break the loop when it reads "Room_end"
import java.util.Scanner;
import java.io.*;
public class Main{
private static String loadRoom(String fileName) throws IOException {
Scanner s = new Scanner(new File(fileName));
StringBuilder sb = new StringBuilder();
boolean print = false;
while(s.hasNextLine()){
String line = s.nextLine();
if (line.equals("Room 1")) print = true;
else if (line.equals("Room_end")) print = false;
else if (print) sb.append(line).append("\n");
}
return sb.toString();
}
public static void main(String[] args) {
try {
String content = loadRoom("content.txt");
System.out.println(content);
}catch(IOException e){
System.out.println(e.getMessage());
}
}
}

How to replace the first line of a txt document

I would like to replace the first line of the document Vokabeln.txt, where the number of vocabularies is stored, so that when a vocabulary is added, the number is increased by one.
Thanks for helping me.
import java.io.*;
public class Vokabeltrainer
{
private String file;
private String line;
private int anzahlVokabeln;
private boolean status = true;
Scanner sc = new Scanner(System.in);
private ArrayList <Vokabel> Vokabelliste;
public Vokabeltrainer()
{
this.file = "";
this.Vokabelliste = new ArrayList<Vokabel>();
}
public void main() throws IOException
{
System.out.println("Vokabeln.txt");
this.file = ("Vokabeln.txt");
try (BufferedReader br = new BufferedReader(new FileReader(file)))
{
line = br.readLine();
anzahlVokabeln = Integer.parseInt(line);
for(int i = 0;i < anzahlVokabeln; i++)
{
line = br.readLine();
this.Vokabelliste.add(new Vokabel(line.split("\\s+")[0],line.split("\\s+")[1]));
}
}
while(status==true)
{
System.out.println("Was willst du machen \n-Vokabel hinzufügen\n-Vokabel enfernen\n-Vokabeln Abfragen\n-Programm Quit");
String line = sc.nextLine();
if(line.equals("one")||line.equals("Add vocabulary"))
{
Vokabelhinzufügen();
}
else if(line.equals("two")||line.equals("Remove vocabulary"))
{
}
else if(line.equals("three")||line.equals("Vokabeln Abfragen"))
{
}
else if(line.equals("four")||line.equals("Quit"))
{
status = false;
//Maybe Statistics from the User
}
else
{
System.out.println("This option doesnt exists.");
}
}
}
public void Vokabelhinzufügen()
{
boolean vokabelhinzustatus = true;
String Vokabel = "";
while(vokabelhinzustatus==true)
{
System.out.println("Please enter the vocabulary now. (Hallo Hello)");
Vokabel = sc.nextLine();
try(PrintWriter output = new PrintWriter(new FileWriter("Vokabeln.txt",true)))
{
output.printf("%s\r\n", Vokabel.toLowerCase());
String after = String.valueOf(anzahlVokabeln+1);
String before = String.valueOf(anzahlVokabeln);
//At this point the replace has to be. before is the number before the translation was added and after is after the translation was added.
}
catch (Exception e) {}
System.out.println("Vocabulary Successfully Added");
System.out.println("Exit Add Vocabulary?");
String line = sc.nextLine();
if(line.equals("yes"))
{
break;
}
}
}
public void Vokabelentfernen()
{
}
}
Not an answer to your question;
a design suggestion instead.
It appears that you have a file in which you store things
(perhaps Vokablin)
and each thing in the file is structured the same,
but contains different details.
Do not store the count in the file.
Instead,
Just store things in the file and read them all.
If you must,
add a marker at the end of the file that indicates "end of stuff".
For, reasons, you might want to store a count of things in the file.
If that is the case,
store the count as part of the end-of-file marker.
If you use this technique,
your add-to-the-file algorithm becomes this:
Read a line.
Is the line a thing?
if yes, write it,
if no, parse the end-of-file marker, increment the count, and write the end-of-file marker.

How to skip blank cells when reading a csv file in Java?

Trying to create a csv file reader, but the reader gets an ArrayIndexOutOfBoundsException when it comes across an end of line blank.
Example: Name, Email, Age, City
John, johnsmith#email, 23, New York - This works and is standard
John, johnsmith#email, 23, - This fails
,,23,New York - This works
John, johnsmith#email,, - This fails
Any additional feedback is welcome as well!
Here's the code.
public class Main {
static String filepath = "filepath.csv";
public static void main(String[] args) {
SQLiteDB db = new SQLiteDB();
CSVReader(filepath);
}
public static void CSVReader(String filepath) {
List<User> users = new ArrayList<User>();
BufferedReader br = null;
String line;
int count = 1;
try {
br = new BufferedReader(new FileReader(filepath));
while ((line = br.readLine()) != null) {
if(line.trim().length() > 0) {
User user = new User();
String[] userinfo = line.split(",(?=([^\"]|\"[^\"]*\")*$)");
user.firstName = userinfo[0];
user.lastName = userinfo[1];
user.email = userinfo[2];
user.gender = userinfo[3];
user.image = userinfo[4];
user.bank = userinfo[5];
user.transaction = userinfo[6];
user.bool1 = userinfo[7];
user.bool2 = userinfo[8];
user.city = userinfo[9];
users.add(user);
System.out.println("Count:" + count + " " + user.getBool2());
count++;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}
For the city value, just use the ternary operator to check the array length before assignment:
user.city = userinfo.length == 10 ? userinfo[9] : "";
If this is not a homework project, why don't you use a library? There are several on GitHub, and here is one that seems easy to use - https://github.com/osiegmar/FastCSV.

Why I could not save the contents of a file after reading it twice?

Already fixed. Thanks for Mas & ruhul for observing my bugs.
I was trying to read a text file twice, named stationary.txt. The contents of the file has three columns such as the amount, the name of product and the total price.
What I am trying to do first is by averaging each product's price by reading line by line. Then I closed the Buffered and then open it again and read. The second reading takes a variable average and compares each product's price line by line. If line 1 is over the average, then write it into dearer.txt, otherwise write it into cheap.txt
Here is the stationary.txt
1 Highlighter 5.99
2 Pen 9.00
3 Eraser 5.00
4 DrawingPin 2.75
5 Highlighter 10.99
6 FountainPen 20.50
7 Pencil 14.50
Below is the source code
import java.util.*;
import java.io.*;
public class Ques {
public static void main(String[] args) throws FileNotFoundException {
double average = 0;
File inFile = new File("stationary.txt");
FileReader fileReader = new FileReader(inFile);
BufferedReader bufReader = new BufferedReader(fileReader);
File outFilel = new File("dearer.txt");
FileOutputStream outFileStreaml = new FileOutputStream(outFilel);
PrintWriter outStream1 = new PrintWriter(outFileStreaml);
File outFile2 = new File("cheap.txt");
FileOutputStream outFileStream2 = new FileOutputStream(outFile2);
PrintWriter outStream2 = new PrintWriter(outFileStream2);
computeAverage(bufReader, outStream1, outStream2, average);
}
public static void computeAverage(BufferedReader bufReader, PrintWriter outStream1, PrintWriter outStream2, double average) {
String line = "";
double mark = 0;
double sum = 0;
int count = 0;
try {
bufReader.readLine();
while ((line = bufReader.readLine()) != null) {
String [] data = line.split(" ");
mark = Double.parseDouble(data[2]);
sum += mark;
count++;
}
average = sum / count;
compareMark(outStream1, outStream2, average);
} catch (NumberFormatException | IOException e) {
System.out.println(e);
} finally {
if (bufReader != null) {
try {
bufReader.close();
} catch ( IOException e) {
e.printStackTrace();
}
}
}
}
public static void compareMark(PrintWriter outStream1, PrintWriter outStream2, double average) throws FileNotFoundException {
File inFile = new File("stationary.txt");
FileReader fileReader = new FileReader(inFile);
BufferedReader bufReader = new BufferedReader(fileReader);
String line = " ";
double sum = 0;
double mark = 0;
int count = 0;
try {
double ave = (double) Math.round(average * 100) / 100;
System.out.println("another " + ave);
bufReader.readLine();
while ((line = bufReader.readLine()) != null) {
System.out.println(line);
String [] data = line.split(" ");
mark = Double.parseDouble(data[2]);
if (mark > ave) {
System.out.println("Over");
outStream1.write(line);
} else {
System.out.println("Less");
outStream2.write(line);
}
}
} catch (IOException e) {
System.out.println(e);
} catch (NumberFormatException ex) {
System.out.println(ex);
} finally {
if (bufReader != null) {
try {
bufReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
The source code is perfectly working, just that I received 0 bytes of both files after executing reading twice (first, doing average and last, doing comparison). Why is that? what am I doing wrong here?
Thank you for your kind help.
Your code is not correct and does not compile. But the main flaws are the following:
Your Double.parseDouble(data[2]) shouldn't work with your 4th line of data. Better use Double.parseDouble(data[data.length - 1])
Remove the readLine()-calls in front of the while-loop.
Write the lines including a line separator.
Close the OutStreams
The Data File that you have provided have the columns seperated by a space. As the 2nd Column has data which contains spaces, the convertion of data[2] to double will trigger an exception. Which will make the program to close the buffers and exit.
Use Commas to seperate column data.
Use better exception handling to find exceptions easily.
All you need is to close those output stream. As you are using bufferredWriter and not flushing it after each write you need to close those output-stream. which will write back those lines or datas into the file. Here is an example how you can do it:
Example 1: using flush().
....
outStream1.write(line);
outStream1.flush();
} else {
System.out.println("Less");
outStream2.write(line);
outStream2.flush();
}
Example 2: most efficient (either way you need to close those buffer too like bufReader.close())
...
} catch (IOException e) {
System.out.println(e);
} catch (NumberFormatException ex) {
System.out.println(ex);
} finally {
// add try catch.
outStream2.close();
outStream1.close();
if (bufReader != null ... ) {
try {
bufReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
As requested, an example using List
First a class to hold the stationary data, must be completed:
public class Stationary {
private final int id; // or String if desired
private final String name;
private final double mark; // BigDecimal would be better for money
public Stationary(int id, String name, double mark) {
// TODO error checking
this.id = id;
...
}
public int getId() {
return id;
}
... // TODO other getters
// TODO equals, hashCode, toString
}
and to read the file:
public List<Stationary> read(File file) {
List<Stationary> list= new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
// TODO parse line into id, name, mark
list.add(new Stationary(id, name, mark);
}
}
return list;
}
now the list can be used as needed, e.g. average:
List<Stationary> stationaries = read(STATIONARY_FILE);
...
for (Stationary stationary : stationaries) {
sum += stationary.getMark();
count += 1;
}
...
streams not used to keep it simple

Calculating Average from a CSV File

I have a CSV file, format as follows:
City,Job,Salary
Delhi,Doctors,500
Delhi,Lawyers,400
Delhi,Plumbers,100
London,Doctors,800
London,Lawyers,700
London,Plumbers,300
Tokyo,Doctors,900
Tokyo,Lawyers,800
Tokyo,Plumbers,400
Lawyers,Doctors,300
Lawyers,Lawyers,400
Lawyers,Plumbers,500
Hong Kong,Doctors,1800
Hong Kong,Lawyers,1100
Hong Kong,Plumbers,1000
Moscow,Doctors,300
Moscow,Lawyers,200
Moscow,Plumbers,100
Berlin,Doctors,800
Berlin,Plumbers,900
Paris,Doctors,900
Paris,Lawyers,800
Paris,Plumbers,500
Paris,Dog catchers,400
I want to find the average of the total salaries.
This is my code:
` import java.io.*;
public class A {
public static void main(String args[])
{
A a= new A();
a.run();
}
public void run()
{
String csv="C:\\Users\\Dipayan\\Desktop\\salaries.csv";
BufferedReader br = null;
String line = "";
int sum=0;
int count=0;
//String a=new String();
try {
br = new BufferedReader(new FileReader(csv));
try {
while ((line = br.readLine()) != null) {
// use comma as separator
String[] country = line.split(",");
int sal=Integer.parseInt(country[2]);
sum=sum+sal;
count++;
//System.out.println("Salary [job= " + country[0]
// + " , salary=" + country[2] + "]");
}
} catch (NumberFormatException | IOException e) {
System.out.println("NA");
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.println(sum/count);
System.out.println("Done");
}
}`
But, its showing error:
java.lang.NumberFormatException: For input string: "Salary"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at A.run(A.java:30)
at A.main(A.java:9)
Exception in thread "main" java.lang.ArithmeticException: / by zero
at A.run(A.java:46)
at A.main(A.java:9)`
Is there any better or short code to parse the CSV file.
Skip the first line of the CSV file. Do an additional
br.readLine()
before the while.
You might also want to add some format checks to be sure the file you are reading is in the correct format.
The first line contains the word "Salary" in the third spot. Put br.readLine()before the loop and everything should be fine.
You have:
br = new BufferedReader(new FileReader(csv));
try {
while ((line = br.readLine()) != null) {
Change it to:
br = new BufferedReader(new FileReader(csv));
br.readLine()
try {
while ((line = br.readLine()) != null) {
br.readLine() before the while-loop will avoid header line problem, but if your data is not correct you will get same Exception again, so, in order to make a safer method you can change this line:
int sal=Integer.parseInt(country[2]);
With a try-catch block to iterate through entire file even if a value is not a valid number
int sal;
try {
sal=Integer.parseInt(country[2]);
} catch (NumberFormatException e) {
// if you want here you can show an error message
// to give feedback to the user there is not a valid number
}
First, use a CSV parser - I will use OpenCSV in this example. I have no affiliation with OpenCSV, it's just what I have in my POM at the moment.
First, create a class:
public class Salary {
private String city;
private String job;
private long salary;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public long getSalary() {
return salary;
}
public void setSalary(long salary) {
this.salary = salary;
}
}
Now your CSV has three columns, and the header of the CSV matches the property names of our bean, so we can simply use a HeaderColumnNameMappingStrategy to determine which properties to set on the bean:
final HeaderColumnNameMappingStrategy<Salary> mappingStrategy = new HeaderColumnNameMappingStrategy<>();
mappingStrategy.setType(Salary.class);
Now we just need to parse the CSV file into a List of our beans:
final CsvToBean<Salary> csvToBean = new CsvToBean<>();
try (final Reader reader = ...) {
final List<Salary> salaries = csvToBean.parse(mappingStrategy, reader);
}
Okay.
Now, how do you get an average salary from this mess? Just use a Java 8 Stream on the result:
final LongSummaryStatistics statistics = salaries.stream()
.mapToLong(Salary::getSalary)
.summaryStatistics();
Now we can get all sorts of useful information:
final long min = statistics.getMin();
final double average = statistics.getAverage();
final long max = statistics.getMax();

Categories