Is there way a "reset" a scanner in Java? - java

Reset may not be the right word here, but I am currently building a program that lets the user look up a name, and by scanning a txt file containing a list of names followed by numbers, the program then displays the numbers following said name. The way I am doing this is via .nextLine, but if the user inputs a name that's later in the list (say Samantha in the example) and then tries to look up a name at the top of the list (like Sally), the second name isn't found.
For reference, here is an example of that txt file:
Sally 0 0 0 0 0 0 0 0 0 0 886
Sam 58 69 99 131 168 236 278 380 467 408 466
Samantha 0 0 0 0 0 0 272 107 26 5 7
Samir 0 0 0 0 0 0 0 0 920 0 798
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Scanner;
public class BabyNames {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
Scanner input = new Scanner (new File("BabyNames.txt"));
Scanner keyboard = new Scanner (System.in);
System.out.println("This program allows you to search through the data from the "
+ "Social Security Administration to see how popular a particular name has "
+ "been since 1900.");
System.out.print("Name? ");
String name = keyboard.nextLine();
do {
while(input.hasNextLine()) {
String text = input.nextLine();
String[] words = text.split(" ");
if (text.contains(name)) {
System.out.println("Statistics on name \"" + name + "\"");
for (int i = 1; i < words.length; i++) {
System.out.println((1900 + (i-1)*10) + ": " + words[i]);
}
System.out.println("Enter another name or type quit to exit.");
name = keyboard.nextLine();
break;
}
else if (name.contains("quit") || name.contains("quit")){
System.exit(0);
}
else {
continue;
}
System.out.print("Error, name not found.");
}
} while (!name.contains("quit") || name.contains("quit"));
}
}
I looked up the .reset method but that hasn't seemed to work. Honestly, I'm stumped here.

Again, don't try to "reset" the Scanner or re-read the file. Your best bet is to read the file once and place all the data into a collection of some type, here a Map<String, SomeCustomClass> would work best. I'd first create a class to hold a row of information, perhaps called BabyName, one that holds a String field for name and an Integer List for the numbers listed after the name, something like:
import java.util.*;
public class BabyName {
String name;
List<Integer> numberList = new ArrayList<>();
public BabyName(String name, List<Integer> numberList) {
this.name = name;
this.numberList = numberList;
}
public String getName() {
return name;
}
public List<Integer> getNumberList() {
return numberList;
}
#Override
public String toString() {
return "BabyName [name=" + name + ", numberList=" + numberList + "]";
}
// consider adding hashCode and equals methods that are based on the name field alone
// ...
}
And then I'd recommend in your code a method that takes a line of text that has been extracted from the file, and converts it into a BabyName object:
private static BabyName createBabyName(String line) {
String[] tokens = line.split("\\s+");
String name = "";
List<Integer> numberList = new ArrayList<>();
// ... code to extract the data and that fills the numberList here
// ... left blank for you to fill in
BabyName babyName = new BabyName(name, numberList);
return babyName;
}
And then create a Map<String, BabyName> babyNameMap = new HashMap<>(); to hold BabyName objects using the name field as the map key, and when you read the file (just once mind you), you fill the map:
Scanner fileScanner = null;
try {
fileScanner = new Scanner(new File(FILE_PATH_NAME));
} catch (FileNotFoundException e) {
e.printStackTrace();
System.exit(-1);
}
// read file and fill the map
while (fileScanner.hasNextLine()) {
String line = fileScanner.nextLine();
BabyName babyName = createBabyName(line);
babyNameMap.put(babyName.getName(), babyName);
}
Then you can use this map to get the data from the user multiple times without having to re-read the file or reuse a Scanner.
e.g.,
String nameEnteredByUser = keyboard.nextLine();
BabyName selectedBabyName = babyNameMap.get(nameEnteredByUser);
// check for null here first
String name = nameEnteredByUser;
List<Integer> numberList = selectedBabyName.getNumberList();

Java Scanner, in general, doesn't know/control the pointer position in the file. It wraps over InputStream which in turn provides the input to the Scanner w.r.t every nextLine() call.
Scanner systemInput = new Scanner(System.in);
//new Scanner(new FileInputStream("file.t"));
InputStream has Mark/Reset feature which will help us to control the pointer position.
(Note: mark/ reset enables us to mark a checkpoint and you can jump back to the checkpoint later.)
Unfortunately, FileInputStream doesn't support it. But, BufferedInputStream came to the rescue.
Let's cook a solution for your problem,
Create a FileInputStream with your input file.
Wraps it with BufferedInputStream which provides mark() and reset() functions.
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream("BabyNames.txt"));
Provide it as input to the Scanner constructor.
Scanner input = new Scanner (inputStream);
Mark a checkpoint at the beginning of the file.
inputStream.mark(0);//saving a checkpoint
After the end of the inner while loop, reset the pointer to the marked position.
inputStream.reset();
Now, your code works fine.

Related

Using hasNext() and If statements

I NEED your help in this. I am demanded to write a java code that reads data from a file. The data in the file looks like this:
88 73
13 60
16 20
59
9 45
44
If the line has only one number (like lines 4 and 6), it represents a Fahrenheit temperature that I need to convert into Celsius. If the line has two numbers, the second number represents relative humidity. I am stuck on how to read the data line by line and one by one. I managed so far to read all the data and put them in two strings that I will later on parse into int or double, but this only works if I have two numbers per line. I know I should use if statement to read if the line has one or two numbers, but I don't know how.
Here's my code
import java.util.*;
import java.io.*;
public class Test3 {
public static void main(String[] args) throws IOException{
FileInputStream file = null;
Scanner kb = null;
try{
file = new FileInputStream("test2.txt");
}
catch (FileNotFoundException e){
System.out.println("Critical error - could not open file");
System.exit(1);
}
kb = new Scanner(file);
while (kb.hasNext()){
String firstNum = kb.next();
String secondNum = kb.next();
System.out.println(firstNum);
System.out.println(secondNum);
}
}
}
Personally I would go for a readLine and split solution
kb = new Scanner(file);
while (kb.hasNextLine()){
String line = kb.nextLine();
String arr[] = line.split (" ");
for (String tok : arr) {
System.out.println(tok);
}
}

Editing the a specific string in a file?

So I am creating a program which when called, will have input, go to a file and change the number assigned to the string called. For example:
The file would look like:
stone 0 wood 5 water 2 metal 5
and if "wood" was called, it would go into the file, find wood then send add one to the value to the right of wood, which would only change that value to 6, then saves the file.
I've looked around on the internet but couldn't really find much which is tailored to my specific problem. Its either changing an int to either one or the other, or changing all ints to something.
public class Main {
public static void main(String[] args) {
FileWriter fw;
BufferedReader reader;
StringBuffer ib;
String allBlockAndNull = "stone 0 wood 5 water 2 metal 5";
String strDir = "C:\\Users\\amdro\\Desktop\\test.txt";
File fileDir = new File(strDir);
//creates file it doesn't exist
try {
fw = new FileWriter(fileDir);
fw.write(allBlockAndNull);
fw.close();
} catch (IOException e) {
e.printStackTrace();
}finally {}
}
}
If you could expand from the above, that would be great!
This is a very simple and basic solution to your problem: It consists of reading the file, appending all changes to a string and overwriting the same file with the string.
Create a scanner to read your text file and initialise a new string variable
Scanner s = new Scanner(new File("fileName.txt"));
String line = "";
While there is still a character in the text file, get the word and the number
while(sc.hasNext()){
String word = s.next();
int number = s.nextInt();
Then, inside the while loop, use switch and case to check the word. For example, if word = "wood", append "wood" and the new number, newNumber to line
case "wood":
line += word + " " + newNumber + " ";
break;
The default will be appending the word and the old number, number
default:
line += word + " " + number + " ";
Finally, just create a FileWriter and a BufferedWriter to write line to the text file.
You can't add numbers to a value from a file because all the values are Strings but what you can do is replace the String value
public static void main(String[] args) throws IOException {
File file = new File("file.txt");//The file containing stone 0 wood 5 water 2 metal 5
BufferedReader reader = new BufferedReader(new FileReader(file));
String words = "", list = "";
while ((words = reader.readLine()) != null) {
list += words;
}
reader.close();
Scanner s = new Scanner(file);
if(list.contains("wood")) {
String replacedtext = list.replaceAll("wood 5", "wood 6");
FileWriter writer = new FileWriter("file.txt");
writer.write(replacedtext);
writer.close();
}
}
}

Reading multiple integers in multiple lines

I am currently writing my Bachelor's thesis in graph theory and use the java scanner to convert a txt file with edges into my Java class graph. My txt file looks like this:
1 2 72 3
2 3 15 98
4 7 66 49
5 6 39 48
6 9 87 97
8 13 31 5
The ints are ordered as: source vertex, sink vertex, cost, capacity.
My Code looks like:
Graph graph = new Graph(false);
File f = new File("Filepath");
Scanner in = new Scanner(f);
while (in.hasNextLine())
{
for (int i =1; i<= numberEdges; i++)
{
String s = in.nextLine();
try (Scanner inscan = new Scanner(s)) {
while (inscan.hasNext())
{
int source = inscan.nextInt();
int sink = inscan.nextInt();
double cost =inscan.nextDouble();
double capacity = inscan.nextDouble();
Vertex Source = new Vertex(source);
Vertex Sink = new Vertex(sink);
Edge edge = new Edge(Source,Sink, cost, capacity);
graph.addEdge(edge);
}
}
}
}
in.close();
I tried to scan each line in a String and then scan the String into my Variables.
It always throws a "NoLineFound" Exception in the first line of the for loop and if I try it with outputing the lines I get none. But when I disable the second scanner and try again I get all lines in the ouput but at the end still a "NoLineFound" Exception.
I checked my txt File and the last line doesn't have a UTF8 line ending, but I don't know how to give it one.
I think that your problem comes from that :
while (in.hasNextLine()){
for (int i =1; i<= numberEdges; i++)
{
First, iteration is redundant (while or for are unitary enough for reading each line. You have to do choice between them).
Besides if your file has less line than numberEdges, a java.util.NoSuchElementException will be raised.
If the number of line is constant in the file, use a for:
for (int i =1; i<= numberEdges; i++)
remove the enclosing while (in.hasNextLine()). It is not required. Iteration control is already done by the for.
If the number of lines in the file may vary, use only a while :
while (in.hasNextLine()){
But anyway, don't use both.
With Java 8 streams:
Files
.lines(f.toPath())
.map(l ->Arrays.stream(l.split(" ")).mapToDouble(Double::parseDouble).toArray())
.map(a->new Edge(new Vertex((int)a[0]), new Vertex((int)a[1]), a[2], a[3]))
.forEach(graph::addEdge);
You are reading nextLine() in a loop after a single check for hasNextLine(). You need to perform a check after each read in order to avoid the "NoLineFound" exception.
It looks like the nested loop is completely unnecessary. You can read file line-by-line, ignoring empty lines, and build your graph without prior knowledge of the number of edges that it has:
Graph graph = new Graph(false);
File f = new File("Filepath");
Scanner in = new Scanner(f);
while (in.hasNextLine()) {
String s = in.nextLine();
try (Scanner inscan = new Scanner(s)) {
if (!inscan.hasNext()) {
continue; // Ignore empty lines
}
int source = inscan.nextInt();
int sink = inscan.nextInt();
double cost =inscan.nextDouble();
double capacity = inscan.nextDouble();
Vertex Source = new Vertex(source);
Vertex Sink = new Vertex(sink);
Edge edge = new Edge(Source,Sink, cost, capacity);
graph.addEdge(edge);
}
}
in.close();
Just perform a check after reading to avoid the "NoLineFound" exception.
You can use the below code to scan the file:
import java.io.File;
import java.util.Scanner;
public class ReadFile {
public static void main(String[] args) {
try {
System.out.print("Enter the file name with extension : ");
Scanner input = new Scanner(System.in);
File file = new File(input.nextLine());
input = new Scanner(file);
while (input.hasNextLine()) {
String line = input.nextLine();
System.out.println(line);
}
input.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

How do I update a file using an ArrayList, Java

I am writing a method that will take in some command line arguments, validate them and if valid will edit an airport's code. The airport name and it's code are stored in a CSV file. An example is "Belfast,BHD". The command line arguments are entered as follows, java editAirport EA BEL Belfast, "EA" is the 2letter code that makes the project know that I want to Edit the code for an Airport, "BEL" is the new code, and Belfast is the name of the Airport.
When I have checked through the cla's and validated them I read through the file and store them in an ArrayList as, "Belfast,BEL". Then I want to update the text file by removing the lines from the text file and dumping in the arraylist, but I cannot figure out how to do it. Can someone show me a way using simple code (no advanced java stuff) how this is possible.
Here is my program
import javax.swing.*;
import java.io.*;
import java.util.*;
import java.text.*;
public class editAirport
{
public static void main(String [] args)throws IOException
{
String pattern = "[A-Z]{3}";
String line, line1, line2;
String[] parts;
String[] parts1;
boolean found1 = false, found2 = false;
File file = new File("Airports.txt"); // I created the file using the examples in the outline
Scanner in = new Scanner(file);
Scanner in1 = new Scanner(file);
Scanner in2 = new Scanner(file);
String x = args[0], y = args[1], z = args[2];
//-------------- Validation -------------------------------
if(args.length != 3) // if user enters more or less than 3 CLA's didplay message
JOptionPane.showMessageDialog(null, "Usage: java editAirport EA AirportCode(3 letters) AirportName");
else if(!(file.exists())) // if "Airports.txt" doesn't exist end program
JOptionPane.showMessageDialog(null, "Airports.txt does not exist");
else // if everything is hunky dory
{
if(!(x.equals("EA"))) //if user doesn't enter EA an message will be displayed
JOptionPane.showMessageDialog(null, "Usage: java editAirport EA AirportCode(3 letters) AirportName");
else if(!(y.matches(pattern))) // If the code doesn't match the pattern a message will be dislayed
JOptionPane.showMessageDialog(null, "Airport Code is invalid");
while(in.hasNext())
{
line = in.nextLine();
parts = line.split(",");
if(y.equalsIgnoreCase(parts[1]))
found1 = true; //checking if Airport code already is in use
if(z.equalsIgnoreCase(parts[0]))
found2 = true; // checking if Airport name is in the file
}
if(found1)
JOptionPane.showMessageDialog(null, "Airport Code already exists, Enter a different one.");
else if(found2 = false)
JOptionPane.showMessageDialog(null, "Airport Name not found, Enter it again.");
else
/*
Creating the ArrayList to store the name,code.
1st while adds the names and coses to arraylist,
checks if the name of the airport that is being edited is in the line,
then it adds the new code onto the name.
sorting the arraylist.
2nd for/while is printing the arraylist into the file
*/
ArrayList<String> airport = new ArrayList<String>();
while(in1.hasNext()) // 1st while
{
line1 = in1.nextLine();
if(line1.contains(z))
{
parts1 = line1.split(",");
parts1[1] = y;
airport.add(parts1[0] + "," + parts1[1]);
}
else
airport.add(line1);
}
Collections.sort(airport); // sorts arraylist
FileWriter aFileWriter = new FileWriter(file, true);
PrintWriter output = new PrintWriter(aFileWriter);
for(int i = 0; i < airport.size();)
{
while(in2.hasNext()) // 2nd while
{
line2 = in2.nextLine();
line2 = airport.get(i);
output.println(line2);
i++;
}
}
output.close();
aFileWriter.close();
}
}
}
}
The Airports.txt file is this
Aberdeen,ABZ
Belfast City,BHD
Dublin,DUB
New York,JFK
Shannon,SNN
Venice,VCE
I think your problem may lie in the two lines:
line2 = in2.nextLine();
line2 = airport.get(i);
this will overwrite the 'line2' in memory, but not in the file.

Parse String Array to FIle

Alright gents I am trying to make a program that reads information from a file and then writes information out to another file.
I am reading from 2 columns first column is an integer (Team#) second column is a string(name of member)
1 Sam
3 Bob
6 Jill
3 Mike
1 Terra
1 Juice
6 Tom
6 Lucy
3 Dude
And then I have to take the 3rd instance in and output the name of the individual so it will look like this
Team Member
1 Juice
3 Dude
6 Lucy
I am having issues with trying to read the text into the array in order to output it, I am trying to use Parse String
My Code
package team;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Scanner;
public class Team {
public static void main(String[] args) throws FileNotFoundException {
//Output Please wait
System.out.println("Team Leader Started. Please wait....");
//Add Read and Write File locations
File inFile = new File("C:\\Users\\Christ\\Documents\\NetBeansProjects\\Team\\src\\team\\read.txt");
File outFile = new File("C:\\Users\\Christ\\Documents\\NetBeansProjects\\Team\\src\\team\\outputfile.txt");
// Initialise Arrays
int[] team = new int[99];
String[] name = new String[99];
// Scanner
Scanner sc = new Scanner(inFile);
sc.nextLine(); // move to second line assuming file is not empty.
// While Loop
while(sc.hasNextLine()) {
String s = sc.nextLine().trim();
String[] splitStr = s.split(" ");
team[Integer.parseInt(splitStr[0])-1] += Integer.parseInt(splitStr[1]);
name[String.parseString(splitStr[0])-1]++;
}
PrintWriter outFileWriter = new PrintWriter(outFile);
outFileWriter.println("Team Name");
// For loop
for(int i=0;i<99;i++) {
// Team
int t=i+1;
// Member
String m = name[i];
// Output to File
outFileWriter.println(t + " "+" "+ " " + m);
}
outFileWriter.close();
//Output Completed file, reference output file for sucees
System.out.println("Team Leader Completed Successfully");
}
}
Can someone please tell me where im going wrong? I do not want the final result only the ability at the moment to output the Team number and then the Member name to my output file.
Please Help ^_^
I would use a Map<Integer, ArrayList<String>> to store your team members with their corresponding teams.
It allows you to store key/value pairs and to maintain a dynamic list of members for each team.
public static void main(String [] args) throws FileNotFoundException{
System.out.println("Team Leader Started. Please wait....");
Map<Integer, ArrayList<String>> map = new HashMap<Integer, ArrayList<String>>();
//Add Read and Write File locations
File inFile = new File("C:\\Users\\Christ\\Documents\\NetBeansProjects\\Team\\src\\team\\read.txt");
File outFile = new File("C:\\Users\\Christ\\Documents\\NetBeansProjects\\Team\\src\\team\\outputfile.txt");
// Scanner
Scanner sc = new Scanner(inFile);
// While Loop
while(sc.hasNextLine()) {
String s = sc.nextLine();
String[] splitStr = s.split(" ");
Integer id = Integer.parseInt(splitStr[0]);
String name = splitStr[1];
List<String> list = map.get(id);
if(list == null)
map.put(id, new ArrayList<>(Arrays.asList(name)));
else {
list.add(name);
}
}
PrintWriter outFileWriter = new PrintWriter(outFile);
outFileWriter.println("Team Name");
// For loop
for(Map.Entry<Integer, ArrayList<String>> entry : map.entrySet()){
outFileWriter.write(entry.getKey()+"\t"+entry.getValue().toString()+"\n");
}
outFileWriter.close();
//Output Completed file, reference output file for sucees
System.out.println("Team Leader Completed Successfully");
}
Output :
Team Name
1 [Sam, Terra, Juice]
3 [Bob, Mike, Dude]
6 [Jill, Tom, Lucy]
If you know the number of inputted people, then adding a row to the input file denoting the length would allow for array sizes to be the minimum required also this gets rid of 100+ people casing an issue
like:
#9
1 Sam
3 Bob
6 Jill
3 Mike
1 Terra
1 Juice
6 Tom
6 Lucy
3 Dude

Categories

Resources