Ete*_*oob 8 java file-io bit-manipulation
要读/写二进制文件,我使用DataInputStream/DataOutputStream,他们有这个方法writeByte()/ readByte(),但我想做的是读/写位?可能吗?
我想用它来进行压缩算法,所以当我压缩时我想写3位(一个数字,文件中有数百万这样的数字),如果我每次写一个字节,我需要写3位,我会写大量的冗余数据......
直接读/写单个位是不可能的,您可以读/写的最小单位是一个字节.
你可以使用标准的按位运算符来操作一个字节,所以例如要获得一个字节的最低2位,你可以做
byte b = in.readByte();
byte lowBits = b&0x3;
Run Code Online (Sandbox Code Playgroud)
将低4位设置为1,并写入字节:
b |= 0xf;
out.writeByte(b);
Run Code Online (Sandbox Code Playgroud)
(注意,为了提高效率,您可能希望读/写字节数组而不是单字节)
没有办法直接做到.计算机可以处理的最小单位是一个字节(甚至布尔值占用一个字节).但是,您可以创建一个自定义流类,该类使用您想要的位打包一个字节然后写入它.然后你可以为这个类创建一个包装器,它的写函数采用一些整数类型,检查它是否在0到7之间(或-4和3 ......或者其他),以与BitInputStream类相同的方式提取位(如下)做,并对BitOutputStream的write方法进行相应的调用.您可能认为您可以只生成一组IO流类,但3不会均匀地进入8.因此,如果您想要最佳的存储效率并且您不想真正努力工作,那么您就会陷入两层抽象的困境.下面是一个BitOutputStream类,一个相应的BitInputStream类,以及一个确保它们工作的程序.
import java.io.IOException;
import java.io.OutputStream;
class BitOutputStream {
private OutputStream out;
private boolean[] buffer = new boolean[8];
private int count = 0;
public BitOutputStream(OutputStream out) {
this.out = out;
}
public void write(boolean x) throws IOException {
this.count++;
this.buffer[8-this.count] = x;
if (this.count == 8){
int num = 0;
for (int index = 0; index < 8; index++){
num = 2*num + (this.buffer[index] ? 1 : 0);
}
this.out.write(num - 128);
this.count = 0;
}
}
public void close() throws IOException {
int num = 0;
for (int index = 0; index < 8; index++){
num = 2*num + (this.buffer[index] ? 1 : 0);
}
this.out.write(num - 128);
this.out.close();
}
}
Run Code Online (Sandbox Code Playgroud)
我确信有一种方法可以用逐位运算符打包int,从而避免不得不反转输入,但我不认为这很难.
此外,您可能会注意到,有检测到最后一位在此实现读取本地没有办法,但我真的不想觉得这很难.
import java.io.IOException;
import java.io.InputStream;
class BitInputStream {
private InputStream in;
private int num = 0;
private int count = 8;
public BitInputStream(InputStream in) {
this.in = in;
}
public boolean read() throws IOException {
if (this.count == 8){
this.num = this.in.read() + 128;
this.count = 0;
}
boolean x = (num%2 == 1);
num /= 2;
this.count++;
return x;
}
public void close() throws IOException {
this.in.close();
}
}
Run Code Online (Sandbox Code Playgroud)
您可能知道这一点,但是您应该在BitStream和FileStream之间放置一个BufferedStream,否则它将永远消失.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
class Test {
private static final int n = 1000000;
public static void main(String[] args) throws IOException {
Random random = new Random();
//Generate array
long startTime = System.nanoTime();
boolean[] outputArray = new boolean[n];
for (int index = 0; index < n; index++){
outputArray[index] = random.nextBoolean();
}
System.out.println("Array generated in " + (double)(System.nanoTime() - startTime)/1000/1000/1000 + " seconds.");
//Write to file
startTime = System.nanoTime();
BitOutputStream fout = new BitOutputStream(new BufferedOutputStream(new FileOutputStream("booleans.bin")));
for (int index = 0; index < n; index++){
fout.write(outputArray[index]);
}
fout.close();
System.out.println("Array written to file in " + (double)(System.nanoTime() - startTime)/1000/1000/1000 + " seconds.");
//Read from file
startTime = System.nanoTime();
BitInputStream fin = new BitInputStream(new BufferedInputStream(new FileInputStream("booleans.bin")));
boolean[] inputArray = new boolean[n];
for (int index = 0; index < n; index++){
inputArray[index] = fin.read();
}
fin.close();
System.out.println("Array read from file in " + (double)(System.nanoTime() - startTime)/1000/1000/1000 + " seconds.");
//Delete file
new File("booleans.bin").delete();
//Check equality
boolean equal = true;
for (int index = 0; index < n; index++){
if (outputArray[index] != inputArray[index]){
equal = false;
break;
}
}
System.out.println("Input " + (equal ? "equals " : "doesn't equal ") + "output.");
}
}
Run Code Online (Sandbox Code Playgroud)
请查看我的 bit-io 库https://github.com/jinahya/bit-io,它可以读取和写入非八位字节对齐的值,例如 1 位布尔值或 17 位无符号整数。
<dependency>
<!-- resides in central repo -->
<groupId>com.googlecode.jinahya</groupId>
<artifactId>bit-io</artifactId>
<version>1.0-alpha-13</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
该库读取和写入任意长度的位。
final InputStream stream;
final BitInput input = new BitInput(new BitInput.StreamInput(stream));
final int b = input.readBoolean(); // reads a 1-bit boolean value
final int i = input.readUnsignedInt(3); // reads a 3-bit unsigned int
final long l = input.readLong(47); // reads a 47-bit signed long
input.align(1); // 8-bit byte align; padding
final WritableByteChannel channel;
final BitOutput output = new BitOutput(new BitOutput.ChannelOutput(channel));
output.writeBoolean(true); // writes a 1-bit boolean value
output.writeInt(17, 0x00); // writes a 17-bit signed int
output.writeUnsignedLong(54, 0x00L); // writes a 54-bit unsigned long
output.align(4); // 32-bit byte align; discarding
Run Code Online (Sandbox Code Playgroud)