Reputation: 53
As part of my Java course, I wrote a "zip" writer and reader - as Huffman algorithm works.
My class extends Reader, and have an object Reader r. In my main method, I have these lines:
input = new BufferedReader(new HuffmanReader(new FileReader("output.hff")));
String str = input.readLine();
It should return the decompressed string I wrote to the file, after decompressing it, of course. But it returns the first line of the file!
My read function:
public int read(char[] cbuf, int off, int len) throws IOException {
//...
r.read(buffer,0,8192)
//does the decompress process
String fnlStr = ... //The final result
cbuf = fnlStr.toCharArray();
//close streams
return cbuf.length;
}
My Debug window shows this:
HuffmanReader.read(char[], int, int) line: 23
BufferedReader.fill() line: not available
BufferedReader.readLine(boolean) line: not available
BufferedReader.readLine() line: not available
Run.main(String[]) line: 23
It calls my read function twice. How can I stop the bufferReader from calling the read function again?
Upvotes: 5
Views: 830
Reputation: 2491
You don't return the data you read from the method like you would usually. Instead, when read
is called, the caller gives you the array cbuf
, which is essentially the address of a chunk of memory, and tells you to write len
char
s into it.
When you do cbuf = fnlStr.toCharArray()
, you're just replacing your local copy of that address with another address, but you're not actually changing the memory you were supposed to write to. You need to either iterate over the array you are given in a for
loop and write to it, or use System.arraycopy
if you have constructed another buffer that contains the result.
E.g., the following read
method will always read "Test\n"
:
public int read(char[] cbuf, int off, int len) throws IOException {
char[] result = "Test\n".toCharArray();
int numRead = Math.min(len, result.length);
System.arraycopy(result, 0, cbuf, off, numRead);
return numRead;
}
Replacing the "Test\n"
literal with your decompressed string should get you started. Of course, you will still have to manage how much of your source you have already consumed.
And as to BufferedReader
calling read
twice: you shouldn't care how often it's called. Simply get the data from your underlying source, write it to cbuf
and return the number of char
s you have written. If there is nothing left to read, return -1
to signal the end of the stream (in which case BufferedReader
will stop calling read
).
As an aside, Reader
is meant to read character streams, while InputStream
is for binary data (it's basically the same thing, just with byte[]
instead of char[]
and without using a charset). Since compressed files are binary, you might want to switch your FileReader
to a FileInputStream
.
I could imagine weird bugs if, for some reason, the charset you encode with isn't the same you decode with. Or less dramatically, you might use more space than you think, if one 16-bit code unit in UTF-16 needs 3 8-bit code units in UTF-8.
Upvotes: 2
Reputation: 90
You are reading only the first line. Change the first part to something like:
input = new BufferedReader(new HuffmanReader(new FileReader("output.hff")));
Arraylist<String> list = new ArrayList<String>();
String line;
while ((line = reader.readLine()) != null) {
list.add(line);
}
And also, to fix that your method is being called twice, make a boolean and set it to true after you have done your things in the method. Then in the beginning of that method, check if that boolean is true. If it is, return from the method so it won't be executing things after it again.
Upvotes: 1