Add text file data to a Arraylist - java

I want to add text file data to an ArrayList.
This is my text file
60000115 2016-10-26-05:57:47
60000104 2016-10-26-05:58:27
60000082 2016-10-26-05:58:38
60000074 2016-10-26-06:01:04
I am split data using space. So there are bassically two part. Id and Date.
I created a bean class called Employee with two String called user_id and mDate.
employeArrayList is the ArrayList that i created using Employee class.
Problem is I cannot add values to the Arraylist. Only the last row data is inserting to the ArrayList. For ex :- 60000074 2016-10-26-06:01:04 .
Four rows of 60000074 2016-10-26-06:01:04 .
This is my code.
for (File f : files) {
FileInputStream fis;
try {
fis = new FileInputStream(f);
BufferedReader in = new BufferedReader(new InputStreamReader(fis));
String aLine;
while ((aLine = in.readLine()) != null) {
String[] tokens = aLine.split(" ");
emp.setUser_id(tokens[0]);
emp.setmDate(tokens[1]);
employeArrayList.add(emp);
out.write(aLine);
out.newLine();
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}

Create a new Employee object each time:
while ((aLine = in.readLine()) != null) {
String[] tokens = aLine.split(" ");
Employee emp = new Employee();
emp.setUser_id(tokens[0]);
emp.setmDate(tokens[1]);
employeArrayList.add(emp);
out.write(aLine);
out.newLine();
}
The problem with your original code is that you were reusing the same object emp. This means that you were inserting the same object repeatedly into the list. And when you changed the fields of that object in each iteration of the loop, you affected every entry in the list. By scoping emp to the loop, it won't be recycled and your code should work as intended.

The problem is that you keep updating the same emp object over and over again.
You have to create a new one for each iteration; and add that.
Besides: you should only use "beans" with setters for core properties when using frameworks that need them.
In other words: your bean class should better look like
public class EmplyoeeBeen {
private final String id;
private final String date;
public EmplyoeeBeen(String id, String date) {
this.id = id;
...
And you only have getters on that class, no setters! And: you probably want nice equals/hashCode methods, too.
Finally: be consistent about naming: do not use "_" underscores (they only go into CONSTANT_NAMES); and either use prefixes like "m" + fieldname ... all the time; or never. But dont go for userId and mDate!
But the most important thing: avoid stringified typing. What I mean is: an ID is not a string. A date is not a date. When your fields carry a meaning; then use **classes to represent them that carry that meaning, too. For example you could invent your own Id class; and for sure: you would want to turn the date string into a real Date object.

There is no need to create tokens variable each time. As String is immutable class you can reassign the value directly.
String[] tokens = null;
for (File f : files) {
FileInputStream fis;
try {
fis = new FileInputStream(f);
BufferedReader in = new BufferedReader(new InputStreamReader(fis));
String aLine;
while ((aLine = in.readLine()) != null) {
Employee emp = new Employee();
tokens = aLine.split(" ");
emp.setUser_id(tokens[0]);
emp.setmDate(tokens[1]);
employeArrayList.add(emp);
out.write(aLine);
out.newLine();
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Also create the Employee object each time for every line.
Another best way is to save your data in such a way that you can directly save it to bean.
Save in JSON format. And parse that data using GSON. You can use array of user and Data as ArrayList in Bean.

This is because of you are not creating new employee object each time. change your code like below, so that it will not take same object each time
for (File f : files) {
FileInputStream fis;
try {
fis = new FileInputStream(f);
BufferedReader in = new BufferedReader(new InputStreamReader(fis));
String aLine;
while ((aLine = in.readLine()) != null) {
String[] tokens = aLine.split(" ");
Employee emp=new Employee(); //create new object of employee
emp.setUser_id(tokens[0]);
emp.setmDate(tokens[1]);
employeArrayList.add(emp);
out.write(aLine);
out.newLine();
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}

Please Try This
List <String,String> emp = new ArrayList<String,String>();
emp.add(tokens[0],tokens[1]);

Issue : You are using same object by changing the values. It will reflect the latest values but all of them in that array list will point the single object in Memory.
1.Create the Employee been inside the loop so that you can create new object for each iteration.
Clone the employee object and add it into the list

Related

Reading and splitting data from a text file

So I have a text file that looks like this...
4234
Bob
6858
Joe
I am trying to read the file with java and insert the data into an array. I want to separate the data by that empty line (space). Here is the code that I have come up with to solve the issue, but I am not quite there.
public class Main {
public static void main(String[] args) {
// This name is used when saving the file
BufferedReader input;
String inputLine;
try {
input = new BufferedReader(new FileReader("test.txt"));
while ((inputLine = input.readLine()) != null) {
System.out.println(Arrays.toString(inputLine.split(" ")));
}
} catch (IOException e) {
System.out.println(e.getMessage());
System.exit(1);
}
}
}
The issue that I am coming across is that the output from the code above looks something like this
[4234]
[Bob]
[]
[6858]
[Joe]
The outcome that I would like to achieve, and for the life of me can't think of how to accomplish, is
[4234, Bob]
[6858, Joe]
I feel like with many things that it is a relatively simple code change; I am just not sure what that is.
You need:
2D array
Logic to keep track of where you are in the array position
If your Line is a Number/String
This sounds like hw :) so I wont be solving it, I will just help a bit.
String[][] myData = define your 2D array;
//You need to create a consumer. This is what will take the String line, figure out where to put it into your 2D array.
Consumer<String> processLine = (line) -> {
if(StringUtils.isNumeric(line)){
//Put into array[counter][1]
}
else{
//its a String
//Put into array[counter][0]
}
};
The below try/catch, Opens a File, Reads its Lines, and goes over each one in order (forEachOrdered), ignoring all empty lines, and send it to your processLine consumer.
try (Stream<String> lines = Files.lines(Paths.get("C:/example.txt"), Charset.defaultCharset())) {
lines.filter(line -> !line.isEmpty()).forEachOrdered(processLine);
}
catch (Exception e){
//Handle Exception
}
Used Apache StringUtils http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html
IF you dont want to use any external Libs. You can probably do
Integer.parseInt(line) <-- If that throws an exception, its not a number
Your way of reading the file is not most convenient, in this case.. Scanner would have eased all this work; however, if you insist, that you want to use BufferedReader and FileReader, it's going to be a bit verbose, boilerplate and even ugly code, something like this:
public class Main {
public static void main(String[] args) {
// This name is used when saving the file
BufferedReader input;
String inputLine;
String answer = "";
try {
input = new BufferedReader(new FileReader("path\\to\\your\\test.txt"));
while ((inputLine = input.readLine()) != null) {
answer = answer + "[" + inputLine + ", ";
while ((inputLine = input.readLine()) != null && !inputLine.equals("")) {
answer += inputLine;
}
answer += "]";
System.out.println(answer);
answer = "";
}
} catch (IOException e) {
System.out.println(e.getMessage());
System.exit(1);
}
}
}
This code, with test.txt containing:
4234
Bob
6858
Joe
4234
John
5352
Martin
will output:
[4234, Bob]
[6858, Joe]
[4234, John]
[5352, Martin]
I don't know if it's an actual requirement for you to use arrays of strings, but the better way in the long run is to create a class.
class Person {
public String id;
public String name;
public String toString() { return String.format("[%s, %s]", id, name); }
}
(note: It's a bad idea to actually make the fields public, but this makes the code shorter. You should probably use getters and setters).
Now you can create Persons while reading the file.
List<Person> allInFile = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader("path\\to\\your\\test.txt"))) {
String line = reader.readLine();
while (line != null) {
line = line.trim();
// ignore empty lines
if (line.length() == 0) {
continue;
}
// this is an id; create a person and assign id
Person person = new Person();
person.id = line;
// read consecutive field, which is the name
person.name = reader.readLine();
// add the person to the list
allInFile.add(person);
}
}
allInFile.forEach(System.out::println);
Lots of improvements to be done on this, but the main point is to put the two data points into a class.
Try with this code:
it work only when file contains number followed by name otherwise pair would be different format
pair : [number, string]
public static void main(String[] args) {
BufferedReader input;
String inputLine;
List<String> pair = new ArrayList<String>();
List<String> list = new ArrayList<String>();
try {
input = new BufferedReader(new FileReader("Test.txt"));
while ((inputLine = input.readLine()) != null) {
if (!inputLine.isEmpty()) {
pair.add(inputLine);
}
if (pair.size() == 2) {
list.add(pair.toString());
pair.clear();
}
}
for (String s : list) {
System.out.println(s);
}
} catch (IOException e) {
System.out.println(e.getMessage());
System.exit(1);
}
}
After looking at the answers posted by my fellow Stack Overflow members I figured out that there was a very simple way of solving this issue and that was by using Scanner rather than using BufferedReader. I am not sure why I didn't think of this before, but hindsight is 2020. Anyway, the code below is what I used to solve my issue.
public static void main(String[] args) {
ArrayList<String> test = new ArrayList<>();
File file = new File("test.txt");
try {
Scanner sc = new Scanner(file);
while (sc.hasNextLine()) {
test.add(sc.next()); // The id
test.add(sc.next()); // The name
}
sc.close();
System.out.println(test.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
All this is doing is getting each line with the different data on it and is skipping the blank. From there it is adding it to an ArrayList for later processing. Remember K.I.S.S (Keep It Simple Stupid) no need to overcomplicate anything.

Is there a way to generate n differentiable instances of a class using a loop?

I want to asign data, that I previously read from a simple "backup" text file (txt), to n differentiable instances of a class so that I can use those instances later on. Is there a way to achieve this using some kind of loop?
I tried creating multiple instances c_0, c_1, .. , c_n of a class "Category" which store the "category name" from the corresponding line in a txt file. A line from that file starts with the category name followed by a comma and negligible information. Now I want to have n (= amount of lines) different Category instances every time I call this function in the beginning of the script. Up till now I tried the following:
public class Backup{
static int maxC = 0;
public static void main(String[] args) throws IOException{
readC();
}
public static class Category{
private String categoryName;
public Category(String nameC){
categoryName = nameC;
}
}
private static void readC(){
BufferedReader br = null;
String line = "";
String seperate = ",";
int i = 0;
try{
br = new BufferedReader(new FileReader("C:/Users/Public/Category.txt"));
while((line = br.readLine()) != null){
String[] oneLineArray = line.split(seperate);
Category c_i = new Category(oneLineArray[0]); //I have a strong feeling
//that this only creates c_i and not the c_0 c_1 that I would want here
//How can one achieve that?
i++;
}
}catch(FileNotFoundException e){
System.out.println("File does not exist. "+e.getMessage());
}catch(IOException e){
System.out.println("I/O Error. "+e.getMessage());
}finally{
if (br != null){
try{
br.close();
}catch(IOException e){
System.out.println("I/O Error. "+e.getMessage());
}
}
}
maxC = i-1; //this is the amount (n) of instances created
}
}
Like I said, I expected to have multiple instances but i kinda suspect every cycle of the loop is just c_i and not c_0 etc. Can someone enlighten me? Where did I go wrong?
c_i is just the variable name, i there is just a character like c or _.
You want to create either an array or a collection. java.util.ArrayList collection is the easiest choice, it will store all new objects and dynamical adjust size.
List<Category> categories = new ArrayList<>();
while((line = br.readLine()) != null){
String[] oneLineArray = line.split(seperate);
Category c = new Category(oneLineArray[0]);
categories.add(c);
}

Making Data Structure Persistent

I read a file in JAVA and based on the users specifications, I convert the data in to a Linked List or a Tree, but how can I save the data in to the file (as a data structure), so that next time I read the data I do not have to make extra effort to parse the file.
You can save the data like this into file it is not a linked list but it will help to understand
//save persons
public void savePersons(){
try{
PersonsInfo p;
String line;
FileWriter fw= new FileWriter("input.txt");
PrintWriter pw= new PrintWriter(fw);
for (int i=0 ; i<persons.size();i++){
p =(PersonsInfo)persons.get(i);
line = p.getName() +","+ p.getAddress() +","+ p.getPhoneNum();
pw.println(line);
}
pw.flush();
pw.close();
fw.close();
} catch (IOException ioEx){
System.out.println(ioEx);
}
and you can retrieve the data like this and you dont need the parse the file every time
public class AddressBook{
ArrayList<PersonsInfo> persons;
public AddressBook (){
persons = new ArrayList <PersonsInfo> ();
loadPersons();
}
//Load Person
public void loadPersons (){
String tokens[]=null;
String name,address,phoneNum;
try{
FileReader fr= new FileReader("input.txt");
BufferedReader br= new BufferedReader(fr);
String line=br.readLine();
while (line !=null)
{
tokens = line.split(",");
name=tokens[0];
address=tokens[1];
phoneNum=tokens[2];
PersonsInfo p = new PersonsInfo(name,address,phoneNum);
persons.add(p);
line = br.readLine();
}
br.close();
fr.close();
}catch (IOException ioEx) {
System.out.println(ioEx);
}
}
It depends on how you want to store the data:
If you don't want to data to be stored in human readable form then you can go ahead with Serialization (example here). Java will take care of storing/constructing the objects/structures during write/read operations respectively.
If you want to store the data in human readable form then you can convert the data into let's say json and store it in String format. You can use Jackson's ObjectMapper class, e.g.:
ObjectMapper mapper = new ObjectMapper();
YourClass object = new YourClass();
FileOutputStream outputStream = new FileOutputStream("path_to_file");
outputStream.write(mapper.writeValueAsBytes(object));
//Read
YourClass persisted = mapper.readValue("path_to_file", YourClass.class);
Here's the example and here's Jackson's documentation.
You can use serialization which is a Java feature so very easy to use :
Save :
ObjectOutputStream oos = null;
try {
LinkedList<String> list = new LinkedList<>();
list.add("toto"); list.add("tata");
oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\..\\Doc\\list.ser"));
oos.writeObject(list);
} catch ... {
}finally (oos.close) ...{
}
Of course, if it's not a you change LinkedList to whatever you want
Load :
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("C:\\Users\\..\\Doc\\list.ser"));
final LinkedList<String> list = (LinkedList<String>) ois.readObject();
System.out.println(list.toString()); //[toto,tata]
} catch ... {
}finally (ois.close) ...{
}
At writing you use writeObject and at reading you use readObject + casting to the good type (so the order is important, if you write a List then String then Other, you may read List then String then Other)
Serialization Details

Creating objects via txt file into an array in Java

I am trying to complete a little program.
I've got a text file (.txt) to store different data on objects that i've got.
The structure of the file is the next (exemples data.txt) :
Sedane
2005
195000
Diesel
Blue
SUV
2013
34000
Fuel
Black
Each object is made true a class that i've build called Cars.
So the 1 line is the type of car, the 2nd the year of built, the 3rd line is the milage, the 4th is the type of fuel, and the 5th line is the color of the car.
So basicly i need to open the file, and load the data into the memory when i execute my program into an array with object in it.
I'm ok to open the file but i'm blocked when it comes to reading the data and putting it in an array.
The array size is 2 for this exemple, but if i have more entries in the file it's going to adapt it's size when loading at the startup of the program.
Here's what i've got unti now (for my code ...)
public static void loadCars () {
FileReader fopen;
BufferedReader opened;
String line;
try {
fEntree = new FileReader( "data.txt" );
opened = new BufferedReader( fopen );
while ( opened.ready() ) {
line = opened.readLine();
// Don't know what to do here ????
}
opened.close();
} catch ( IOException e ) {
System.out.println( "File doesn't exist !" );
}
}
Someting like this will do the trick. I'm adding the file contents line by line to an Arraylist instead of an array though. This way you don't have to know how big your array needs to be before hand. Plus you can always change it to an array later.
public ArrayList<String> readFileToMemory(String filepath)
{
in = new BufferedReader(new FileReader( "data.txt" ));
String currentLine = null;
ArrayList<String> fileContents = new ArrayList<String>();
try
{
while((currentLine = in.readLine()) != null)
{
fileContents.add(currentLine);
}
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
try
{
in.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
return fileContents;
}
LineNumberReader lnr = new LineNumberReader(new FileReader(new File("File1")));
lnr.skip(Long.MAX_VALUE);
long length = lnr.getLineNumber();
lnr.close();
in = new BufferedReader(new FileReader( "data.txt" ));
Car[] cars= new Car[length/5];
String currentLine;
int i=0;
for(int i=0;i<length/5;i+=5) {
String name = in.readLine();
String year = in.readLine();
String miles = in.readLine();
String gas = in.readLine();
String color = in.readLine();
cars[i] = new Car(name,year,miles,gas,color);
}
You'll have to handle exceptions too, surround stuff in try catch structures.
You can look at my solution here below (I also corrected/simplified some problems with the variables for reading the file, anyway this was not the main topic):
public static void loadCars() {
FileReader fopen;
BufferedReader opened;
String line;
ArrayList<Car> carList = new ArrayList<Car>();
try {
fopen = new FileReader("data.txt");
opened = new BufferedReader(fopen);
int nFields = 5; // we have 5 fields in the Car class
String[] fields = new String[nFields]; // to temporary store fields values read line by line
int lineCounter = 0;
while ((line = opened.readLine()) != null) {
fields[lineCounter] = line;
lineCounter++;
if ((lineCounter) % nFields == 0) { //it means we have all 5 fields values for a car
carList.add(new Car(fields)); //therefore we create a new car and we add it to the list of cars
}
}
opened.close();
} catch (IOException e) {
System.out.println("File doesn't exist !");
}
}
Basically we use an ArrayList to store all the cars, and we read the file, waiting to have all the fields values in order to create the Car object. I store the fields values in an array of Strings: I don't know how you implemented the Car class, but maybe it is useful to create a constructor that takes as parameter an array of strings, so it can set the fields, for instance:
class Car {
private String type;
private String year;
private String milage;
private String fuel;
private String color;
public Car(String[] fields) {
type=fields[0];
year=fields[0];
milage=fields[0];
fuel=fields[0];
type=fields[0];
}
}
But I've to say that probably this is a little 'too static'.
For simplicity I assumed that all your fields are of String type, but probably fields like 'year' or 'milage' might be of int type. In this case you can use array of Object[] (instead of String[]), and then cast the value with the right type.
I hope this may help you.

Initialising an array of objects from a CSV file

This problem takes a bit of explaining, I'll try to be as concise as possible:
I have am trying to initalise an array of Can objects, these objects only have 2 fields (both Strings): name, manufacturer
I am trying to initialise the fields by reading from a CSV file with the following format:
Tomatoes,Heinz
Legumes,Jerry
(no space between the lines, it's being formatted like that on this site for some reason)
The first string in each row is the value I want to be the name, the 2nd is the manufacturer.
So I've created a method to read each line of the CSV, which passes each line to a tokenizer method to extract single values:
private void readFile (String inFilename) {
FileInputStream fileStrm = null;
InputStreamReader rdr;
BufferedReader bufRdr;
int lineNum;
String line;
try {
fileStrm = new FileInputStream(inFilename);
rdr = new InputStreamReader(fileStrm);
bufRdr = new BufferedReader(rdr);
lineNum = 0;
line = bufRdr.readLine();
while {line != null) {
lineNum++;
processLine(line); //passes line to tokenizer
line = bufRdr.readLine();
}
fileStrm.close();
}
catch (IOException e) {
if (fileStrm != null) {
try { fileStrm.close(); } catch (IOException ex2) { }
}
System.out.println("Error in file processing: " + e.getMessage());
}
}
The lines are passed to this tokenizer method:
private String processLine(String csvRow) {
String thisToken = null;
StringTokenizer strTok;
strTok = new StringTokenizer(csvRow, ",");
while (strTok.hasMoreTokens()) {
thisToken = strTok.nextToken();
}
}
And that's where I get a bit stuck. To initialise my array I think I'd need a for loop, something like
for (int i=0; i<=array.length;i++)
{
array[i].name = readFile("filename.csv");
array[i].manufacturer = readFile("filename.csv");
}
But obviously this will not work. Can anyone suggest how I can go about this? I'd prefer to keep the code mostly intact and figure out a solution using the existing code.
Thanks
First thing: -
You are calling processLine(line);, but are not returning the token read from this method.. So, the token obtained in this method in engulped there only.. So, you should return something from that method..
Second:-
array[i].name = readFile("filename.csv");
array[i].manufacturer = readFile("filename.csv");
In the above code, you are calling readFile() each time for the two attributes.. So, even if you return somthing, these two attributes will be initialized to same value.. Because each time you are starting reading file from scratch..
Third thing: -
In fact your above code will not compile.. Because you are assigning the value of readFile() (which is actually not returning anything) to array.. So give a return type to this method.. It would be String.. And returning the tokens read..
EDIT: -
* I would suggest, you can use split() method of String class.. Tokenizer is not needed here, for justsplittingaround a singlecomma(,)`
Also, rather than using an array, you can use ArrayList, in which you can add your newly created object on the fly.. That way, you will not have to fix the size of array.. (And this is what you will want, as you don't know how much line you will have in your file right?)
Here's what you can do: -
Call the method readFile from somewhere, probably main()
readFile("filename.csv")
In your readFile() method, you can iterate over file to create an ArrayList like this: -
List<Can> yourList = new ArrayList<>();
while ((line = reader.readLine()) != null) {
String[] wordRead = line.split(',');
yourList.add(new Can(wordRead[0], wordRead[1]));
}
I assume, Can is the name of your class as you stated in your problem..

Categories

Resources