Read multiple lines from InputStreamReader (JAVA) - java

I have an InputStreamReader object. I want to read multiple lines into a buffer/array using one function call (without crating a mass of string objects). Is there a simple way to do so?

First of all mind that InputStreamReader is not so efficient, you should wrap it around a BufferedReader object for maximum performance.
Taken into account this you can do something like this:
public String readLines(InputStreamReader in)
{
BufferedReader br = new BufferedReader(in);
// you should estimate buffer size
StringBuffer sb = new StringBuffer(5000);
try
{
int linesPerRead = 100;
for (int i = 0; i < linesPerRead; ++i)
{
sb.append(br.readLine());
// placing newlines back because readLine() removes them
sb.append('\n');
}
}
catch (Exception e)
{
e.printStackTrace();
}
return sb.toString();
}
Mind that readLine() returns null is EOF is reached, so you should check and take care of it.

If you have some delimiter for multiple lines you can read that many characters using read method with length and offset. Otherwise using a StringBuilder for appending each line read by BufferedReader should work well for you without eating up too much temp memory

Related

Faster input style in java

Scanner has a method hasNext() but if i want to use BufferedReader insteadOf Scanner how to handle hasNext() types of method in BufferedReader?
I want to do this because BufferedReader is faster than Scanner. Is there any faster input reading way besides BufferedReader?
Need Help! Thanks in advance.
If you are working with Strings use a StringBuilder. It is a built in object in Java and allows you to not have to recreate a String every time you append a String.
I have not worked with a scanner much because I like BufferedReader so much. Java's BufferedReader reads a certain amount of bytes at a time. The default buffer size is 8192 characters. You can change this is you want to if you think you will be reading enormous amounts of characters. An integer as the second parameter would specify the number of bytes to read each time.
This is how you would use a BufferedReader and StringBuilder efficiently:
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
String output;
try(BufferedReader reader = new BufferedReader(new FileReader(System.getProperty("user.home") + "/Desktop/lotsOfText.txt"), 8192)) { //if you want a bigger buffer - give it a larger number
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n"); //StringBuilder returns a reference to itself
}
} catch (IOException io) {
System.err.println(io.toString());
}
output = sb.toString();
System.out.println(output);
}
If you are expecting double or ints, you can use a try{}catch (Exception e){} and in the try use either java's class Double or Integer to parse a string:
try {
double d = Double.parse(line);
int i = Integer.parse(line);
catch (NumberFormatException nfe) {
System.err.println(nfe.toString() + "\n\nThe number was unreadable");
}
Your question was really vague, so it is hard to give you an explicit answer. I hope this helps.
Also, as a note, BufferedReader also accepts an InputStreamReader as an argument, so you could have
try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)) {} catch...
in order to read user input.
The "truly" correct way to read an InputStream can be found here

ReadLine - execute twice?

I need to be able to read each line of the file for multiple arguments, hence the for loop. After the first one, it does not seem to be reading them anymore, seems to skip the try statement. Any ideas? I'm sure Its something silly I am missing but have been playing about with it and unfortunately time is not on my side.
for (int j = 0; j < ags.length; j++){
try{
String nameFromFile = null;
BufferedReader InputReader = new BufferedReader(new InputStreamReader(System.in));
while ((nameFromFile = InputReader.readLine()) != null) {
// Do stuff
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
You appear to have two sources you want to compare System.in and args I suggest you read these individually and then compare them.
Set<String> fromInt = new HashSet<>();
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
for(String line; (line = br.readLine()) != null;)
fromIn.add(normalise(line));
}
// compare argsList with fromIn.
e.g.
for(String arg: args) {
if (fromIn.contains(normalise(arg))) {
// something
} else {
// something else
}
}
I need to be able to read each line of the file
What file? You're reading from System.in:
BufferedReader InputReader = new BufferedReader(new InputStreamReader(System.in));
Your code will block at this line until you enter something at the console.
You do not read a file, bu the System.in stream.
Every stream has an internal pointer, so the stream nows, which line was read at last.
If the System stream was read once, the pointer is pointing to the end of the stream.
As long as the stream is not reset, the read command will not return anything.
try
InputStream.reset()
or even better, only read the Stream once and cache the result! This is faster and safe, because the Stream input can change during iteration.
Your code will never exit from while loop.
while ((nameFromFile = InputReader.readLine()) != null)
In above loop it will print only one time and at the end of the file it will not be out of the while loop . That's why you are getting only one time output. Since it is not exited from while loop it does not go back into for loop. readLine() return the string and it is terminated by "\n" or "\r\n". Change as below and you will be able to read as ags.length
while ((nameFromFile = InputReader.readLine())=="\n")

GZIP eats newlines

I have the following code for compressing and decompressing string.
public static byte[] compress(String str)
{
try
{
ByteArrayOutputStream obj = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(obj);
gzip.write(str.getBytes("UTF-8"));
gzip.close();
return obj.toByteArray();
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
public static String decompress(byte[] bytes)
{
try
{
GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(bytes));
BufferedReader bf = new BufferedReader(new InputStreamReader(gis, "UTF-8"));
StringBuilder outStr = new StringBuilder();
String line;
while ((line = bf.readLine()) != null)
{
outStr.append(line);
}
return outStr.toString();
}
catch (IOException e)
{
return e.getMessage();
}
}
I compress into byte array on windows, and then send the byte array through socket to the linux and uncompress it there. However upon uncompression it seem that all my newline characters are gone.
So I thought that the problem was linux to windows relationship. However I have tried writing a simple program on windows that uses it, and found that the newlines are still gone.
Can anyone shed any light as to what causes it? I can't figure out any explanation.
I think the problem is here:
while ((line = bf.readLine()) != null)
{
outStr.append(line);
}
The readLine see's the newline char but doesn't include it in the returned value for line
The problem is worse than you think, perhaps.
readLine() gets all the characters up to, but not including, a newline (or some variety of returns and linefeed characters) OR the end of file. So you don't know if the last line you get had a newline on the end or not.
This might not matter, and if so, you can just add this following the other append:
outStr.append('\n');
Some files might end up with an extra line ending at the end of file.
If it does matter, you will need to use read() and then output all the characters you receive. In that case, you might end up with the infamous "What's at the end of the line?" problem you allude to between Windows, Linux and the MacOS and the way they use different combinations of return and new-line characters to end lines.
It is not GZIP that is "eating" newlines.
It is this code:
while ((line = bf.readLine()) != null)
{
outStr.append(line);
}
The readLine() method reads a line (up to and including a line termination sequence) and then returns it without a newline. You then append it to outStr ... without replacing the line termination that was stripped.
But even if you replaced the line termination, you can't guarantee to preserve the actual line termination sequence that was used ... if you do it that way.
I recommend that you replace the readLine() calls with read() calls; i.e. read and then buffer the data one character at a time. It solves two problems at once. It may even be faster, because you are avoiding the unnecessary overhead of assembling line Strings.

Reading every 10 lines using a BufferedReader

Is there a way of reading, say, every 10 lines from a .txt file using a BufferedReader? At the moment my BufferedReader is reading every line, splitting the different values and storing them in an array list; which is then used elsewhere in my program.
Use LineNumberReader which is intended for this very purpose:
LineNumberReader reader = new LineNumberReader(fileReader);
ArrayList<String> goodLines = new ArrayList<String>();
String line = null;
while ((line = reader.readLine()) != null) {
if ((reader.getLineNumber()+1) % 10 == 0) {
goodLines.add(line);
}
}
Use a loop to read all the lines you don't want, then read the line you do want.
BufferedReader br = new BufferedReader(new FileReader(file));
int index = 10;
while (lineNumber < index - 1)
{
lineNumber++;
br.readLine();
}
String lineYouWant = br.readLine();
if (lineYouWant.isEmpty()) br.close();
// Do stuff with lineYouWant
br.close();
Since all of your lines are the same size you could look at the skip() method in the BufferedReader. You would basically read a line and then skip 10 * lineSize and read the next line, etc...
The purpose of a buffered reader is to make reading logical units like lines easy. Reading multiple lines would complicate your code and not provide a great performance boost since the buffered reader is already reading large blocks of data into its buffer.
Edit: Since your records are fixed size you could use a lower level reader and just read the amount of bytes required.

Filereader null declarations and appending best practice

I want to optimise my file reader function but am not sure if it is best practice to declare the nulls outside of the try loop. Also, is looping and appending chars to a Stringbuffer considered bad practice? I would like to use the exception handling here, but maybe it is better to use another structure? any advice most welcome, thanks.
public String readFile(){
File f = null;
FileReader fr = null;
StringBuffer content = null;
try{
f = new File("c:/test.txt");
fr = new FileReader(f);
int c;
while((c = fr.read()) != -1){
if(content == null){
content = new StringBuffer();
}
content.append((char)c);
}
fr.close();
}
catch (Exception e) {
throw new RuntimeException("An error occured reading your file");
}
return content.toString();
}
}
Advice:
Indent your code properly. The stuff in your question looks like a dog's breakfast.
You don't need to initialize f inside the try / catch block. The constructor can't throw an Exception the way you are using it.
In fact, you don't need to declare it at all. Just inline the new File(...).
In fact, you don't even need to do that. Use the FileReader(String) constructor.
There's no point initializing the StringBuffer inside the loop. The potential performance benefit is small and only applies in the edge-case where the file is empty or doesn't exist. In all other cases, this is an anti-optimization.
Don't catch Exception. Catch the exceptions that you expect to be thrown and allow all other exceptions to propagate. The unexpected exceptions are going to be due to bugs in your program, and need to be handled differently from others.
When you catch an exception, don't throw away the evidence. For an unexpected exception, either print / log the exception, its message and its stacktrace, or pass it as the 'cause' of the exception that you throw.
The FileReader should be closed in a finally clause. In your version of the code, the FileReader won't be closed if there is an exception after the object has been created and before the close() call. That will result in a leaked file descriptor and could cause problems later in your application.
Better yet, use the new Java 7 "try with resource" syntax which takes care of closing the "resource" automatically (see below).
You are reading from the file one character at a time. This is very inefficient. You need to either wrap the Reader in a BufferedReader, or read a large number of characters at a time using (for example) read(char[], int, int)
Use StringBuilder rather than StringBuffer ... unless you need a thread-safe string assembler.
Wrapping exceptions in RuntimeException is bad practice. It makes it difficult for the caller to handle specific exceptions ... if it needs to ... and even makes printing of a decent diagnostic more difficult. (And that assumes that you didn't throw away the original exception like your code does.)
Note: if you follow the advice of point 8 and not 9, you will find that the initialization of fr to null is necessary if you open the file in the try block.
Here's how I'd write this:
public String readFile() throws IOException {
// Using the Java 7 "try with resource syntax".
try (FileReader fr = new FileReader("c:/test.txt")) {
BufferedReader br = new BufferedReader(fr);
StringBuilder content = new StringBuilder();
int c;
while ((c = br.read()) != -1) {
content.append((char)c);
}
return content.toString();
}
}
A further optimization would be to use File.length() to find out what the file size (in bytes) is and use that as the initial size of the StringBuilder. However, if the files are typically small this is likely to make the application slower.
public String readFile() {
File f = new File("/Users/Guest/Documents/workspace/Project/src/test.txt");
FileReader fr = null;
BufferedReader br = null;
StringBuilder content = new StringBuilder();;
try {
fr = new FileReader(f);
br = new BufferedReader(fr);
//int c;
//while ((c = fr.read()) != -1) {
//content.append((char) c);
//}
String line = null;
while((line = br.readLine()) != null) {
content.append(line);
}
fr.close();
br.close();
} catch (Exception e) {
// do something
}
return content.toString();
}
Use buffered reader and youll get 70%+ improvement, use string builder instead of string buffer unless you need syncronization.
ran it on a 10MB file 50 times and averaged
no need to put anything that does not need exception handling inside try
no need for that if clause because it will be true only once and so you're wasting time - checking it for every character
there is no runtime exceptions to throw.
results:
fastest combination to slowest:
string builder and buffered reader line by line: 211 ms
string buffer and buffered reader line by line: 213 ms
string builder and buffered reader char by char: 348 ms
string buffer and buffered reader char by char: 372 ms
string builder and file reader char by char: 878
string buffer and file reader char by char: 935 ms
string: extremely slow
so use string builder + buffered reader and make it read line by line for best results.

Categories

Resources