SpotBugs - Method ignores results of InputStream.read() - java

I am having some problems debugging a code, I managed to debug all bugs but one:
Method ignores results of InputStream.read(), the debugger (SpotBugs) says the problem is on reader.read(buffer, 0, n) and advises me to check the return value otherwise the caller will not be able to correctly handle the case where fewer bytes were read than the caller requested.
char[] buffer = new char[n];
try{
reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
reader.read(buffer,0,n);
reader.close();
}
catch(RuntimeException e) {
throw e;
}
catch(Exception e) {
System.out.println("Something went wrong");
}
for(int i=0;i<buffer.length;i++) {
int swap = i % 2;
if (Integer.toString(swap).equals(Integer.toString(1))) {
buffer[i] = ' ';
}
}
System.out.print(buffer);
How can I fix this bug?

read() when used with a buffer returns the actual number of the bytes read (or -1 for end of stream). It's possible that the buffer isn't filled completely with a single read (although small buffers are, since data is transferred in blocks), so you need to make sure (i.e. use a while loop) you've read the amount of bytes you intended to.

R. Castro gave you good explanation, but what's missing (in obvious words) is you are not checking how many bytes are being read from file. The number can be different than size of your buffer. That's what spotbug is trying to tell you. Your file can be longer or shorter than buffer size. You are not handling the case where file is longer than buffer size. And loop you have needs to be changed to whatever number of bytes are read than buffer.length

Related

Using 2 BufferedReaders to read 1 file

So i'm trying to create a 2d character array from a .txt file. The first while-loop calculates to number of columns and rows. The second while-loop is to enter chars into the 2d array. However when i create BufferedReader br2 and use readLine() and then try to print it the line prints out "null". Why does the second BufferedReader start at the end of the file?
public Maze(FileReader reader){
try {
BufferedReader br = new BufferedReader(reader);
cols = 0;
rows = 0;
str = br.readLine();
while (str != null) {
if (str.length() > cols) {
cols = str.length();
}
rows++;
str = br.readLine();
}
}
catch (IOException e) {
System.out.println("Error");
}
maze = new char[getNumRows()][getNumColumns()];
try {
BufferedReader br2 = new BufferedReader(reader);
line = br2.readLine();
System.out.println(line);
while ((line = br2.readLine()) != null) {
System.out.println(line);
for (int i = 0; i < getNumColumns(); i++) {
maze[row][i] = line.charAt(i);
}
row++;
}
}
catch (IOException e) {
System.out.println("Error");
}
}
this is how I call it from main
public class RobotTest {
public static void main(String[] args) throws IOException{
File file = new File(args[0]);
Maze maze = new Maze(new FileReader(file));
}
}
You are using the same reader for initializing both of the BufferedReaders and after the first one finishes reading that means the next one will continue reading at the EOF. You must return the second one to the beginning of the file before iterating again through it.
You can reset the pointer of the reader by using FileReader.reset()
You can checkout mark() as well in the documentation.
Source: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Reader.html#reset()
As the name indicates, a 'BufferedReader' uses a buffer.
There's a reason for that.
Harddisks, network communications, SSDs - these are all concepts that tend to operate in terms of packets. They write or read largish chunks. For example, with networking, you can't just 'send a bunch of bytes down a wire' - you need to send a packet, because the packet includes information about where the packet is supposed to go and to solve the ordering issue (when you send packets on the internet, one you sent later may arrive earlier, so packets need an index number on them so the receiver can re-order them in the right way).
If you send one byte, okay - but that'll be ~200 bytes on the wire. Hence, sending 1 byte 5000 times is ~1 million bytes sent, whereas sending 5000 bytes in one go is only 5200 bytes; a 1000x difference!
Similar principles apply elsewhere, thus, 'send 1 byte' or 'read 1 byte' is often incredibly, factor 1000x inefficient.
Hence, buffers. You ASK for one character or one line (which can be quite a short line) from your BufferedReader and it will dutifully give you this, but under the hood it has read an entire largish chunk (because that is efficient), and will be fielding your further requests for e.g. another line from this buffer until it runs out and then it grabs another chunk.
The upshot of all that, is that you CAN NEVER use a reader ever again once you wrap it in a bufferedreader. You are 'committed' to the buffer now: That BufferedReader is the only thing you can read, from here on out, until the stream is done.
You're creating another one, and thus, your code is buggy: You're now effectively skpping whatever the first BufferedReader buffered; given that you're getting null out, that means right now it buffered the entire contents of the file, but perhaps on another system, a bigger file, it wouldn't return null, but some line deep into the file. Either way, you cannot use that filereader anymore once you have created a bufferedreader.
The solution is simple enough: Make the bufferedreader, once, and pass that around. Don't keep making BufferedReader instances out of it.
Also, resources need to be 'protected' - you must close them no matter how your code exits. If your code throws an error you need to still close the resources; failure to do so means your program will eventually get stuck and will be incapable of opening files, forever - the only way out is to completely close the app. Finally, FileReader is basically broken; it uses 'platform default charset encoding' which is anyone's guess. You want to 'hardcode' what encoding it has, and usually, the right answer is "UTF-8". This doesn't matter if the only characters are simple ASCII, but it's 2021. People use emojis, snowmen, and almost every language on the planet needs more than just a to z. If your encoding settings are off, it'll be mangled gobbledygook.
The newer Files API (java.io.File is outdated and you probably don't want to use it anymore) defaults to UTF-8, which is great, saves us some typing.
thus:
public static void main(String[] args) throws IOException {
try (var reader = Files.newBufferedReader(Paths.get(args[0]))) {
Maze maze = new Maze(reader);
}
}

How does this Java method work to read input string?

My Java class is creating a program in which a person thinks of a certain animal within a list of animals, and answers various yes/no questions (such as "Does your animal live on land?" or "Does you animal fly?" etc.) for the computer to determine what animal it is. Everyone in my class was issued a source code to begin working with, and one of the methods within it is obviously designed to read code and I'm not sure how it works exactly, but would like to know how it works to use it in my own programming projects. Any help to know exactly what it does would be greatly appreciated. Thanks!
public static String read()
{
byte[] buffer = new byte[10];
try
{
int numBytes = System.in.read(buffer);
}
catch(IOException e)
{
System.out.print("Error: " + e);
System.exit(1);
}
String str = new String(buffer);
int ball = 5;
return (str);
}
public static String read()
{
byte[] buffer = new byte[10];
Creates an array of ten bytes.
try
Begins a protected portion of code in which some error could happen (exception).
{
int numBytes = System.in.read(buffer);
Reads at most 10 bytes from input.
}
catch(IOException e)
{
In case reading request encounters a condition that makes your reading impossible, execute that block of code.
System.out.print("Error: " + e);
Prints a message.
System.exit(1);
Terminates the execution with indication that something goes wrong.
}
In case reading was ok (no error in try block), control flow ends here.
String str = new String(buffer);
Construct a String with what was read (at most 10 bytes).
int ball = 5;
Does nothing interesting here, except initializing a variable that is never used.
return (str);
Returns the constructed value (what was read on input as a String) to the caller of that method.
}

UVa online judge #458 time limit exceeded

I am trying to solve UVa problem 458 - decoder and I came up with the following algorithm which gives me the correct output for the sample input data, but runs longer than allowed.
public class Decoder {
public void decoder() {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
String line = sc.nextLine();
for (int i = 0; i < line.length(); i++) {
if(line.charAt(i)>=32 && line.charAt(i)<=126)
System.out.print((char) (line.charAt(i) - 7));
}
System.out.println();
}
}
}
What I've looked into
Well I have read the forums and most of the solutions were pretty similar, I have been researching if there was a way of avoiding the for loop which is running through the string and printing out the new char. But this loop is inevitable, this algorithm's time complexity is always going to be n^2.
The problem also mentions to only change ASCII printable values, which is why I set the condition to check if its greater than or equal to 32 and 126. According to Wikipedia that is the range of printable values.
http://ideone.com/XkByW9
Avoid decoding the stream to characters. It's ok to use bytes if you only have to support ASCII.
Read and write the data in big chunks to avoid function/system call overhead.
Avoid unnecessary allocations. Currently you are allocating new String for every line.
Do not split the input into lines to avoid bad performance for very small lines.
Example:
public static void main(String[] args) throws IOException {
byte[] buffer = new byte[2048];
while (true) {
int len = System.in.read(buffer);
if (len <= 0) {
break;
}
for (int i = 0; i < len; i++) {
...
}
System.out.write(buffer, 0, len);
}
}
It will process the input as you would normally process a binary file. For every iteration, it will read up to 2048 bytes into a buffer, process them and write them to standard output. Program will end when EOF is reached and read returns -1. 2048 is usually a good buffer size, but you might want to try different sizes and see which one works best.
Never use Scanner for long inputs. The scanner is unbelievably slower than other means of reading input in Java, such as BufferedReader. This UVa problem looks like one with a quite long input.

Why would someone structure a while loop like this?

I'm reading a book on Java, and we're on reading from a channel into a ByteBuffer. I found the way the author was structuring the while loop odd:
try (FileChannel inCh = (FileChannel) Files.newByteChannel(file)) {
ByteBuffer lengthBuf = ByteBuffer.allocate(8);
int strLength = 0;
ByteBuffer[] buffers = { null, ByteBuffer.allocate(8) };
while(true) {
if(inCh.read(lengthBuf) == -1)
break;
lengthBuf.flip();
strLength = (int)lengthBuf.getDouble();
buffers[0] = ByteBuffer.allocate(2*strLength);
if(inCh.read(buffers) == -1) {
System.err.println("EOF found reading ht eprime string.");
break;
}
System.out.printf("String length: %3s String: %-12s Binary Value: %3d%n", strLength,
((ByteBuffer) (buffers[0].flip())).asCharBuffer().toString(),
((ByteBuffer)buffers[1].flip()).getLong());
lengthBuf.clear();
buffers[1].clear();
}
System.out.println("\nEOF reached.");
} catch (IOException e) {
I tried it like this:
while(inCh.read(lengthBuf) != -1) {
and it works the same. Would there be a practical or code clarity reason the author would write it like he did?
It is clear that your version of the loop is semantically identical. However, that's not the only thing to consider.
Notice that further down the while loop there is a second condition that breaks out of the loop. I suspect that this is what has motivated the author to use while (true).
By writing it as while (true) you alert the reader to the fact that there must be one or more breaks inside the while. The reader is going to have to look inside the loop for breaks, and will hopefully find them both.
Written your way, the casual reader might scan the top of the code and assume that the while condition was the only way for the loop to terminate.
Another point to consider is that of symmetry, or balance. As written by the original author, the loop terminations are all of the same form. Namely breaks from within the loop. Your version feels asymmetrical. One termination point in the while test, and a further termination point, of a different nature, inside the loop.
The author has two exit points, one of which prints out an error before exiting the loop. Just makes the code a little more verbose in that case. It can be written in a number of different ways of course.

An alternative to reading input from Java's System.in

I’m working on the UVa Online Judge problem set archive as a way to practice Java, and as a way to practice data structures and algorithms in general.
They give an example input file to submit to the online judge to use as a starting point (it’s the solution to problem 100).
Input from the standard input stream (java.lang.System.in) is required as part of any solution on this site, but I can’t understand the implementation of reading from System.in they give in their example solution. It’s true that the input file could consist of any variation of integers, strings, etc, but every solution program requires reading basic lines of text input from System.in, one line at a time. There has to be a better (simpler and more robust) method of gathering data from the standard input stream in Java than this:
public static String readLn(int maxLg) {
byte lin[] = new byte[maxLg];
int lg = 0, car = -1;
String line = “”;
try {
while (lg < maxLg) {
car = System.in.read();
if ((car < 0) || (car == ‘\n’)) {
break;
}
lin[lg++] += car;
}
} catch (java.io.IOException e) {
return (null);
}
if ((car < 0) && (lg == 0)) {
return (null); // eof
}
return (new String(lin, 0, lg));
}
I’m really surprised by this. It looks like something pulled directly from K&R’s “C Programming Language” (a great book regardless), minus the access level modifer and exception handling, etc. Even though I understand the implementation, it just seems like it was written by a C programmer and bypasses most of Java’s object oriented nature. Isn’t there a better way to do this, using the StringTokenizer class or maybe using the split method of String or the java.util.regex package instead?
You definitely don't have to read one byte at a time (you don't in C either, that's what fgets is for). Depending on what you're doing, you might use BufferedReader or Scanner:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
Scanner sc = new Scanner(System.in);
BufferedReader has a readLine method, while Scanner has a variety of useful methods, including nextLine, nextInt, nextDouble, etc. which handle conversions for you. It also has a regex-based delimiter for reading arbitrary tokens.
One thing to understand about Java is that it has a very clear distinction between binary data (Streams) and character data (Readers and Writers). There are default decoders and encoders (as used above), but you always have the flexibility to choose the encoding.

Categories