Parse text file to object - java

I have few same type text files.
name: Michel;
race: Man;
age: 44;
How to parse them values to List Characters
public class Character {
private String name;
private String race;
private String age;
}

You can use a BufferedReader, FileReader or Scanner object to read txt files in Java. It depends on which you'd like to use for it's functions.
You can use them to iterate trough lines in the txt file and you can put that read content in a String. Then you can assign that stringvalue to your objectvariables.
A quick google brought me to this website which explains the methods complete with code examples: https://www.geeksforgeeks.org/different-ways-reading-text-file-java/

Here add one character with change name class
List<Person> personList = new ArrayList<>();
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(String.valueOf(path))));
String line;
String name = null;
String race = null;
String age = null;
while ((line = br.readLine()) != null) {
if (line.contains("name:")) {
name = line.substring(6, line.length() - 1);
}
if (line.contains("race:")) {
race = line.substring(6, line.length() - 1);
}
if (line.contains("age:")) {
age = line.substring(5, line.length() - 1);
}
}
Person person = new Person();
person.setName(name);
person.setRace(race);
person.setAge(age);
personList.add(person);
return personList;

Related

Copy one element of string array into another java

Hi I'm essentially trying to copy an element of one array into another array. I have the array lineOfData which holds data from a csv file (id, size, custom label) and I want a new array ids that just holds the ids. I have tried ids = lineOfData[0]; but to no avail. what is the best way to do this?
Code:
public class Merge {
String filePath;
public Merge() {
}
public static void main(String[] args) throws FileNotFoundException {
Frame myFrame = new Frame();
FileDialog fileBox = new FileDialog(myFrame, "Open", FileDialog.LOAD);
fileBox.setVisible(true);
String filename = fileBox.getFile();
String directoryPath = fileBox.getDirectory();
if ( filename !=null )
{
String filePath = directoryPath + filename;
//testFile(filePath);
mergeFile(filePath);
}
}
public static void mergeFile(String... filePaths) throws FileNotFoundException {
String[] lineOfData = null;
String[] ids = null;
for(String filePath : filePaths)
{
String path = filePath;
Scanner scanner = new Scanner(new File(path));
String columnTitle = scanner.nextLine();
while(scanner.hasNextLine())
{
//scanner.useDelimiter(",");
String line = scanner.nextLine();
lineOfData = line.split(",");
ids[0] = lineOfData[0];
System.out.println(Arrays.toString(ids));
}
scanner.close();
}
}
You mentioned that you're getting that "The value ids can only be null at this location". This is because you haven't initialized the ids array. Right now, ids isn't pointing to any array. In order to fix this, you
String line = scanner.nextLine();
lineOfData = line.split(",");
ids = new String[lineOfData.length];
ids[0] = lineOfData[0];
if you're going to be adding all the values of lineOfData to ids, or
String line = scanner.nextLine();
lineOfData = line.split(",");
ids = new String[1];
ids[0] = lineOfData[0];
if you only want to copy one element of lineOfData into ids.
Also, notice that lineOfData also starts out by not pointing to any array. However, the lineOfData = line.split(","); line fixes that, and makes it point to an array of Strings. Ask if you have any questions.

read txt file and store data in a hashtable in java

I am reading a txt file and store the data in a hashtable, but I couldn't get the correct output. the txt file like this (part) attached image
this is part of my data
And I want to store the column 1 and column 2 as the key(String type) in hashtable, and column 3 and column 4 as the value (ArrayList type) in hashtable.
My code below:
private Hashtable<String, ArrayList<String[]>> readData() throws Exception {
BufferedReader br = new BufferedReader (new FileReader("MyGridWorld.txt"));
br.readLine();
ArrayList<String[]> value = new ArrayList<String[]>();
String[] probDes = new String[2];
String key = "";
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//System.out.println("line ="+line);
String source;
String action;
//split by tab
String [] splited = line.split("\\t");
source = splited[0];
action = splited[1];
key = source+","+action;
probDes[0] = splited[2];
probDes[1] = splited[3];
value.add(probDes);
hashTableForWorld.put(key, value);
System.out.println("hash table is like this:" +hashTableForWorld);
}
br.close();
return hashTableForWorld;
}
The output looks like this:
it's a very long long line
I think maybe the hashtable is broken, but I don't know why. Thank you for reading my problem.
The first thing we need to establish is that you have a really obvious XY-Problem, in that "what you need to do" and "how you're trying to solve it" are completely at odds with each other.
So let's go back to the original problem and try to work out what we need first.
As best as I can determine, source and action are connected, in that they represent queryable "keys" to your data structure, and probability, destination, and reward are queryable "outcomes" in your data structure. So we'll start by creating objects to represent those two concepts:
public class SourceAction implements Comparable<SourceAction>{
public final String source;
public final String action;
public SourceAction() {
this("", "");
}
public SourceAction(String source, String action) {
this.source = source;
this.action = action;
}
public int compareTo(SourceAction sa) {
int comp = source.compareTo(sa.source);
if(comp != 0) return comp;
return action.compareto(sa.action);
}
public boolean equals(SourceAction sa) {
return source.equals(sa.source) && action.equals(sa.action);
}
public String toString() {
return source + ',' + action;
}
}
public class Outcome {
public String probability; //You can use double if you've written code to parse the probability
public String destination;
public String reward; //you can use double if you're written code to parse the reward
public Outcome() {
this("", "", "");
}
public Outcome(String probability, String destination, String reward) {
this.probability = probability;
this.destination = destination;
this.reward = reward;
}
public boolean equals(Outcome o) {
return probability.equals(o.probability) && destination.equals(o.destination) && reward.equals(o.reward);
public String toString() {
return probability + ',' + destination + ',' + reward;
}
}
So then, given these objects, what sort of Data Structure can properly encapsulate the relationship between these objects, given that a SourceAction seems to have a One-To-Many relationship to Outcome objects? My suggestion is that a Map<SourceAction, List<Outcome>> represents this relationship.
private Map<SourceAction, List<Outcome>> readData() throws Exception {
It is possible to use a Hash Table (in this case, HashMap) to contain these objects, but I'm trying to keep the code as simple as possible, so we're going to stick to the more generic interface.
Then, we can reuse the logic you used in your original code to insert values into this data structure, with a few tweaks.
private Map<SourceAction, List<Outcome>> readData() {
//We're using a try-with-resources block to eliminate the later call to close the reader
try (BufferedReader br = new BufferedReader (new FileReader("MyGridWorld.txt"))) {
br.readLine();//Skip the first line because it's just a header
//I'm using a TreeMap because that makes the implementation simpler. If you absolutely
//need to use a HashMap, then make sure you implement a hash() function for SourceAction
Map<SourceAction, List<Outcome>> dataStructure = new TreeMap<>();
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//split by tab
String [] splited = line.split("\\t");
SourceAction sourceAction = new SourceAction(splited[0], splited[1]);
Outcome outcome = new Outcome(splited[2], splited[3], splited[4]);
if(dataStructure.contains(sourceAction)) {
//Entry already found; we're just going to add this outcome to the already
//existing list.
dataStructure.get(sourceAction).add(outcome);
} else {
List<Outcome> outcomes = new ArrayList<>();
outcomes.add(outcome);
dataStructure.put(sourceAction, outcomes);
}
}
} catch (IOException e) {//Do whatever, or rethrow the exception}
return dataStructure;
}
Then, if you want to query for all the outcomes associated with a given source + action, you need only construct a SourceAction object and query the Map for it.
Map<SourceAction, List<Outcome>> actionMap = readData();
List<Outcome> outcomes = actionMap.get(new SourceAction("(1,1)", "Up"));
assert(outcomes != null);
assert(outcomes.size() == 3);
assert(outcomes.get(0).equals(new Outcome("0.8", "(1,2)", "-0.04")));
assert(outcomes.get(1).equals(new Outcome("0.1", "(2,1)", "-0.04")));
assert(outcomes.get(2).equals(new Outcome("0.1", "(1,1)", "-0.04")));
This should yield the functionality you need for your problem.
You should change your logic for adding to your hashtable to check for the key you create. If the key exists, then grab your array list of arrays that it maps to and add your array to it. Currently you will overwrite the data.
Try this
if(hashTableForWorld.containsKey(key))
{
value = hashTableForWorld.get(key);
value.add(probDes);
hashTableForWorld.put(key, value);
}
else
{
value = new ArrayList<String[]>();
value.add(probDes);
hashTableForWorld.put(key, value);
}
Then to print the contents try something like this
for (Map.Entry<String, ArrayList<String[]>> entry : hashTableForWorld.entrySet()) {
String key = entry.getKey();
ArrayList<String[]> value = entry.getValue();
System.out.println ("Key: " + key + " Value: ");
for(int i = 0; i < value.size(); i++)
{
System.out.print("Array " + i + ": ");
for(String val : value.get(i))
System.out.print(val + " :: ")
System.out.println();
}
}
Hashtable and ArrayList (and other collections) do not make a copy of key and value, and thus all values you are storing are the same probDes array you are allocating at the beginning (note that it is normal that the String[] appears in a cryptic form, you would have to make it pretty yourself, but you can still see that it is the very same cryptic thing all the time).
What is sure is that you should allocate a new probDes for each element inside the loop.
Based on your data you could work with an array as value in my opinion, there is no real use for the ArrayList
And the same applies to value, it has to be allocated separately upon encountering a new key:
private Hashtable<String, ArrayList<String[]>> readData() throws Exception {
try(BufferedReader br=new BufferedReader(new FileReader("MyGridWorld.txt"))) {
br.readLine();
Hashtable<String, ArrayList<String[]>> hashTableForWorld=new Hashtable<>();
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//System.out.println("line ="+line);
String source;
String action;
//split by tab
String[] split = line.split("\\t");
source = split[0];
action = split[1];
String key = source+","+action;
String[] probDesRew = new String[3];
probDesRew[0] = split[2];
probDesRew[1] = split[3];
probDesRew[2] = split[4];
ArrayList<String[]> value = hashTableForWorld.get(key);
if(value == null){
value = new ArrayList<>();
hashTableForWorld.put(key, value);
}
value.add(probDesRew);
}
return hashTableForWorld;
}
}
Besides relocating the variables to their place of actual usage, the return value is also created locally, and the reader is wrapped into a try-with-resource construct which ensures that it is getting closed even if an exception occurs (see official tutorial here).

How can i read the same file two times in Java?

I want to counter the lines of the file and in the second pass i want to take every single line and manipulating it. It doesn't have a compilation error but it can't go inside the second while ((line = br.readLine()) != null) .
Is there a different way to get the lines(movies) of the file and storing in an array ?
BufferedReader br = null;
try { // try to read the file
br = new BufferedReader(new FileReader("movies.txt"));
String line;
int numberOfMovies = 0;
while ((line = br.readLine()) != null) {
numberOfMovies++;
}
Movie[] movies = new Movie[numberOfMovies]; // store in a Movie
// array every movie of
// the file
String title = "";
int id = 0;
int likes = 0;
int icounter = 0; // count to create new movie for each line
while ((line = br.readLine()) != null) {
line = line.trim();
line = line.replaceAll("/t", "");
line = line.toLowerCase();
String[] tokens = line.split(" "); // store every token in a
// string array
id = Integer.parseInt(tokens[0]);
likes = Integer.parseInt(tokens[tokens.length]);
for (int i = 1; i < tokens.length; i++) {
title = title + " " + tokens[i];
}
movies[icounter] = new Movie(id, title, likes);
icounter++;
}
} catch (IOException e) {
e.printStackTrace();
}
Simplest way would be to reset br again.
try { // try to read the file
br = new BufferedReader(new FileReader("movies.txt"));
String line; int numberOfMovies = 0;
while (br.hasNextLine()){
numberOfMovies++;
}
br.close();
Movie[] movies = new Movie[numberOfMovies];
// store in a Movie
// array every movie of
// the file
String title = "";
int id = 0;
int likes = 0;
int icounter = 0;
// count to create new movie for each line
br = new BufferedReader(new FileReader("movies.txt"));
while ((br.hasNextLine()) {
line = line.trim();
line = line.replaceAll("/t", "");
line = line.toLowerCase();
String[] tokens = line.split(" ");
// store every token in a
// string array
id = Integer.parseInt(tokens[0]);
likes = Integer.parseInt(tokens[tokens.length]);
for (int i = 1; i < tokens.length; i++) {
title = title + " " + tokens[i];
}
movies[icounter] = new Movie(id, title, likes);
icounter++;
}
} catch (IOException e) { e.printStackTrace(); }
I changed br.nextLine() != null to br.hasNextLine() because it's shorter and more appropriate in this case. Plus it won't consume a line.
There are two things here:
InputStreams and Readers are one-shot structures: once you've read them to the end, you either need to explicitly rewind them (if they support rewinding), or you need to close them (always close your streams and readers!) and open a new one.
However in this case the two passes are completely unnecessary, just use a dynamically growing structure to collect your Movie objects instead of arrays: an ArrayList for example.
Firstly, there is no need to read the file twice.
Secondly, why don't you use the java.nio.file.Files class to read your file.
It has a method readAllLines(Path path, Charset cs) that gives you back a List<String>.
Then if you want to know how many lines just call the size() method on the list and you can use the list to construct the Movie objects.
List<Movie> movieList = new ArrayList<>();
for (String line : Files.readAllLines(Paths.get("movies.txt"), Charset.defaultCharset())) {
// Construct your Movie object from each individual line and add to the list of Movies
movieList.add(new Movie(id, title, likes));
}
The use of the Files class also reduces your boilerplate code as it will handle closing the resource when it has completed reading meaning you will not need a finally block to close anything.
If you use the same Reader, everything is already read once you reach the second loop.
Close the first Reader, then create another one to read a second time.
You are running through the file with the BufferedReader, until the nextline points towards null. As your BufferedReader IS null, it won't even enter the second while((line = br.readline) != null), as the first read line is null.
Try getting a new BufferedReader. something like this:
...
int id = 0;
int likes = 0;
int icounter = 0;
br = new BufferedReader(new FileReader("movies.txt")) //Re-initialize the br to point
//onto the first line again
while ((line = br.readLine()) != null)
...
EDIT:
Close the reader first..
This is a combination of a couple of other answers already on this post, but this is how I would go about rewriting your code to populate a List. This doubly solves the problem of 1) needing to read the file twice 2) removing the boilerplate around using BufferedReader while using Java8 Streams to make the initializing of your List as concise as possible:
private static class Movie {
private Movie(int id, String title, int likes) {
//TODO: set your instance state here
}
}
private static Movie movieFromFileLine(String line) {
line = line.trim();
line = line.replaceAll("/t", "");
line = line.toLowerCase();
String[] tokens = line.split(" "); // store every token in a
String title = "";
int id = Integer.parseInt(tokens[0]);
int likes = Integer.parseInt(tokens[tokens.length]);
for (int i = 1; i < tokens.length; i++) {
title = title + " " + tokens[i];
}
return new Movie(id, title, likes);
}
public static void main(String[] args) throws IOException {
List<Movie> movies = Files.readAllLines(Paths.get("movies.txt"), Charset.defaultCharset()).stream().map
(App::movieFromFileLine).collect(Collectors.toList());
//TODO: Make some magic with your list of Movies
}
For cases where you absolutely need to read a source (file, URL, or other) twice, then you need to be aware that it is quite possible for the contents to change between the first and second readings and be prepared to handle those differences.
If you can make a reasonable assumption that the content of the source will fit in to memory and your code fully expects to work on multiple instances of Readers/InputStreams, you may first consider using an appropriate IOUtils.copy method from commons-io to read the contents of the source and copy it to a ByteArrayOutputStream to create a byte[] that can be re-read over and over again.

Reading Structured File in Java

I have written code for reading a structured file in Java, and extracting the line contents to create objects (of type Person).
The file has the following structure: [personNumber], [personName], [personAge], for example
0, Sherlock Holmes, 44
1, Harry Potter, 17
2, Jack Sparrow, 50
...
The code for reading the file and extracting the information is:
RandomAccessFile rf = new RandomAccessFile(fileName, "rw");
String line;
File myFile = new File(fileName);
scan = new Scanner(myFile);
String[] split;
//Read file
while((line = rf.readLine()) != null) {
split = scan.nextLine().split(", ");
pnumber = Integer.parseInt(split[0]);
name = split[1];
age = Integer.parseInt(split[2]);
thePerson = new Person(name, age, pnumber);
personList.addLast(thePerson);
}
This works well, and the Person-objects are correctly added to a singly linked list that I have programmed. No problems here.
However, the program is also supposed to be able to read a text file of the following format:
#People
0, Sherlock Holmes, 44
1, Harry Potter, 17
2, Jack Sparrow, 50
#Dogs
0, Scooby, 10
1, Milou, 7
2, Scar, 15
Is there a way to check if the line being read contains a hash (#) symbol, in which case the program understands that it is not to split this line, but simply that a new category is starting? So that you can decide which type of object you want to create from following lines, for instance person og dog objects. For simplicity, the order of the types (Person, Dog) will always be the same, but the number of lines following each category will vary. Hence, I need help with figuring out if a line contains a #-symbol, indicating the start of a new category, and only create objects from the following lines.
or if your # is always at the beginning of the string:
EDIT:
while((line = rf.readLine()) != null) {
if(line.charAt(0)=='#'){
scan.nextLine(); //use it to suit your need..
//alert the program to prepare for new type of object
//do something..
}else {
split = scan.nextLine().split(", ");
pnumber = Integer.parseInt(split[0]);
name = split[1];
age = Integer.parseInt(split[2]);
thePerson = new Person(name, age, pnumber);
personList.addLast(thePerson);
}
}
As this looks like homework, I will only answer your first question and let you figure out how to use it in your program. The way to check if the line you read contains a hash symbol is this:
line = scan.nextLine();
if(line.contains('#')){
// the line had a #
}
else{
//it did not.
}
You can do this:
String line = null;
String currentType = null;
while((line = rf.readLine()) != null) {
if (line.startsWith("#")) {
currentType = line.substring(1);
continue;
}
split = line.split(",");
if (currentType.equals("People")) {
pnumber = Integer.parseInt(split[0]);
name = split[1];
age = Integer.parseInt(split[2]);
thePerson = new Person(name, age, pnumber);
personList.addLast(thePerson);
} else if (currentType.equals("Dogs")) {
...
Dog dog = new Dog(name,age);
}
}
First assign readed line to a variable:
String line = scan.nextLine();
Then apply logic to its value:
if (line.startsWith("#")) {
// check which type of object is declared
} else {
// parse line according to object type
// add object to list
}
Also I recommend using separate parser for separate type of objects. I.e. DogLineParser, PersonLineParser, etc. all of which would implement common interface. Example interface could look like this
public interface LineParser<T> {
T parseLine(String line);
}
And example implementation could look like this:
public class PersonLineParser extends LineParser<Person> {
#Override
public Person parseLine(String line) {
String[] split = line.split(", ");
pnumber = Integer.parseInt(split[0]);
name = split[1];
age = Integer.parseInt(split[2]);
return new Person(name, age, pnumber);
}
}
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if(line.startsWith('#')) {
// don't split the
}
else {
// you can split
}
}
scanner.close();

Compare values in two files

I have two files Which should contain the same values between Substring 0 and 10 though not in order. I have Managed to Outprint the values in each file but I need to Know how to Report say id the Value is in the first File and Notin the second file and vice versa. The files are in these formats.
6436346346....Other details
9348734873....Other details
9349839829....Other details
second file
8484545487....Other details
9348734873....Other details
9349839829....Other details
The first record in the first file does not appear in the second file and the first record in the second file does not appear in the first file. I need to be able to report this mismatch in this format:
Record 6436346346 is in the firstfile and not in the secondfile.
Record 8484545487 is in the secondfile and not in the firstfile.
Here is the code I currently have that gives me the required Output from the two files to compare.
package compare.numbers;
import java.io.*;
/**
*
* #author implvcb
*/
public class CompareNumbers {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
File f = new File("C:/Analysis/");
String line;
String line1;
try {
String firstfile = "C:/Analysis/RL001.TXT";
FileInputStream fs = new FileInputStream(firstfile);
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
while ((line = br.readLine()) != null) {
String account = line.substring(0, 10);
System.out.println(account);
}
String secondfile = "C:/Analysis/RL003.TXT";
FileInputStream fs1 = new FileInputStream(secondfile);
BufferedReader br1 = new BufferedReader(new InputStreamReader(fs1));
while ((line1 = br1.readLine()) != null) {
String account1 = line1.substring(0, 10);
System.out.println(account1);
}
} catch (Exception e) {
e.fillInStackTrace();
}
}
}
Please help on how I can effectively achieve this.
I think I needed to say that am new to java and may not grab the ideas that easily but Am trying.
Here is the sample code to do that:
public static void eliminateCommon(String file1, String file2) throws IOException
{
List<String> lines1 = readLines(file1);
List<String> lines2 = readLines(file2);
Iterator<String> linesItr = lines1.iterator();
while (linesItr.hasNext()) {
String checkLine = linesItr.next();
if (lines2.contains(checkLine)) {
linesItr.remove();
lines2.remove(checkLine);
}
}
//now lines1 will contain string that are not present in lines2
//now lines2 will contain string that are not present in lines1
System.out.println(lines1);
System.out.println(lines2);
}
public static List<String> readLines(String fileName) throws IOException
{
List<String> lines = new ArrayList<String>();
FileInputStream fs = new FileInputStream(fileName);
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
String line = null;
while ((line = br.readLine()) != null) {
String account = line.substring(0, 10);
lines.add(account);
}
return lines;
}
Perhaps you are looking for something like this
Set<String> set1 = new HashSet<>(FileUtils.readLines(new File("C:/Analysis/RL001.TXT")));
Set<String> set2 = new HashSet<>(FileUtils.readLines(new File("C:/Analysis/RL003.TXT")));
Set<String> onlyInSet1 = new HashSet<>(set1);
onlyInSet1.removeAll(set2);
Set<String> onlyInSet2 = new HashSet<>(set2);
onlyInSet2.removeAll(set1);
If you guarantee that the files will always be the same format, and each readLine() function is going to return a different number, why not have an array of strings, rather than a single string. You can then compare the outcome with greater ease.
Ok, first I would save the two sets of strings in to collections
Set<String> s1 = new HashSet<String>(), s2 = new HashSet<String>();
//...
while ((line = br.readLine()) != null) {
//...
s1.add(line);
}
Then you can compare those sets and find elements that do not appear in both sets. You can find some ideas on how to do that here.
If you need to know the line number as well, you could just create a String wrapper:
class Element {
public String str;
public int lineNr;
public boolean equals(Element compElement) {
return compElement.str.equals(str);
}
}
Then you can just use Set<Element> instead.
Open two Scanners, and :
final TreeSet<Integer> ts1 = new TreeSet<Integer>();
final TreeSet<Integer> ts2 = new TreeSet<Integer>();
while (scan1.hasNextLine() && scan2.hasNexLine) {
ts1.add(Integer.valueOf(scan1.nextLigne().subString(0,10));
ts1.add(Integer.valueOf(scan1.nextLigne().subString(0,10));
}
You can now compare ordered results of the two trees
EDIT
Modified with TreeSet
Put values from each file to two separate HashSets accordingly.
Iterate over one of the HashSets and check whether each value exists in the other HashSet. Report if not.
Iterate over other HashSet and do same thing for this.

Categories