StreamTokenizer infinite input problem from console - java

I am beginner in Java, so during my learning another topic as StreamTokenizer, I faced some kind of intresting problem. And I didn't found any close solutions or hints in the Internet.
So, basically, almost every educational source give us an example like this:
import java.io.*;
public class pr_23 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer st = new StreamTokenizer(br);
while (st.nextToken() != st.TT_EOF)
if (st.ttype == st.TT_NUMBER)
System.out.print(st.nval + " "); // not infinite cycle
br.close();
}
}
And it works well. But if I include in the cycle some other operators with st.nval, like double b = st.nval and exclude this System.out.print() code, compiler cant determine the end of the Stream in this case anymore, so it starts infinite reading. I wanted StreamTokenizer gave numbers to my ArrayList, but magically it cant see the end of Stream in this case with similar cycle. What's intresting it does work correctly if I use FileInputStream instead of InputStreamReader. But I need to get input from the console, not from a file. Also, using FIS in Tokenizer is deprecated. So here's similar code, but it doesnt work properly:
import java.io.*;
import java.util.ArrayList;
public class pr_23 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer st = new StreamTokenizer(br);
ArrayList<Integer> a = new ArrayList<>();
while (st.nextToken() != st.TT_EOF) {
a.add((int)st.nval); // infinite cycle
}
System.out.print(a);
br.close();
}
}
P.S. input is meant to be only int numbers for simplicity

Please understand that your loop is repeating until the input reaches to the EOF. And, your latter code does not output anything before your loop would exit. So, if you want to see your output with the latter code, you must close your standard input stream first. To close standard input, you should send EOF code from keyboard. On Linux and macos, you can close standard input with Ctrl-D, and on Windows, it is Ctrl-Z.

The source of your problem is using System.in.
Try reading from a file:
import java.io.*;
import java.util.ArrayList;
public class pr_23 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("myfile.txt"));
StreamTokenizer st = new StreamTokenizer(br);
ArrayList<Integer> a = new ArrayList<>();
while (st.nextToken() != st.TT_EOF) {
a.add((int)st.nval); // infinite cycle
}
System.out.print(a);
br.close();
}
}
The problem is that you won't get an EOF in a System.in if you run it interactively. Though you would get it if you run it like this:
java pr_23 < myfile.txt
By the way a better way to write this without the dangling close() would be:
import java.io.*;
import java.util.ArrayList;
public class pr_23 {
public static void main(String[] args) throws IOException {
// using try this way will close br automagically
try (BufferedReader br = new BufferedReader(new FileReader("myfile.txt"))) {
StreamTokenizer st = new StreamTokenizer(br);
ArrayList<Integer> a = new ArrayList<>();
while (st.nextToken() != st.TT_EOF) {
a.add((int)st.nval); // infinite cycle
}
System.out.print(a);
}
}
}

Related

java - read user input and print line if it is a duplicate

So I'm learning about reading text files in java and I'm trying to write a program that reads user input one line at a time and outputs the current line if and only if it is a duplicate of some previous line. This is the part of code I'm struggling with and was wondering if I could get a push in the right direction. Right now it currently asks for user input, and when I write a line and press enter, the program ends without printing anything.
public static void doIt(BufferedReader r, PrintWriter w) throws IOException {
Set<String> s = new HashSet<String>();
while(true) {
String line = r.readLine();
if(s.contains(line)) {
s.add(line);
}else {
break;
}
}
for (String text : s) {
w.println(text);
}
}
You can keep two mutable states, one for all the lines and one for duplicate lines.
Example below. (You can exit program on :q).
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
public class CheckDupes {
public static void main(String[] args) throws IOException {
Set<String> lines = new HashSet<String>();
Set<String> duplicateLines = new HashSet<String>();
BufferedReader stdReader =
new BufferedReader(new InputStreamReader(System.in));
String line = null;
while (!(line = stdReader.readLine()).equals(":q")) {
if (lines.contains(line)) {
duplicateLines.add(line);
} else {
lines.add(line);
}
}
duplicateLines.forEach(l -> System.out.println(l));
}
}
Input/ Output
love is great
weather is good
software is version 4
weather is good
love is great
:q
weather is good
love is great

Reading a list of strings from command line in Java

I am trying to read a list of strings from command line in Java and then print the strings.
Here is the code: -
public class Example {
public static void main(String args[] ) throws Exception {
List<String> list = new ArrayList<String>();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = br.readLine()) != null) {
list.add(line);
}
System.out.println(list);
}
}
But it enters into an infinite loop and never prints the list.
Can anyone please help me point the mistake in my code?
Checking the terminating condition inside the while loop will solve your issue.
public class Example {
public static void main(String args[] ) throws Exception {
List<String> list = new ArrayList<String>();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while(true) {
line = br.readLine();
if (line == null || line.isEmpty()) {
break;
}
list.add(line);
}
System.out.println(list);
}
}
There's nothing wrong with your code. It doesn't terminate simply because it haven't got the correct "signal" yet.
Try Ctrl+D after you are done with the input. It should work for most cases.
Or Ctrl+Z for windows command line.
If you are using Java 8. There's a shorter version
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.stream.Collectors;
public class ReadLinesFromStdin {
public static void main(String [] args) throws IOException {
List<String> lines = new BufferedReader(new InputStreamReader(System.in))
.lines().collect(Collectors.toList());
System.out.println(lines);
}
}

Why people use so many codes in competitive programming to write solution?

Sometimes i solve problems in 'codeforces.org' and after every solve i see the solution of others.But most of the others solution contains so many codes.
For example:
I have written a code for the problem Domino Piling like following.
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int m = in.nextInt(), n = in.nextInt();
int count = n*(m/2);
if(m%2 == 1)
count += n/2;
System.out.println(count);
in.close();
}
}
But petr who ranked in 2nd in codeforces wrote this solution like
import java.io.*;
import java.util.*;
public class Template implements Runnable {
private void solve() throws IOException {
int n = nextInt();
int m = nextInt();
writer.println(n * m / 2);
}
public static void main(String[] args) {
new Template().run();
}
BufferedReader reader;
StringTokenizer tokenizer;
PrintWriter writer;
public void run() {
try {
reader = new BufferedReader(new InputStreamReader(System.in));
tokenizer = null;
writer = new PrintWriter(System.out);
solve();
reader.close();
writer.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
int nextInt() throws IOException {
return Integer.parseInt(nextToken());
}
long nextLong() throws IOException {
return Long.parseLong(nextToken());
}
double nextDouble() throws IOException {
return Double.parseDouble(nextToken());
}
String nextToken() throws IOException {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
}
Here what we see that he used thread and his own customized input/output technique.But i am not understanding why he solved this solution like this and what's the need of own customized i/o technique??
There's one thing which impressed me most is,besides his long code his code execution time is better than me.His code execution time is only '90 milliseconds' and mine is '248 milliseconds'.
Can anyone explain me the reason behind it??
Many coders actually have predefined templates for competitions. On codeforces, usually, they just copy that template into a file before even reading the problem they want to code and then code into that.
That bunch of code is actually fast input for Java. Some problems on codeforces require that. Petr must have just copied his usual template and coded that problem there, even if it wasn't necessary. The actual code Petr wrote specifically for this problem was the 3 lines function called Solve.
I saw this on a book called "算法竞赛入门经典" and the author said that this code is about 5~10 times faster than scanf.
Since I don't know java, I can't explain what this code means, but I'm sure you can understand it.
/** Class for buffered reading int and double values */
class Reader {
static BufferedReader reader;
static StringTokenizer tokenizer;
/** call this method to initialize reader for InputStream */
static void init(InputStream input) {
reader = new BufferedReader(
new InputStreamReader(input) );
tokenizer = new StringTokenizer("");
}
/** get next word */
static String next() throws IOException {
while ( ! tokenizer.hasMoreTokens() ) {
//TODO add check for eof if necessary
tokenizer = new StringTokenizer(
reader.readLine() );
}
return tokenizer.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt( next() );
}
static double nextDouble() throws IOException {
return Double.parseDouble( next() );
}
}

File not opening in Java

Im trying to read a simple text file with contents
input.txt
Line 1
Line 2
Line 3
But it always goes to the exception and prints Error.
import java.io.*;
import java.util.*;
public class Main {
public static void main(String args[]){
List<String> text = new ArrayList<String>();
try{
BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
for (String line; (line = reader.readLine()) != null; ) {
text.add(line);
}
System.out.println(text.size()); //print how many lines read in
reader.close();
}catch(IOException e){
System.out.println("ERROR");
}
}
}
Im using Eclipse as my IDE if that makes a difference. I've tried this code on http://www.compileonline.com/compile_java_online.php
and it runs fine, why wont it run in Eclipse?
give complete file path like "C:\\folder_name\\input.txt" or place input.txt inside src directory of eclipse project.
public class Main {
public static void main(String args[]){
List<String> text = new ArrayList<String>();
try{
BufferedReader reader = new BufferedReader(
new FileReader("input.txt")); //<< your problem is probably here,
//More than likely you have to supply a path the input file.
//Something like "C:\\mydir\\input.txt"
for (String line; (line = reader.readLine()) != null; ) {
text.add(line);
}
System.out.println(text.size()); //print how many lines read in
reader.close();
}catch(IOException e){
System.out.println("ERROR"); //This tells you nothing.
System.out.println(e.getMessage()); //Do this
//or
e.printStackTrace(); //this or both
}
}
}
You most likely have a bad path. Consider this main instead:
public class Main {
public static void main(String args[]) throws Exception {
List<String> text = new ArrayList<String>();
BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
for (String line; (line = reader.readLine()) != null; ) {
text.add(line);
}
System.out.println(text.size()); //print how many lines read in
reader.close();
}
}
The "throws Exception" addition allows you to focus on the code, and consider better error handling later. Also consider using File f = new File("input.txt") and use that, because it allows you to print out f.getAbsolutePath() which tells you the filename it was actually looking for.
Changing input.txt to src\\input.txt solved the problem!
I guess it was because the current directory isnt actually the src folder its the parent,
Thanks for the help!

Basic Java IO, always throwing exception

I'm new to Java and am trying to write a program that has one argument, the path of a text file. The program will locate the text file and print it out to the screen. Eventually I'm going to build this to format the given text file and then print it out to an outfile, but I'll get there later.
Anyways my program is always throwing and IOException and I'm not sure why. Given the argument C:\JavaUtility\input.txt , I receieve "Error, could not read file" during runtime. My code is located below.
import java.io.*;
public class utility {
public static void main(String[] path){
try{
FileReader fr = new FileReader(path[0]);
BufferedReader textReader = new BufferedReader(fr);
String aLine;
int numberOfLines = 0;
while ((aLine = textReader.readLine()) != null) {
numberOfLines++;
}
String[] textData = new String[numberOfLines];
for (int i=0;i < numberOfLines; i++){
textData[i] = textReader.readLine();
}
System.out.println(textData);
return;
}
catch(IOException e){
System.out.println("Error, could not read file");
}
}
}
[EDIT] Thanks for all the help everyone! So given my end goal, I thought it would still be useful to find the number of lines and store in a finite array. So I ended up writing two classes. The first, ReadFile.java found the data I wanted and handles most of the reading. The second FileData.java invokes the methods in ReadFile and prints out. I've posted them below incase someone later finds them useful.
package textfiles;
import java.io.*;
public class ReadFile {
private String path;
public ReadFile(String file_path){
path = file_path;
}
int readLines() throws IOException{
FileReader file_to_read = new FileReader(path);
BufferedReader bf = new BufferedReader(file_to_read);
String aLine;
int numberOfLines = 0;
while ((aLine = bf.readLine()) != null){
numberOfLines++;
}
bf.close();
return numberOfLines;
}
public String[] OpenFile() throws IOException{
FileReader fr = new FileReader(path);
BufferedReader textReader = new BufferedReader(fr);
int numberOfLines = readLines();
String[] textData = new String[numberOfLines];
for(int i=0; i < numberOfLines; i++){
textData[i] = textReader.readLine();
}
textReader.close();
return textData;
}
}
package textfiles;
import java.io.IOException;
public class FileData {
public static void main(String[] args)throws IOException{
String file_name = args[0];
try{
ReadFile file = new ReadFile(file_name);
String[] aryLines = file.OpenFile();
for(int i=0; i < aryLines.length; i++){
System.out.println(aryLines[i]);
}
}
catch (IOException e){
System.out.println(e.getMessage());
}
}
}
You're at the end of the file. When you determine the number of lines in the file, you've read until the end of the file,and the EOF Flag is set. [Edit: As #EJP notes below, BufferedReader returns null reading past the end of a file. The fact your reader isn't where you want it, however, remains true.] In the past, I've hacked around this simply by closing and re-opening the file. Alternatively, look into Array Lists or simple Lists. They're dynamically re-sizing, so you don't need to know the number of lines in the file ahead of time.
As mentioned by #mikeTheLiar you are at End Of File. BufferedReader reference is File Handler with an internal cursor pointing to current position in file. As you fire readLine() method, the pointer reads characters till it reaches new line character, returning the string. The pointer is set to new position. Once you read all the lines then readLine() returns null. After that if you call readLine() it will throw IOException. As noted by #EJP
One of the best coding rules while using IO API is to always check for EOF condition - the way you have in first loop. Once you reach EOF after that you should not call read method on the same reference without resetting the cursor - this can be done by calling reset() method.
IMHO, in your case there is no need for second loop. You can achieve the functionalty using one loop only.
import java.io.*;
import java.util.ArrayList;
public class utility {
public static void main(String[] path){
try{
FileReader fr = new FileReader(path[0]);
BufferedReader textReader = new BufferedReader(fr);
String aLine;
int numberOfLines = 0;
ArrayList readLines = new ArrayList();
while ((aLine = textReader.readLine()) != null) {
numberOfLines++;
readLines.add(aLine);
}
//Assuming you need array of lines, if not then you can print the lines directly in above loop
String[] textData = readLines.toArray();
System.out.println(textData);
return;
}
catch(IOException e){
System.out.println("Error, could not read file");
}
}
}
EDIT
I tried your code - it is working fine and printing the array reference. As suggested in comments the problem is with source (file might not be readable due to security or any other reason) - if you can print the exception message and get the exact line number where exception is thrown it would be helpful.
Couple of observations apart from the IO exception:
You are trying to open the file twice. readLines() method is called from within OpenFile(). Following the sequence of code file is first opened in OpenFile() when you create textReader. After that you are calling readLines() which is again trying to open the file when you create file_to_read.
You should try to avoid that and in your flow you should call int numberOfLines = readLines(); before FileReader fr = new FileReader(path);
Again IMHO there should be only one method and you should iterate over the file only once - both from efficience/performance and code maintainability perspective. You can change your ReadFile class as follows:
package textfiles;
import java.io.*;
import java.util.ArrayList;
public class ReadFile {
private String path;
public ReadFile(String file_path){
path = file_path;
}
//You need not have separate file for counting lines in file
//Java provides dynamic sized arrays using ArrayList
//There is no need to count lines
public String[] OpenFile() throws IOException{
FileReader fr = new FileReader(path);
BufferedReader textReader = new BufferedReader(fr);
ArrayList fileLines = new ArrayList();
String readLine = textReader.readLine();
while(readLine != null){
fileLines.add(readLine);
readLine = textReader.readLine();
}
textReader.close();
return fileLines.toArray();
}
}
Another small observation: in some places the java variable naming conventions are not followed. OpenFile() method should be openFile() and file_to_read should be fileToRead
Contrary to several answers here, readLine() does not throw an exception at end of file, it just keeps returning null. Your problem is being masked by another one. Never just make up your own error messages. Always print the one that comes with the exception. If you had done that you would probably have found the problem immediately. Almost certainly you weren't able to open the file at all, either because it wasn't there or you didn't have read access. The exception will tell you.

Categories