Unexpected behavior constructing a java.util.Scanner - java

I have the following file lines.txt
Line1
Line2
Line3
I'm using a Scanner to parse the contents of this file line by line.
I have the following setup in LinesReader.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
class Line {
Line(String content) {
this.content = content;
}
public String content;
public String toString() {
return content;
}
}
public class LinesReader {
public static Line buildLine(InputStream is) {
Scanner scanner = new Scanner(is);
if (scanner.hasNextLine()) {
return new Line(scanner.nextLine());
}
return null;
}
public static Line buildLine(Scanner scanner) {
if (scanner.hasNextLine()) {
return new Line(scanner.nextLine());
}
return null;
}
public static void main(String[] args) throws FileNotFoundException {
List<Line> lines = new ArrayList<>();
Line line = null;
FileInputStream is = new FileInputStream("lines.txt");
// buildLine(scanner) works as expected
while ((line = buildLine(is)) != null) {
lines.add(line);
}
System.err.println(lines);
}
}
The output is
[Line1]
The expected output would be
[Line1, Line2, Line3]
I understand the Scanner implements AutoCloseable, but according to the documentation that would only apply for a
try-with-resources construct and not here. Also, when i debug it is says the underlying stream is open. The second call to scanner.hasNextLine() unexpectedly fails.
If I construct the scanner once in main() it works as expected.
My java version is 1.8.0_275
In response to a comment by #Sweeper the scanner seems to buffer up more than what is consumed, the documentation sort of contradicts that.
for hasNextLine()
The scanner does not advance past any input.
for nextLine()
Since this method continues to search through the input looking for a line separator, it may buffer all of the input searching for the line to skip if no line separators are present.
Emphasis mine.

The documentation for hasNextLine()
The scanner does not advance past any input.
is somewhat misleading. It doesn't advance the internal buffer of the scanner, which is obvious, but several kilobytes of the stream is read.
In this case the entire stream is consumed by hasNextLine().
My personal opinion is that this is a defect in the implementation of Scanner. Scanner is designed for convenience and simplicity, not for performance. Wrapping the InputStream in a BufferedInputStream would be sensible and make the usage a a lot simpler.

A Scanner is buffered, and one cannot expect that the underlying (File)InputStream is not read further than what is returned by nextLine. In fact the underlying FileInputStream could be advanced to the end-of-file. So the first Scanner instance could let the FileInputStream at the end-of-file.
Since java 8, it is easier to use Path, Files, Stream.
Path path = Paths.get("lines.txt");
try (Stream<String> in = Files.lines(path, Charset.defaultCharset())) {
List<Line> lines = in.map(Line::new)
.collect(Collectors.toList());
...
}
The above also automatically closes the file, try-with-resources syntax.
The code is smaller with the new classes.

Try this.
...
FileInputStream is = new FileInputStream("lines.txt");
while (true) {
System.err.println(is.available());
Scanner scanner = new Scanner(is);
if (scanner.hasNextLine()) {
lines.add(new Line(scanner.nextLine()));
} else {
break;
}
}
I got the following.
18
0 <---- FileInputStream is not avaliable for the 2nd Scanner
[Line1]
But if I move the line
while (true) {
FileInputStream is = new FileInputStream("lines.txt");
System.err.println(is.available());
...
}
the loop keeps printing out 18.

Related

Java - Take any char one by one input from the Scanner [duplicate]

I am used to the c-style getchar(), but it seems like there is nothing comparable for java. I am building a lexical analyzer, and I need to read in the input character by character.
I know I can use the scanner to scan in a token or line and parse through the token char-by-char, but that seems unwieldy for strings spanning multiple lines. Is there a way to just get the next character from the input buffer in Java, or should I just plug away with the Scanner class?
The input is a file, not the keyboard.
Use Reader.read(). A return value of -1 means end of stream; else, cast to char.
This code reads character data from a list of file arguments:
public class CharacterHandler {
//Java 7 source level
public static void main(String[] args) throws IOException {
// replace this with a known encoding if possible
Charset encoding = Charset.defaultCharset();
for (String filename : args) {
File file = new File(filename);
handleFile(file, encoding);
}
}
private static void handleFile(File file, Charset encoding)
throws IOException {
try (InputStream in = new FileInputStream(file);
Reader reader = new InputStreamReader(in, encoding);
// buffer for efficiency
Reader buffer = new BufferedReader(reader)) {
handleCharacters(buffer);
}
}
private static void handleCharacters(Reader reader)
throws IOException {
int r;
while ((r = reader.read()) != -1) {
char ch = (char) r;
System.out.println("Do something with " + ch);
}
}
}
The bad thing about the above code is that it uses the system's default character set. Wherever possible, prefer a known encoding (ideally, a Unicode encoding if you have a choice). See the Charset class for more. (If you feel masochistic, you can read this guide to character encoding.)
(One thing you might want to look out for are supplementary Unicode characters - those that require two char values to store. See the Character class for more details; this is an edge case that probably won't apply to homework.)
Combining the recommendations from others for specifying a character encoding and buffering the input, here's what I think is a pretty complete answer.
Assuming you have a File object representing the file you want to read:
BufferedReader reader = new BufferedReader(
new InputStreamReader(
new FileInputStream(file),
Charset.forName("UTF-8")));
int c;
while((c = reader.read()) != -1) {
char character = (char) c;
// Do something with your character
}
Another option is to not read things in character by character -- read the entire file into memory. This is useful if you need to look at the characters more than once. One trivial way to do that is:
/** Read the contents of a file into a string buffer */
public static void readFile(File file, StringBuffer buf)
throws IOException
{
FileReader fr = null;
try {
fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
char[] cbuf = new char[(int) file.length()];
br.read(cbuf);
buf.append(cbuf);
br.close();
}
finally {
if (fr != null) {
fr.close();
}
}
}
Wrap your input stream in a buffered reader then use the read method to read one byte at a time until the end of stream.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Reader {
public static void main(String[] args) throws IOException {
BufferedReader buffer = new BufferedReader(
new InputStreamReader(System.in));
int c = 0;
while((c = buffer.read()) != -1) {
char character = (char) c;
System.out.println(character);
}
}
}
If I were you I'd just use a scanner and use ".nextByte()". You can cast that to a char and you're good.
You have several options if you use BufferedReader. This buffered reader is faster than Reader so you can wrap it.
BufferedReader reader = new BufferedReader(new FileReader(path));
reader.read(char[] buffer);
this reads line into char array. You have similar options. Look at documentation.
Wrap your reader in a BufferedReader, which maintains a buffer allowing for much faster reads overall. You can then use read() to read a single character (which you'll need to cast). You can also use readLine() to fetch an entire line and then break that into individual characters. The BufferedReader also supports marking and returning, so if you need to, you can read a line multiple times.
Generally speaking, you want to use a BufferedReader or BufferedInputStream
on top of whatever stream you are actually using since the buffer they maintain will make multiple reads much faster.
In java 5 new feature added that is Scanner method who gives the chance to read input character by character in java.
for instance;
for use Scanner method import java.util.Scanner;
after in main method:define
Scanner myScanner = new Scanner(System.in);
//for read character
char anything=myScanner.findInLine(".").charAt(0);
you anything store single character, if you want more read more character declare more object like anything1,anything2...
more example for your answer please check in your hand(copy/paste)
import java.util.Scanner;
class ReverseWord {
public static void main(String args[]){
Scanner myScanner=new Scanner(System.in);
char c1,c2,c3,c4;
c1 = myScanner.findInLine(".").charAt(0);
c2 = myScanner.findInLine(".").charAt(0);
c3 = myScanner.findInLine(".").charAt(0);
c4 = myScanner.findInLine(".").charAt(0);
System.out.print(c4);
System.out.print(c3);
System.out.print(c2);
System.out.print(c1);
System.out.println();
}
}
This will print 1 character per line from the file.
try {
FileInputStream inputStream = new FileInputStream(theFile);
while (inputStream.available() > 0) {
inputData = inputStream.read();
System.out.println((char) inputData);
}
inputStream.close();
} catch (IOException ioe) {
System.out.println("Trouble reading from the file: " + ioe.getMessage());
}

Empty line in file

I could not find an explanation and those I found I am unsure of. So please confirm my doubts:
I am reading through a file using a while loop and if the line in the file is empty it skips and goes to next line. I just want to make sure the code I am using is correct for the what I just described:
while((strLine = reader.readLine())!= null) <----- While loop that is suppose to read Line by Line
{
if (strLine.isEmpty() == false) <----- Check for empty Line
{
/** My Code **/
}
else
{
/** My Code **/
}
}
Yes! What you are doing is what you want to do. You can just try compiling it yourself, you know. Trial and error. If you could not figure out how to use the reader, as the other answers propose, here you go:
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Trial {
public static void main(String[] args) throws IOException {
String strLine;
BufferedReader reader = new BufferedReader(new FileReader(
"/home/user234/folder1/filename"));
while ((strLine = reader.readLine()) != null) {
if (!strLine.isEmpty()) {
System.out.println("notEMPTY");
} else {
System.out.println("EMPTY");
}
}
}
}
yes. it will work fine.
while(/* While scanner has next line */)
{
line = scanner.nextLine();
if( /* line is not equal to null */) {
/* perform code */
}
}
The logic shown in the above code makes sense to what you have described. It should perform what you desire.
The Java Reader does not have a readline() method.
If you want to do specific parsing of tokens you should use the Scanner. Scanner has a nextLine() method to grab each line, but throws an Exception if there is no next line. Therefore you should use Scanner.hasNextLine() for your while condition.
Scanner s = new Scanner("filename.txt");
String line;
while(s.hasNextLine()){ // check for next line
line = s.nextLine(); // get next line
if(line == ""){ // check if line is empty
System.out.println("Empty");
} else {
System.out.println("Not Empty:" + line);
}
}
Here's a live Example using Ideone.
EDIT: The BufferedReader does have a readline() method, as used by #natsirun. Although for any file parsing more complicated than line reading you would prefer the Scanner.

How to read a file containg just 1 line or 1 word in Java

I have a file, I know that file will always contain only one word.
So what should be the most efficient way to read this file ?
Do i have to create input stream reader for small files also OR Is there any other options available?
Well something's got to convert bytes to characters.
Personally I'd suggest using Guava which will allow you to write something like this:
String text = Files.toString(new File("..."), Charsets.UTF_8);
Obviously Guava contains much more than just this. It wouldn't be worth it for this single method, but it's positive treasure trove of utility classes. Guava and Joda Time are two libraries I couldn't do without :)
Use Scanner
File file = new File("filename");
Scanner sc = new Scanner(file);
System.out.println(sc.next()); //it will give you the first word
if you have int,float...as first word you can use corresponding function like nextInt(),nextFloat()...etc.
Efficient you mean performance-wise or code simplicity (lazy programmer)?
If it is the second, then nothing I know beats:
String fileContent = org.apache.commons.io.FileUtils.readFileToString("/your/file/name.txt")
- Use InputStream and Scanner for reading the file.
Eg:
public class Pass {
public static void main(String[] args){
File f = new File("E:\\karo.txt");
Scanner scan;
try {
scan = new Scanner(f);
while(scan.hasNextLine()){
System.out.println(scan.nextLine());
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
- Guava Library handles this beautifully and efficiently.
Use BufferedReader and FileReader classes. Only two lines of code will suffice to read one word/one line file.
BufferedReader br = new BufferedReader(new FileReader("Demo.txt"));
System.out.println(br.readLine());
Here is a small program to do so. Empty file will cause to print 'null' as output.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class SmallFileReader
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("Demo.txt"));
System.out.println(br.readLine());
}
}

Java Read from file to Array runtime error

import java.io.*;
import java.util.*;
public class Readfilm {
public static void main(String[] args) throws IOException {
ArrayList films = new ArrayList();
File file = new File("filmList.txt");
try {
Scanner scanner = new Scanner(file);
while (scanner.hasNext())
{
String filmName = scanner.next();
System.out.println(filmName);
}
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
}}
Above is the code I'm currently attempting to use, it compiles fine, then I get a runtime error of:
java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:907)
at java.util.Scanner.next(Scanner.java:1416)
at Readfilm.main(Readfilm.java:15)
I've googled the error and not had anything that helped (I only googled the first 3 lines of the error)
Basically, the program I'm writing is part of a bigger program. This part is to get information from a text file which is written like this:
Film one / 1.5
Film two / 1.3
Film Three / 2.1
Film Four / 4.0
with the text being the film title, and the float being the duration of the film (which will have 20 minutes added to it (For adverts) and then will be rounded up to the nearest int)
Moving on, the program is then to put the information in an array so it can be accessed & modified easily from the program, and then written back to the file.
My issues are:
I get a run time error currently, not a clue how to fix? (at the moment I'm just trying to read each line, and store it in an array, as a base to the rest of the program) Can anyone point me in the right direction?
I have no idea how to have a split at "/" I think it's something like .split("/")?
Any help would be greatly appreciated!
Zack.
Your code is working but it reads just one line .You can use bufferedReader here is an example import java.io.*;
class FileRead
{
public static void main(String args[])
{
try{
// Open the file that is the first
// command line parameter
FileInputStream fstream = new FileInputStream("textfile.txt");
// Get the object of DataInputStream
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
// Print the content on the console
System.out.println (strLine);
}
//Close the input stream
in.close();
}catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
}
}
And here is an split example class StringSplitExample {
public static void main(String[] args) {
String st = "Hello_World";
String str[] = st.split("_");
for (int i = 0; i < str.length; i++) {
System.out.println(str[i]);
}
}
}
I wouldn't use a Scanner, that's for tokenizing (you get one word or symbol at a time). You probably just want to use a BufferedReader which has a readLine method, then use line.split("/") as you suggest to split it into two parts.
Lazy solution :
Scanner scan = ..;
scan.nextLine();

How do I read input character-by-character in Java?

I am used to the c-style getchar(), but it seems like there is nothing comparable for java. I am building a lexical analyzer, and I need to read in the input character by character.
I know I can use the scanner to scan in a token or line and parse through the token char-by-char, but that seems unwieldy for strings spanning multiple lines. Is there a way to just get the next character from the input buffer in Java, or should I just plug away with the Scanner class?
The input is a file, not the keyboard.
Use Reader.read(). A return value of -1 means end of stream; else, cast to char.
This code reads character data from a list of file arguments:
public class CharacterHandler {
//Java 7 source level
public static void main(String[] args) throws IOException {
// replace this with a known encoding if possible
Charset encoding = Charset.defaultCharset();
for (String filename : args) {
File file = new File(filename);
handleFile(file, encoding);
}
}
private static void handleFile(File file, Charset encoding)
throws IOException {
try (InputStream in = new FileInputStream(file);
Reader reader = new InputStreamReader(in, encoding);
// buffer for efficiency
Reader buffer = new BufferedReader(reader)) {
handleCharacters(buffer);
}
}
private static void handleCharacters(Reader reader)
throws IOException {
int r;
while ((r = reader.read()) != -1) {
char ch = (char) r;
System.out.println("Do something with " + ch);
}
}
}
The bad thing about the above code is that it uses the system's default character set. Wherever possible, prefer a known encoding (ideally, a Unicode encoding if you have a choice). See the Charset class for more. (If you feel masochistic, you can read this guide to character encoding.)
(One thing you might want to look out for are supplementary Unicode characters - those that require two char values to store. See the Character class for more details; this is an edge case that probably won't apply to homework.)
Combining the recommendations from others for specifying a character encoding and buffering the input, here's what I think is a pretty complete answer.
Assuming you have a File object representing the file you want to read:
BufferedReader reader = new BufferedReader(
new InputStreamReader(
new FileInputStream(file),
Charset.forName("UTF-8")));
int c;
while((c = reader.read()) != -1) {
char character = (char) c;
// Do something with your character
}
Another option is to not read things in character by character -- read the entire file into memory. This is useful if you need to look at the characters more than once. One trivial way to do that is:
/** Read the contents of a file into a string buffer */
public static void readFile(File file, StringBuffer buf)
throws IOException
{
FileReader fr = null;
try {
fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
char[] cbuf = new char[(int) file.length()];
br.read(cbuf);
buf.append(cbuf);
br.close();
}
finally {
if (fr != null) {
fr.close();
}
}
}
Wrap your input stream in a buffered reader then use the read method to read one byte at a time until the end of stream.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Reader {
public static void main(String[] args) throws IOException {
BufferedReader buffer = new BufferedReader(
new InputStreamReader(System.in));
int c = 0;
while((c = buffer.read()) != -1) {
char character = (char) c;
System.out.println(character);
}
}
}
If I were you I'd just use a scanner and use ".nextByte()". You can cast that to a char and you're good.
You have several options if you use BufferedReader. This buffered reader is faster than Reader so you can wrap it.
BufferedReader reader = new BufferedReader(new FileReader(path));
reader.read(char[] buffer);
this reads line into char array. You have similar options. Look at documentation.
Wrap your reader in a BufferedReader, which maintains a buffer allowing for much faster reads overall. You can then use read() to read a single character (which you'll need to cast). You can also use readLine() to fetch an entire line and then break that into individual characters. The BufferedReader also supports marking and returning, so if you need to, you can read a line multiple times.
Generally speaking, you want to use a BufferedReader or BufferedInputStream
on top of whatever stream you are actually using since the buffer they maintain will make multiple reads much faster.
In java 5 new feature added that is Scanner method who gives the chance to read input character by character in java.
for instance;
for use Scanner method import java.util.Scanner;
after in main method:define
Scanner myScanner = new Scanner(System.in);
//for read character
char anything=myScanner.findInLine(".").charAt(0);
you anything store single character, if you want more read more character declare more object like anything1,anything2...
more example for your answer please check in your hand(copy/paste)
import java.util.Scanner;
class ReverseWord {
public static void main(String args[]){
Scanner myScanner=new Scanner(System.in);
char c1,c2,c3,c4;
c1 = myScanner.findInLine(".").charAt(0);
c2 = myScanner.findInLine(".").charAt(0);
c3 = myScanner.findInLine(".").charAt(0);
c4 = myScanner.findInLine(".").charAt(0);
System.out.print(c4);
System.out.print(c3);
System.out.print(c2);
System.out.print(c1);
System.out.println();
}
}
This will print 1 character per line from the file.
try {
FileInputStream inputStream = new FileInputStream(theFile);
while (inputStream.available() > 0) {
inputData = inputStream.read();
System.out.println((char) inputData);
}
inputStream.close();
} catch (IOException ioe) {
System.out.println("Trouble reading from the file: " + ioe.getMessage());
}

Categories

Resources