Reading multiple integers in multiple lines - java

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();
}
}
}

Related

How to print specific numbers from txt file?

I have a text file written in the following texts:
18275440:Annette Nguyen:98
93840989:Mary Rochetta:87
23958632:Antoine Yung:79
23658231:Claire Coin:78
23967548:Emma Chung:69
23921664:Jung Kim:98
23793215:Harry Chiu:98
I want to extract last two digit numbers from each line. This is my written code:
for (int i = 3; i < 25; i++) {
line = inFile.nextLine();
String[] split = line.split(":");
System.out.println(split[2]);
}
And I am getting a runtime error.
Update the reading method, if you are using Scanner you can check if there are more lines left or not.
while(inFile.hasNextLine()) {
line = inFile.nextLine();
String[] split = line.split(":");
System.out.println(split[2]);
}
Why the complexity of the for loop specification? You don't use i, so why bother with all that. Don't you just want to read lines until there aren't any more? If you do that, assuming that inFile will let you read lines from it, your code to actually parse each line and extract the number at the end seems right. Here's a complete (minus the class definition) example that uses your parsing logic:
public static void main(String[] args) throws IOException {
// Open the input data file
BufferedReader inFile = new BufferedReader(new FileReader("/tmp/data.txt"));
while(true) {
// Read the next line
String line = inFile.readLine();
// Break out of our loop if we've run out of lines
if (line == null)
break;
// Strip off any whitespace on the beginning and end of the line
line = line.strip();
// If the line is empty, skip it
if (line.isEmpty())
continue;
// Parse the line, and print out the third component, the two digit number at the end of the line
String[] split = line.strip().split(":");
System.out.println(split[2]);
}
}
If there's a file named /tmp/data.txt with the contents you provide in your question, this is the output you get from this code:
98
87
79
78
69
98
98
Don't be so explicit with your loop criteria. Use a counter to acquire the data you want from the file, for example:
int lineCounter = 0;
String line;
while (inFile.hasNextLine()) {
line = inFile.nextLine();
lineCounter++;
if (lineCounter >=3 && lineCounter <= 24) {
String[] split = line.trim().split(":");
System.out.println(split[2]);
}
}
I don't know why your code gives error. If you had any unwanted lines (I see you have 3 such lines in your code) in the beginning just run an empty scanner over them.
Scanner scanner = new Scanner(new File("E:\\file.txt"));
String[] split;
// run an empty scanner
for (int i = 1; i <= 3; i++) scanner.nextLine();
while (scanner.hasNextLine()) {
split = scanner.nextLine().split(":");
System.out.println(split[2]);
}
In case you don't know of such lines and they would not comply to the rules of the lines, then you could use try...catch to eliminate them. I'm using a simple exception here. But you could throw an exception when your conditions doesn't meet.
Suppose your file looks like this:
1
2
3
18275440:Annette Nguyen:98
93840989:Mary Rochetta:87
23958632:Antoine Yung:79
bleh bleh bleh
23658231:Claire Coin:78
23967548:Emma Chung:69
23921664:Jung Kim:98
23793215:Harry Chiu:98
Then your code would be
Scanner scanner = new Scanner(new File("E:\\file.txt"));
String[] split;
// run an empty scanner
// for (int i = 1; i <= 3; i++) scanner.nextLine();
while (scanner.hasNextLine()) {
split = scanner.nextLine().split(":");
try {
System.out.println(split[2]);
} catch (ArrayIndexOutOfBoundsException e) {
}
}
Assuming you're using Java 8, you can take a simpler, less imperative approach by using BufferedReader's lines method, which returns a Stream:
BufferedReader reader = new BufferedReader(new FileReader("/tmp/data.txt"));
reader.lines()
.map(line -> line.split(":")[2])
.forEach(System.out::println);
But, come to think of it, you could avoid BufferedReader by using Files from Java's NIO API:
Files.lines(Paths.get("/tmp/data.txt"))
.map(line -> line.split(":")[2])
.forEach(System.out::println);
You can split on \d+:[\p{L}\s]+: and take the second element from the resulting array. The regex pattern, \d+:[\p{L}\s]+: means a string of digits (\d+) followed by a : which in turn is followed by a string of any combinations of letters and space which in turn is followed by a :
public class Main {
public static void main(String[] args) {
String line = "18275440:Annette Nguyen:98";
String[] split = line.split("\\d+:[\\p{L}\\s]+:");
String n = "";
if (split.length == 2) {
n = split[1].trim();
}
System.out.println(n);
}
}
Output:
98
Note that \p{L} specifies a letter.

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);
}
}

Why is my program reading one less line than there actually is? And why is my array taking in only ones?

In my high school comp sci class I have to read a text file with marks and then create an array with those marks in them (so I can manipulate them later). When I try and read the number of lines in the program it reads one less than there is, and when I output the array it consists of only "1.00" written to the amount of lines it has counted (which is incorrect).
import java.awt.*;
import java.io.*;
import hsa.Console;
public class Assignment3Q3
{
static Console c;
public static void main (String[] args) throws IOException
{
c = new Console ();
BufferedReader input = new BufferedReader (new FileReader ("marks.txt"));
String mark = input.readLine ();
int lines = 0;
while (input.readLine () != null)
lines++;
input.close ();
c.println (lines);
double[] marks = new double [lines];
int count = 0;
BufferedReader input1 = new BufferedReader (new FileReader ("marks.txt"));
while (input1.readLine () != null)
{
marks [count] = Double.parseDouble (mark);
count += 1;
if (count == lines)
{
break;
}
}
for (int x = 0 ; x < lines ; x++)
{
c.println (marks [x]);
}
}
}
In your second while loop, you are always assigning the parsed version of mark variable to the marks array elements. But you have only set mark variable once in your code, which is the first line of your file.
Anyway without reading the file twice (once to get the number of lines and then to store the actual line content), you can do this in a single read cycle by using a List instead of an array.
try (BufferedReader input = new BufferedReader (new FileReader("src/marks.txt"))) {
List<Double> marks = new ArrayList<>();
String line;
while ((line = input.readLine()) != null) {
marks.add(Double.parseDouble(line));
}
System.out.println(marks);
} catch (IOException e) {
e.printStackTrace();
}
In case you really want to get these marks to an array, you can onvert the above list into an array as follows.
Double[] marksArray = marks.toArray(new Double[marks.size()]);
Also as I have done in the above code snippet, better to use try with resources approach when you create AutoCloseable resources such as BufferedReader or FileReader. Then you don't have to close them explicitly in your code.
Why this separation in two steps at all? This is error prone. No values in the marks-array above the current line-count are accessed. So store the doubles in a dynamicly growing ArrayList<Double> instead and do the job in one step.

Reading a text file & adding the content to an ArrayList

I am learning about all of the different ways to take input from a text file and read through the content. I am struggling to use a try - catch block (with resources), and reading in the file name.
Below is what I have written for this part so far:-
public static void main(String[] args)
{
ArrayList<StationRecord> data = new ArrayList<>();
String stationName = null;
Scanner scan = new Scanner(System.in);
System.out.println("What is the filename?");
String input = scan.nextLine();
File file = new File(input);
try(BufferedReader in = new BufferedReader(new FileReader(file))){
while(scan.hasNext()){
stationName = scan.nextLine();
int yearMonthDay = scan.nextInt();
int max = scan.nextInt();
int min = scan.nextInt();
int avg = scan.nextInt();
double dif = scan.nextDouble();
StationRecord sr = new StationRecord(yearMonthDay, max, min, avg, dif);
data.add(sr);
}
}
catch(IOException e)
{
e.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
}
I am trying to do this for not only one file, but two of them. Regardless, here is a sample of input:-
Console: What is the filename?
TempData2018a.txt
After this is entered, I am trying to go through the data in the text file and add it to the ArrayList of type StationRecord (my other class).
Any suggestions and guidance would be much appreciated! Also any input on how you might do this with 2 files would be awesome!.
Edit: .txt file data example
PITTSBURGH ALLEGHENY CO AIRPORT PA
20180101 11 2 7 -22.614762
20180102 12 5 9 -20.514762
20180103 23 2 13 -16.414762
I am trying to store that whole first line in a variable called stationName. Then Im trying to store the next int, int, int, int double in an ArrayList of StationRecord type.
Since this is 2018, please stop using new File(..) and start using nio APIs. As you are using Java 8, you can easily achieve what you are trying to achieve here! So, you can create your StationRecord like this:
Path filePath = Paths.get(pathToFile);
String stationName = Files.lines(filePath)
.findFirst()
.get();
List<StationRecord> stationRecords =
Files.lines(filePath)
.skip(1) //Skip first line since it has station name
.map(line -> line.split("\\s")) // split at a space starting from 2nd line
.map(
stationData -> new StationRecord(Integer.valueOf(stationData[0]),
Integer.valueOf(stationData[1]), Integer.valueOf(stationData[2]),
Integer.valueOf(stationData[3]), Double.valueOf(stationData[4]))) // Create StationRecord object using the split fields
.collect(Collectors.toList()); // Collect result to an ArrayList
Using Java 7 & Java 8 API's feature, you can solve your problem like below:
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class LineOperation {
private static List<String> lines;
public static void main(String[] args) throws IOException {
lines = Collections.emptyList();
try {
lines = Files.readAllLines(Paths.get("C:\\Users\\Abhinav\\Downloads\\TempData2018a.txt"), StandardCharsets.UTF_8);
String stationName = lines.get(0);
String[] arr = null;
ArrayList<StationRecord> data = new ArrayList<>();
for(int i=1;i<lines.size();i++) {
arr = lines.get(i).split(" ");
data.add(new StationRecord(Long.parseLong(arr[0]), Integer.parseInt(arr[1]), Integer.parseInt(arr[2]), Integer.parseInt(arr[3]), Double.parseDouble(arr[4])));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
But I strongly recommend you to refer below links for your further clarifications on Java I/O:-
Java – Read from File
Read a File into an ArrayList

Reading from a file rather than from the console

I am getting exception thrown and i think it has to with the ArrayIndexOutOfBounds at the sub string and also do you think the below method would work for getting data passed to my array after parsing
I want this to be read from a txt file like this, on each line:
1
0
1
0
0
1
0
ONE INTEGER PER LINE!!
String fileName = "input.txt";
File file = new File(fileName);
Scanner scanner = new Scanner(file);
while(scanner.hasNextLine()){
data1 = scanner.nextLine();
}
for ( int i = 0; i < data1.length(); i++)
{
covertDataArray[i] = Byte.parseByte(data1.substring( i, i+1));
}
This is previous working version but it reads from the console. where it would be : 1010101001
System.out.println("Enter the binary bits");
data1 = in.next();
for ( int i = 0; i < data1.length(); i++)
{
covertDataArray[i] = Byte.parseByte(data1.substring( i, i+1));
}
You're reading all the lines and only keeping the last in your data1 variable. That's probably your problem.
You should, instead, handle each value right away while reading the file, and build an ArrayList instead of an array (because you won't know its size beforehand):
String fileName = "input.txt";
File file = new File(fileName);
Scanner scanner = new Scanner(file);
ArrayList<Byte> covertDataList= new ArrayList<>();
while(scanner.hasNextLine()){
String line = scanner.nextLine(); // the line should be just a number
covertDataList.add(Byte.parseByte(line)); // no substring needed
}
If you want to fail nicely when the file format is wrong, you may surround parseByte with a try/catch block.
About the ArrayList
If you want to use your list as an array, you can just:
use covertDataList.get(i) instead of covertDataArray[i]
use covertDataList.set(i, value); instead of covertDataArray[i] = value;
If you really need an array (I don't see the point here), you can do this:
Byte[] covertDataArray = covertDataList.toArray(new Byte[list.size()]);

Categories

Resources