I/O Reading in object data from a file - java

I have a Vehicle class which contains all information about Vehicle objects including get and set methods. There is also a Showroom class which maintains a list of all of the Vehicle objects, with methods to add/delete and scroll through the list.
In my main (a seperate class called VehicleDriverClass) I am trying to use I/O to write Vehicle data to a file and read in Vehicle data from a file. I can write to a file fine. I am using notepad and so a .txt file to read from. The problem I am having is with how to terminate the end of a line when reading from the file. Here is the constructor for the Vehicle class, so you know the paramaters.
public Vehicle(String man, String mod, String VIN, String dateOfMan, char taxBand, int costOfVehicle)
{
this.manufacturer = man;
this.model = mod;
this.VIN = VIN;
this.dateOfManufacture = dateOfMan;
this.taxBand = taxBand;
this.costOfVehicle = costOfVehicle;
}
This is what I have for the Input method at the moment (without trying to create the oject, just reading from file). The Showroom s being passed to it is for use later, when I create the vehicle object and add it to the showroom.
// code replaced below.
With this implementation when the dataFromFile is outputted to the console it is all on one line, rather than on new lines. Does readline() not terminate the line when '\n' is read in?
Here is how my data is stored in the input file.
Fordtest\n Focus\n frank\n ioCheck\n 09/01/1989\n 23/11/2013\n true\n d\n 1995\n
So for now, how do I get the line to terminate? So that I can then implement the creation of an object from this.
EDIT: I/O is working now. I am now having trouble with the constructor for my Vehicle object needing a the data types char and int for the last two variables. With the current method they are in a string array.
I have removed the code from above and added the new implementation below.public static void
addNewVehicleFromFile(Showroom s)
{
String dataFromFile;
String[] tokens = null;
try
{
File fileReader = new File("AddNewVehicleFromFile.txt");
FileReader fr = new FileReader(fileReader);
BufferedReader br = new BufferedReader(fr);
while ((dataFromFile = br.readLine()) != null)
{
tokens = dataFromFile.split("~");
}
System.out.println(Arrays.toString(tokens));
Vehicle inputVehicle = new Vehicle(tokens[0], tokens[1], tokens[2], tokens[3],
tokens[4], tokens[5]);
/*
Erorr above here with these two. token[4] should be a char and [5] an int
*/
s.addVehicle(inputVehicle);
System.out.println("addNewVehicleFromFile Complete");
}
catch (FileNotFoundException fnfe)
{
System.out.println("File not found exception: " + fnfe.toString());
}
catch (IOException ioe)
{
System.out.println("I/O exception: " + ioe.toString());
}
}
Should I be writing my own toChar and toInt methods to call for these two variables? Or parsing to int or similar.

I think you'll do better if you change your input data format. This is what XML and JSON were born for. If you must persist with your current arrangement, change the delimiter between data elements to something like a tilde '~' instead of \n.
So your input looks like this:
Fordtest~Focus~frank~ioCheck~09/01/1989~23/11/2013~true~d~1995
It's easy to parse now:
String [] tokens = data.split("~");
Write yourself some factory methods to create Vehicles:
public class VehicleFactory {
private static final VehicleFactory INSTANCE= new VehicleFactory();
private VehicleFactory() {}
public static VehicleFactory getInstance() { return INSTANCE; }
public static Vehicle createVehicle(String data) {
Vehicle value = null;
String [] tokens = data.split("~");
if ((tokens != null) && (tokens.length > X)) {
// Map String to int or Date here
value = new Vehicle(tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
}
return value;
}
public static List<Vehicle> createVehicles(File f) {
List<Vehicle> values = new ArrayList<Vehicle>();
// implementation left for you
return values;
}
}

readLine() terminates the line when a character matching the Java syntax of \n is read. In most text editors, this is a newline. To express a newline in a Java string, use \n in the source code, but when creating the file by hand, use:
Fordtest
Focus
frank
ioCheck
09/01/1989
23/11/2013
true
d1995

Related

How To Read A Specific Part Of A Line In A Text File In Java?

I have a text file in which I have written some information line by line like this:
name|Number|amount|PIN
How can I read back data In a way that (for example) I will be able to use just the "name" part in a method?
The sample code is shown in the image below.
in the beginning declare a List to collect the accounts:
import java.util.ArrayList;
...
public Account[] inReader() { //BTW: why do you pass an Account[] here?
ArrayList accountList = new ArrayList();
...
}
replace the for(String records : dataRecords) {...} with
String name = dataRecords[0];
String cardNumber = dataRecords[1];
int pin = Integer.parseInt(dataRecords[2]); //to convert the String back to int
double balance = Double.parseDouble(dataRecords[3]);
Account account = new Account(name, cardNumber, pin, balance);
accountList.add(account);
because you already proceed record by record (while ((line = br.readLine())!=null) {...})
in the end return accountList.toArray(new Account[0]);
You can read the text line by line and then use the "|" delimiter to separate the columns.
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
}
You could read the file line-by-line and split on the delimiter '|'.
The following example assumes the filepath is in args[0] and would read then output the name component of the input:
public static void main(String[] args) {
File file = new File(args[0]);
BufferedReader br = new BufferedReader(new FileReader(file));
while(String line = br.readLine()) != null) {
String[] details = line.split("|");
System.out.println(details[0]);
}
}
As mentioned in the comment above, you can simply split the line on your delimiter, |, and go from there.
Something like:
public class Account {
// ...
public static Account parseLine(String line) {
String[] split = line.split("|");
return new Account(split[0], split[1], split[2], split[3]);
}
}
should work fine (assuming you have a constructor which takes the four things you're putting in). If your Account class has more information than this, you can create an AccountView or similarly named class which does only contain the details you have available here. With this, just iterate line by line, parse your lines to one of these Objects, and use it's properties (including the already available getters) when calling other methods which need name, etc.
First, you need to read the whole content of the file or line by line.
Then, for each line you need to create a function to split the line text by a configurable delimiter. This function can receive the column number and it should return the needed value. For example: extractData(line, 0) should return 'name', extractData(line, 2) should return 'amount' etc.
Also, you need some validation: what if there are only 3 columns and you expect 4? You can throw and exception or you can return null/empty.
There are many possible ways to do it. One of them is to make an object that will hold the data. Example since you know that your data will always have name, number, amount and pin then you can make a class like this:
public class MyData {
private String name;
private String number;
private double amount;
private String pin;
// Add getters and setters below
}
Then while reading the text file you can make a list of MyData and add each data. You can do it like this:
try {
BufferedReader reader = new BufferedReader(new FileReader("path\file.txt"));
String line = reader.readLine();
ArrayList<MyData> myDataList = new ArrayList<MyData>();
while (line != null) {
String[] dataParts = line.split("|"); // since your delimiter is "|"
MyData myData = new MyData();
myData.setName(dataParts[0]);
myData.setNumber(dataParts[1]);
myData.setAmount(Double.parseDouble(dataParts[2]));
myData.setPin(dataParts[3]);
myDataList.add(myData);
// read next line
line = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
Then you can use the data like this:
myDataList.get(0).getName(); // if you want to get the name of line 1
myDataList.get(1).getPin(); // if you want to get the pin of line 2
You can convert the file into a csv file and use a library specific for reading csv files, e.g. OpenCSV. This will give you more flexibility in handling the data in the file.

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).

Parsing various values in Textfile (Java)

I have a textfile as such:
type = "Movie"
year = 2014
Producer = "John"
title = "The Movie"
type = "Magazine"
year = 2013
Writer = "Alfred"
title = "The Magazine"
What I'm trying to do is, first, search the file for the type, in this case "Movie" or "Magazine".
If it's a Movie, store all the values below it, i.e
Set the movie variable to be 2014, Producer to be "John" etc.
If it's a Magazine type, store all the variables below it as well separately.
What I have so far is this:
public static void Parse(String inPath) {
String value;
try {
Scanner sc = new Scanner(new FileInputStream("resources/input.txt"));
while(sc.hasNextLine()) {
String line = sc.nextLine();
if(line.startsWith("type")) {
value = line.substring(8-line.length()-1);
System.out.println(value);
}
}
} catch (FileNotFoundException ex) {
Logger.getLogger(LibrarySearch.class.getName()).log(Level.SEVERE, null, ex);
}
}
However, I'm already having an issue in simply printing out the first type, which is "Movie". My program seems to skip that one, and print out "Magazine" instead.
For this problem solely, is it because the line: line.startsWith("type")is checking if the current line in the file starts with type, but since the actual String called lineis set to the nextline, it skips the first "type"?
Also, what would be the best approach to parsing the actual values (right side of equal sign) below the type "Movie" and "Magazine" respectively?
I recommend you try the following:
BufferedReader reader = new BufferedReader(new FileReader(new File("resources/input.txt")));
String line;
while((line = reader.readLine()) != null) {
if (line.contains("=")) {
String[] bits = line.split("=");
String name = bits[0].trim();
String value = bits[1].trim();
if (name.equals("type")) {
// Make a new object
} else if (name.equals("year")) {
// Store in the current object
}
} else {
// It's a new line, so you should make a new object to store stuff in.
}
}
In your code, the substring looks suspect to me. If you do a split based on the equals sign, then that should be much more resilient.

How to read from a file to an arraylist

i'm having some trouble with reading from a text file back and writing back to an array list. I was wondering if you could tell me where I'm going wrong? Thanks.
accountArrayList = new ArrayList<BankAccount>();
private void fileIn()
{
try
{
createTestAccounts();
//Scanner input = new Scanner(new FileReader(bankFile));
JOptionPane.showMessageDialog(null, "File: " + bankFile + " has been opened for importing");
BufferedReader reader = new BufferedReader(new FileReader("bankFile.txt"));
String account = reader.readLine();
while(account !=null) {
accountArrayList.add(account); // - add a new account to the text file, but exception show that String cannot be converted to Bank Account
account = reader.readLine();
}
reader.close();
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, "not found");
}
}
You are adding a String, but the list.add method expects an object of type BankAccount.
You'll have to find a way to turn that String into an Object of that type , then add the latter. Maybe there is a fromString() factory method? Or a Constructor that takes an initialization - String ?
If there is a constructor then it should look like
accountArrayList.add(new BankAccount(account));
To read all lines you may use (if your file is in UTF-8):
List<String> allLines = Files.readAllLines("bankFile.txt", StandardCharsets.UTF_8);
But as it was mentioned in the other comments you will need to transform a String into a BankAccount
BankAccount ba = new BankAccount(account);
accountArrayList.add(ba);
You're going to need something like this...depending on what your BankAccount class is exactly.
Assuming you have a String constructor for BankAccount, something like this:
public BankAccount(String account) {
this.account = account;
}
You can use Apache commons-io and java 8 to get a one-liner!
List<BankAccount> accounts = FileUtils.readLines(new File(filename))
.stream().map(BankAccount::new).collect(Collectors.toList());
The arraylist expects an BankAccount object, instead you are reading from a file, so the arraylist should be String.
ArrayList<String> accountArrayList = new ArrayList<>();
For the while loop condition, personally, i always use, but you can do it like that too.
while((account = reader.readLine()) != null){
accountArrayList.add(account);
}

Java program for counting the most frequent elements

I want a java program to count the most frequent elements in a file
Is the problem that your "newCount" is a String instead of an Integer?
String newCount = entry.getValue().toString();
if(topN.containsKey(entry.getKey())){
newCount += topN.get(entry.getKey());
}
With the line Parser parser; you declare a variable of your class Parser, but you do not initialize that varialbe. Use Parser parser = new Parser(); instead.
There also seem to be a whole lot of type problem along the lines of
String newCount = entry.getValue().toString();
if(topN.containsKey(entry.getKey())){
newCount += topN.get(entry.getKey());
}
topN.put(entry.getKey(), newCount);
It seems like you want to add up the counts, but this will not work if you convert the Integer to String first! Also, the key of the Entry will be a value, so topN can never contain that key, as it is a Map of Strings and Actors, and even if it would, how would you add an Actor to an Integer (or String)? Finally, as others have noted, the put will fail, as both the type of the key and the value do not match the types of the Map.
WIthout knowing what those other classes (Sketch, Value, Actor, etc.) do, it is very hard do give clear advice how to fix your problem.
topN is declared as Map<String, Actor>. So key must be a String and value must be of type Actor.
In topN.put(entry.getKey(), newCount);, newCount (a String) is not an Actor. Also check if entry.getKey() is a String.
public class Parser {
private BufferedReader bf;
private static final String ACTOR_MOVIE_FILE = "actormovie.txt";
private Map<String, Actor> actors;
//this is the input file size
int fileSize = ACTOR_MOVIE_FILE.length();
public Parser() {
try {
bf = new BufferedReader(new FileReader(ACTOR_MOVIE_FILE), 32768);
} catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(null, "file cannot be located ", "File not found exception", JOptionPane.ERROR_MESSAGE);
}
actors = new Hashtable<String, Actor>(1713251);
}
/**
* this reads data on a line one at a time
* #return actors in the hash table, with the name of an actor as a,
* and value as the actor object
*/
public Map<String, Actor> readLines() {
String line=" ";
while(true){
try {
line = bf.readLine();
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "deadlock file not in proper format", "we have error reading the file", JOptionPane.ERROR_MESSAGE);
}
if(line == null){
break;
}
String[] tokens = line.split("/");
assemblyLines(tokens);
}
try {
bf.close();
} catch(IOException e){
}
return actors;
}
/**
* from a line we get stringTokenizers parse to the data structures. Film is described as a
* stringTokenizer with film object created from it. There are actors which are as well
* stringTokenizers created as actor object
* there is an actor table that controls entry space. In occurrences of other actors ,
* the object is altered, other than that
* objected is created and appended to the table
* #param stringTokenizer makes the text file divided into individual components
*/
public void assemblyLines(String[] stringTokenizer){
Film film = new Film(stringTokenizer[0]);
for(int i = 1; i < stringTokenizer.length;i++){
Actor actor;
String actorName = stringTokenizer[i];
if(actors.containsKey(actorName)){
actor = actors.get(actorName);
} else {
actor = new Actor(actorName);
actors.put(actorName, actor);
}
film.addActor(actor);
actor.addFilm(film);
}
}
}

Categories