我是编程新手,我尝试使用这种方法进行压缩,我已经具有正确的0和1序列,我需要一点一点地编写它,所以我使用的是一个称为BitOutputStream和BitInputStream的类来编写它(我没有这样做),问题是我从已写入的文件中读取的内容与我所拥有的序列不同,这是我以前编写的代码:
public void writeCompressed() throws IOException{
BitOutputStream fop2 = new BitOutputStream(
new ObjectOutputStream(
new FileOutputStream(
"C:\\Users\\David\\Documents\\davidCompress.dabc")));
for (int i = 0; i < secuenciaFinal.length(); i++) {
if (secuenciaFinal.charAt(i) == '1') {
fop2.write1Bit();//lee la cadena y si contiene 1 escribe in 1 bit en mi archivo1
} else if (secuenciaFinal.charAt(i) == '0') {
fop2.write0Bit();//si la cadena contiene 0 bits escribe 0 bits
} else {
//fop2.missingBits();
}
}
fop2.close();
}
其中“ secuenciaFinal”是我要保存的序列,但是当我阅读它时,我得到了一个完全不同的序列:
public void writeDecompressed(String path) throws IOException{
InputStream is = new FileInputStream(path);
BitInputStream bis = new BitInputStream(is);
String textBits = "", OriginalText ="";
while(bis.available()>0)
textBits += bis.readBit() +"";
TreeNode node = root;
for (int i = 0; i < textBits.length(); i++) {
if(!node.isLeaf()){
if(Integer.parseInt(textBits.charAt(i)+"") == 0)
{node = node.getleftSon();}
else if(Integer.parseInt(textBits.charAt(i)+"") == 1)
{node = node.getrightSon();}
else
System.out.println("No se encontró 1 ni 0");
}else{
OriginalText += node.getData();
node = root;
}
}
bis.close();
}
我已经在这个问题上停留了几个小时,不知道该怎么办,我做错了吗?还是BitOutputStream和BitInputStream类出现故障?
提前致谢。
好了,这些类很大,所以我不得不删除所有注释,以免在这里的BitInputStream造成混乱:
public class BitInputStream extends InputStream {
private static final int DEFAULT_BUFFER_SIZE = 4096;
private byte[] buf;
private int bufSize;
private int pos;
private int bits;
private int bitSize;
private int unreadSize;
private InputStream in;
private boolean fillByteBuffer() throws IOException {
if (in == null) {
throw new IOException("The stream is closed!");
}
if ((bufSize = in.read(buf, 0, buf.length)) == -1) {
pos = -1;
unreadSize = 0;
return false;
}
pos = 0;
return true;
}
public BitInputStream(InputStream in, int size) {
if (in == null) {
throw new NullPointerException("The stream in is null");
}
if (size <= 0) {
throw new IllegalArgumentException("A buffer size of " + size
+ " is illegal!");
}
buf = new byte[size];
this.in = in;
}
public BitInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
public BitInputStream(String fileName, int size) throws FileNotFoundException {
this(new FileInputStream(fileName), size);
}
public BitInputStream(String fileName) throws FileNotFoundException {
this(new FileInputStream(fileName));
}
public static BitInputStream fromFile(String fileName)
throws FileNotFoundException {
return new BitInputStream(new FileInputStream(fileName));
}
public static BitInputStream fromByteArray(byte[] b) {
if (b == null) {
throw new NullPointerException("The byte array b is null!");
}
int size = DEFAULT_BUFFER_SIZE;
if (b.length < size) {
size = b.length;
}
return new BitInputStream(new ByteArrayInputStream(b), size);
}
@Override
public int available() throws IOException {
if (in == null) {
throw new IOException("The stream is closed!");
}
return bitSize + 8 * (bufSize - pos + in.available());
}
@Override
public int read() throws IOException {
unreadSize = 8; // the maximal number of bits to be unread
if (bitSize < 8) // the bit buffer needs more bits
{
if (pos >= bufSize) // does the byte array need a refill?
{
if (fillByteBuffer() == false) {
return -1;
}
}
bits <<= 8; // makes room for 8 new bits
bits |= (buf[pos++] & 0xff); // a byte (8 bits) is added
return (bits >> bitSize) & 0xff; // 8 bits are returned
} // end of if (bitSize < 8)
bitSize -= 8;
return (bits >> bitSize) & 0xff; // 8 bits are returned
}
public int readBit() throws IOException {
unreadSize = 1;
if (bitSize <= 0) // the bit buffer is empty
{
if (pos >= bufSize) // does the byte array need a refill?
{
if (fillByteBuffer() == false) {
return -1;
}
}
bits = (buf[pos++] & 0xff); // 8 bits are added
bitSize = 8; // bitSize is updated
} // if (bitSize <= 0)
bitSize--;
return (bits >> bitSize) & 1;
}
public int readBits(int numberOfBits) throws IOException {
if (numberOfBits < 0) {
throw new IllegalArgumentException("Cannot read " + numberOfBits
+ " bits!");
}
// / 1. numberOfBits <= 25, the most common case /////////
if (numberOfBits <= 25) {
while (bitSize < numberOfBits) // will not create overflow
{
if (pos >= bufSize) // does the byte array need a refill?
{
if (fillByteBuffer() == false) {
return -1;
}
}
bits <<= 8; // makes room for 8 new bits
bits |= (buf[pos++] & 0xff); // a byte (8 bits) is added
bitSize += 8; // bitSize is updated
} // end while
bitSize -= numberOfBits; // bitSize is updated
unreadSize = numberOfBits; // unreadSize is updated
return (bits >> bitSize) & ~(-1 << numberOfBits);
}
// / 2. numberOfBits > 25 /////////////////////
while (bitSize < 25) // will not create overflow
{
if (pos >= bufSize) // does the byte array need a refill?
{
if (fillByteBuffer() == false) {
return -1;
}
}
bits <<= 8; // makes room for 8 new bits
bits |= (buf[pos++] & 0xff); // a byte (8 bits) is added
bitSize += 8; // bitSize is updated
} // end while
// / 3. numberOfBits < bitSize /////////////////////
if (numberOfBits < bitSize) // enough bits in the buffer!
{
bitSize -= numberOfBits; // bitSize is updated
unreadSize = numberOfBits; // unreadSize is updated
return (bits >> bitSize) & ~(-1 << numberOfBits);
}
// / 4. numberOfBits == bitSize /////////////////////
if (numberOfBits == bitSize) {
// To continue we need to be sure that numberOfBits is not
// out of range, i.e. not equal to 32 or greater.
if (numberOfBits > 31) {
throw new IllegalArgumentException("Cannot read " + numberOfBits
+ " bits!");
}
bitSize = 0; // bitSize is updated
unreadSize = numberOfBits; // unreadSize is updated
return bits & ~(-1 << numberOfBits);
}
// / 5. numberOfBits > bitSize /////////////////////
int copy = bits & ~(-1 << bitSize); // a bit buffer copy
if (pos >= bufSize) // does the byte array need a refill?
{
if (fillByteBuffer() == false) {
return -1;
}
}
bits <<= 8; // makes room for 8 new bits
bits |= (buf[pos++] & 0xff); // a byte (8 bits) is added
int diff = numberOfBits - bitSize;
bitSize = 8 - diff; // bitSize is updated
unreadSize = diff + 24; // unreadSize is updated
return (copy << diff) | ((bits >> bitSize) & ~(-1 << diff));
}
public int skip() throws IOException {
unreadSize = 0; // no unread subsequent to a skip
if (bitSize < 8) // more bits to the bit buffer
{
if (pos >= bufSize) // does the byte array need a refill?
{
if (fillByteBuffer() == false) {
int skipSize = bitSize;
bitSize = 0;
return skipSize; // equal to the number of bits skipped
}
}
bits <<= 8; // make room for 8 bits
bits |= (buf[pos++] & 0xff); // a byte (8 bits) is added
return 8; // 8 bits are skipped
} // end of if (bitSize < 8)
bitSize -= 8;
return 8; // 8 bits are skipped
}
@Override
public long skip(long n) throws IOException {
throw new UnsupportedOperationException();
}
public void unreadBit() throws IOException {
if (in == null) {
throw new IOException("The stream is closed!");
}
if (unreadSize <= 0) {
throw new IllegalStateException("No bits to unread!");
}
unreadSize--;
bitSize++;
}
public void unreadBits() throws IOException {
if (in == null) {
throw new IOException("The stream is closed!");
}
bitSize += unreadSize;
unreadSize = 0;
}
public void unreadBits(int numberOfBits) throws IOException {
if (in == null) {
throw new IOException("The stream is closed!");
}
if (numberOfBits < 0 || numberOfBits > unreadSize) {
throw new IllegalArgumentException("Illegal number of bits!");
}
unreadSize -= numberOfBits;
bitSize += numberOfBits;
}
public int unreadSize() throws IOException {
if (in == null) {
throw new IOException("The stream is closed!");
}
return unreadSize;
}
public void insertBit(int bit) throws IOException {
if (in == null) {
throw new IOException("The stream is closed!");
}
if (bitSize == 32) {
throw new IllegalStateException("No bits can be inserted!");
}
bits = ((bits & (-1 << bitSize)) << 1) | ((bit & 1) << bitSize)
| (bits & ((1 << bitSize) - 1));
if (unreadSize > 0) {
unreadSize--;
}
bitSize++;
}
public void insert0Bit() throws IOException {
if (in == null) {
throw new IOException("The stream is closed!");
}
if (bitSize == 32) {
throw new IllegalStateException("No bits can be inserted!");
}
bits = ((bits & (-1 << bitSize)) << 1) | (bits & ((1 << bitSize) - 1));
if (unreadSize > 0) {
unreadSize--;
}
bitSize++;
}
public void insert1Bit() throws IOException {
if (in == null) {
throw new IOException("The stream is closed!");
}
if (bitSize == 32) {
throw new IllegalStateException("No bits can be inserted!");
}
bits = ((bits & (-1 << bitSize)) << 1) | (1 << bitSize)
| (bits & ((1 << bitSize) - 1));
if (unreadSize > 0) {
unreadSize--;
}
bitSize++;
}
public void insertBits(int value, int numberOfBits) throws IOException {
if (in == null) {
throw new IOException("The stream is closed!");
}
if (numberOfBits < 0 || numberOfBits > insertSize()) {
throw new IllegalArgumentException("numberOfBits too large!");
}
if (numberOfBits == 32) // bitSize = 0
{
bits = value;
} else {
bits = (bits & ((1 << bitSize) - 1))
| ((bits & (~((1 << bitSize) - 1))) << numberOfBits)
| ((value & ((1 << numberOfBits) - 1)) << bitSize);
}
unreadSize -= numberOfBits;
if (unreadSize < 0) {
unreadSize = 0;
}
bitSize += numberOfBits;
}
public int insertSize() throws IOException {
if (in == null) {
throw new IOException("The stream is closed!");
}
return 32 - bitSize;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
if (in != null) {
close();
}
}
@Override
public void close() throws IOException {
// a second call to close will have no effect
if (in == null) {
return;
}
in.close();
in = null;
buf = null;
pos = -1;
bufSize = -1;
bitSize = -1;
}
}
这是BitOutputStream:
public class BitOutputStream extends OutputStream {
private static final int DEFAULT_BUFFER_SIZE = 4096;
private byte buf[];
private int bufSize;
private int pos;
private int bits;
private int bitSize;
private OutputStream out;
public BitOutputStream(OutputStream out, int size) {
if (out == null) {
throw new NullPointerException("The stream out is null");
}
if (size <= 0) {
throw new IllegalArgumentException("The size(" + size + ") <= 0");
}
buf = new byte[bufSize = size];
this.out = out;
}
public BitOutputStream(OutputStream out) {
this(out, DEFAULT_BUFFER_SIZE);
}
public BitOutputStream(String fileName, int size)
throws FileNotFoundException {
this(new FileOutputStream(fileName), size);
}
public BitOutputStream(String fileName) throws FileNotFoundException {
this(new FileOutputStream(fileName), DEFAULT_BUFFER_SIZE);
}
public static BitOutputStream toFile(String fileName)
throws FileNotFoundException {
return new BitOutputStream(new FileOutputStream(fileName));
}
public static BitOutputStream toFile(String fileName, boolean append)
throws FileNotFoundException {
return new BitOutputStream(new FileOutputStream(fileName, append));
}
private void flushBuffer() throws IOException {
if (out == null) {
throw new IOException("The stream is closed!");
}
if (pos > 0) {
out.write(buf, 0, pos);
pos = 0;
}
} // end flushBuffer
public void writeBit(int bit) throws IOException {
bits <<= 1; // a bit can now be added
bits |= (bit & 1); // the last bit of the parameter bit is added
bitSize++; // bitSize is updated
if (bitSize >= 8) // a byte can be moved to the byte buffer
{
bitSize = 0;
// the byte buffer is flushed if it is full
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) bits; // a byte is moved
}
} // end writeBit
public void write0Bit() throws IOException {
bits <<= 1; // adds a 0-bit
bitSize++; // bitSize is updated
if (bitSize >= 8) // a byte can be moved to the byte buffer
{
bitSize = 0;
// the byte buffer is flushed if it is full
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) bits; // a byte is moved
}
} // end write0Bit
public void write1Bit() throws IOException {
bits <<= 1; // a bit can now be added
bits |= 1; // adds a 1-bit
bitSize++; // bitSize is updated
if (bitSize >= 8) // a byte can be moved to the byte buffer
{
bitSize = 0;
// the byte buffer is flushed if it is full
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) bits; // a byte is moved
}
} // end write1Bit
@Override
public void write(int b) throws IOException {
bits <<= 8; // 8 bits can now be added
bits |= (b & 0xff); // adds the 8 rightmost bits of b
// the byte buffer is flushed if it is full
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize); // a byte is moved
} // end write
public void writeBits(int value, int numberOfBits) throws IOException {
if (numberOfBits < 0) {
throw new IllegalArgumentException("Cannot write " + numberOfBits
+ " bits!");
}
if (numberOfBits <= 25) // the most common case
{
bits <<= numberOfBits; // will not create overflow
bits |= (value & ((1 << numberOfBits) - 1)); // the bits are added
bitSize += numberOfBits; // the bitsize is updated
while (bitSize >= 8) {
bitSize -= 8;
// the byte buffer is flushed if it is full
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize); // a byte is moved
}
} else if (numberOfBits <= 32) {
int k = numberOfBits - 25; // 1 <= k <= 7
bits <<= 25; // 25 bits can now be added
bits |= (value >> k) & 0x1ffffff; // 25 bits are added
bitSize += 25; // bitSize is updated
// the bit buffer contains at least 25 bits,
// 24 of them are moved to the byte buffer
bitSize -= 8;
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize);
bitSize -= 8;
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize);
bitSize -= 8;
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize);
bits <<= k; // k bits can now be added
bits |= (value & ((1 << k) - 1)); // the rightmost k bits of value
bitSize += k; // bitSize is updated
if (bitSize >= 8) // 2 <= bitSize <= 15
{
bitSize -= 8;
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize); // a byte is moved
}
} else {
throw new IllegalArgumentException("Cannot write " + numberOfBits
+ " bits!");
}
} // end writeBits
public void writeBits(int value) throws IOException {
// must find the number of significant bits of value
int signifcantBits = 31, v = value;
if (v >>> 16 == 0) {
signifcantBits -= 16;
v <<= 16;
}
if (v >>> 24 == 0) {
signifcantBits -= 8;
v <<= 8;
}
if (v >>> 28 == 0) {
signifcantBits -= 4;
v <<= 4;
}
if (v >>> 30 == 0) {
signifcantBits -= 2;
v <<= 2;
}
signifcantBits += v >>> 31;
bitSize += signifcantBits;
if (bitSize <= 32) {
bits <<= signifcantBits; // will not create overflow
bits |= value; // the signifcantBits are added
while (bitSize >= 8) {
bitSize -= 8;
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize);
}
} else {
int k = bitSize - 32;
bits <<= signifcantBits - k;
bits |= value >>> k;
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> 24);
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> 16);
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> 8);
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) bits;
bits = value;
bitSize = k;
}
} // end writeBits
public void writeLeftBits(int value, int numberOfBits) throws IOException {
if (numberOfBits < 0) {
throw new IllegalArgumentException("Cannot write a negative ("
+ numberOfBits + ") number of bits!");
}
if (numberOfBits <= 25) // the most common case
{
bits <<= numberOfBits; // will not create overflow
bits |= (value >>> (32 - numberOfBits)); // the bits are added
bitSize += numberOfBits; // the bitsize is updated
while (bitSize >= 8) {
bitSize -= 8;
// the byte buffer is flushed if it is full
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize); // a byte is moved
}
} else if (numberOfBits <= 32) {
bits <<= 25; // 25 bits can now be added
bits |= (value >>> 7); // 25 bits are added
bitSize += 25; // bitSize is updated
// the bit buffer contains at least 25 bits,
// 24 of them are moved to the byte buffer
bitSize -= 8;
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize);
bitSize -= 8;
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize);
bitSize -= 8;
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize);
int k = numberOfBits - 25; // 1 <= k <= 7
bits <<= k; // the missing k bits can now be added
bits |= ((value >>> (32 - numberOfBits)) & ((1 << k) - 1));
bitSize += k; // bitSize is updated
if (bitSize >= 8) // 2 <= bitSize <= 15
{
bitSize -= 8;
if (pos >= bufSize) {
flushBuffer();
}
buf[pos++] = (byte) (bits >> bitSize); // a byte is moved
}
} else {
throw new IllegalArgumentException("Cannot write " + numberOfBits
+ " bits!");
}
} // end writeBits
public void writeLeftBits(int value) throws IOException {
writeLeftBits(value, 32 - Integer.numberOfTrailingZeros(value));
} // end writeBits
@Override
public void flush() throws IOException {
if (bitSize > 0) {
// the byte buffer is written to the ouput stream if it is full
if (pos >= bufSize) {
flushBuffer();
}
// 0-bits are added to create a full byte
buf[pos++] = (byte) (bits <<= (8 - bitSize));
bitSize = 0;
}
flushBuffer();
out.flush();
} // end flush()
public int missingBits() throws IOException {
if (out == null) {
throw new IOException("The stream is closed!");
}
return bitSize == 0 ? 0 : 8 - bitSize;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
if (out != null) {
close();
}
}
@Override
public void close() throws IOException {
// a second call to close will have no effect
if (out == null) {
return;
}
flush();
out.close();
out = null;
buf = null;
pos = bufSize = -1;
bitSize = 8;
} // end close()
public static String toBitString(byte[] b) {
StringBuilder s = new StringBuilder();
String[] fourBits = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
for (int c : b) {
s.append(fourBits[(c & 255) >> 4]);
s.append(fourBits[c & 15]);
s.append(' ');
}
return s.toString();
}
} // end class BitOutputStream
最佳答案
我发现此https://github.com/nayuki/Huffman-Coding/tree/master/src/nayuki/huffmancoding与您的霍夫曼编码有关。这可能很有用。
如果可以提供您的BitInputStream / BitOutputStream类,我认为您的问题在那里,那么可以根据您的代码提出更好的答案。