什么是在Java中将布尔数组输出到(和输入自)文件的最有效方法?我本来想使用一个字符串,其中每个字符都是't'或'f',然后我想,为什么不节省八倍的空间?
注:实际上我不知道哪种方法更好,我只选择了Peter's,因为我理解它。感谢两位回答者!
注:实际上我不知道哪种方法更好,我只选择了Peter's,因为我理解它。感谢两位回答者!
假设你有一个boolean[]数组
boolean[] ar = {true,false,false,true,false,true,true,true,false,true,false,false,false,true,true};
如果您想将其写入磁盘,而且对于它在内存中的实现方式并不关心。
public static void main(String... args) throws IOException {
boolean[] ar = {true, false, false, true, false, true, true, true, false, true, false, false, false, true, true};
FileOutputStream out = new FileOutputStream("test.dat");
writeBooleans(out, ar);
out.close();
FileInputStream in = new FileInputStream("test.dat");
boolean[] ar2 = new boolean[ar.length];
readBooleans(in, ar2);
in.close();
System.out.println(Arrays.toString(ar));
System.out.println(Arrays.toString(ar2));
System.out.println("The file size was "+new File("test.dat").length()+" bytes.");
}
private static void writeBooleans(OutputStream out, boolean[] ar) throws IOException {
for (int i = 0; i < ar.length; i += 8) {
int b = 0;
for (int j = Math.min(i + 7, ar.length-1); j >= i; j--) {
b = (b << 1) | (ar[j] ? 1 : 0);
}
out.write(b);
}
}
private static void readBooleans(InputStream in, boolean[] ar) throws IOException {
for (int i = 0; i < ar.length; i += 8) {
int b = in.read();
if (b < 0) throw new EOFException();
for (int j = i; j < i + 8 && j < ar.length; j++) {
ar[j] = (b & 1) != 0;
b >>>= 1;
}
}
}
[true, false, false, true, false, true, true, true, false, true, false, false, false, true, true]
[true, false, false, true, false, true, true, true, false, true, false, false, false, true, true]
The file size was 2 bytes.
但是如果我查看文件的实际大小
$ ls -l test.dat
-rw-rw-r-- 1 peter peter 2 2012-02-19 14:04 test.dat
$ du -h test.dat
4.0K test.dat
它说长度为2个字节,但实际使用的磁盘空间却是4 KB。
注意:您花费的1分钟时间价值大约相当于80 MB的SSD(昂贵的磁盘,HDD更多)。因此,如果您认为使用它不能至少节省80 MB,则可能会浪费您的时间。;)
您可以使用BitSet,每个字符都是16位,可以减少16倍的空间。
t
或f
。尽管如此,我仍然认为位掩码的概念是提高空间效率的途径:长度=O(n)+1,其中n是布尔数组的长度。 - user268396BooleanInputStream
留给你作为练习。请注意,文件中的第一个位现在是右侧(MSB)位(在示例中删除Byte.SIZE - 1 -
以获取其他字节顺序,无论您喜欢哪种方式)。只需使用例如DataOutputStream首先将东西的大小写入文件。10K可以适合一个整数。BitSet
来完成这项工作(最终,需要BitSet
的人!)。public final class BooleanOutputStream extends FilterOutputStream {
private int bitIndex;
private byte buffer;
public BooleanOutputStream(final OutputStream out) {
super(out);
}
public void writeBoolean(final boolean value) throws IOException {
buffer ^= (value ? 1 : 0) << (Byte.SIZE - 1 - bitIndex++);
if (bitIndex == Byte.SIZE) {
write(buffer & 0xFF);
buffer = 0;
bitIndex = 0;
}
}
/**
* This is an encoder and does therefore not close the underlying stream.
* Please close underlying stream separately.
*/
public void close() throws IOException {
if (bitIndex != 0) {
out.write(buffer);
buffer = 0;
bitIndex = 0;
}
}
}
public class BooleanInputStream extends FilterInputStream {
private int bitIndex;
private byte buffer;
public BooleanInputStream(final InputStream in) {
super(in);
}
public boolean readBoolean() throws IOException {
if (bitIndex == 0) {
int b = read();
if (b == -1) {
throw new EOFException();
}
buffer = (byte) b;
}
boolean value = (buffer & (1 << (Byte.SIZE - 1 - bitIndex++))) != 0;
if (bitIndex == Byte.SIZE) {
bitIndex = 0;
}
return value;
}
/**
* This is a decoder and therefore does not close the underlying stream.
* Please close underlying stream separately.
*/
public void close() throws IOException {
buffer = 0;
bitIndex = 0;
}
}