我对位级读取和写入/从文件写起来都不是新鲜事。
我想在位级精度读取和写入文件。即在缓冲区中读取与写入时完全相同的位数。
这是我的尝试:
1)写入文件方法
private static final int INT_BYTES = Integer.SIZE / Byte.SIZE;
public void writeToFile(FileChannel fc, BitSet bitSet, int intId ) throws IOException
{
//each bitSet has a intId, first two int bytes written will have intId and bitSet.length() and rest will have content of bitSet
int byteLenOfBitSet=(int)Math.ceil((bitSet.length/8.0));
ByteBuffer bf = ByteBuffer.allocate(byteLenOfBitSet + 2*(INT_BYTES));
bf.putInt(intId); //put the Id
bf.putInt(bitSet.length(); // put the bit length, it would be used during read
bf.put(bitSet) //FIXME this is wrong, need to put bits , bf.put() put bytes
bf.flip();
fc.write(bf);
}
2)从文件方法中读取
public Result readFromFile(FileChannel fc) throws IOException
{
long currentPos = fc.position();
ByteBuffer bf = ByteBuffer.allocate(2* INT_BYTES);
if(fc.read(bf) < 0)return null;
bf.rewind();
int intId=bf.getInt(); //read first int as intId
int bitLen = bf.getInt(); //read second int as bitLen to read further from file
int byteLen=(int)Math.ceil((bitLen/8.0)); //FIXME not so sure
//move fc read position ahead by 2 INT_BYTES to read bitSet
fc.position((currentPos + INT_BYTES * 2));
bf = ByteBuffer.allocate(byteLen);//FIXME, this is wrong, we need to somehow get bit not in bytelen , don't want unnecessarily read entire byte if there is less than 8 bit of info to read
if(fc.read(bf) < 0)return null;
bf.rewind();
BitSet readBitSet = new BitSet();
//TODO, then read each bit from bf to a readBitSet
// and return result with intId+readBitSet
}
在另一组方法中,我必须只读取和写入整数(在字节级别),我使用类似于上面的逻辑使其工作正常。但是,陷入了一定的压力。
如果需要更多说明,请告诉我。
可能类似于Read and write file bit by bit 但答案是针对Perl,我正在寻找Java中的实现
修改
我的担忧:
由于数据以这种方式写入文件
2 INT_BYTES then bitSet example: 5 3 101
2 INT_BYTES then bitSet example: 2 10 1010111101
我担心在尝试首先阅读2 INT_BYTES
时我可能会读到第二个bitSet
,所以我的第一个结果是bitSet会出错。因此,想知道如何确保维持位级边界。即只有在读取第一个bitSet时才想读直到第一个BitSet的长度。
答案 0 :(得分:1)
This answer包含一个具有toByteArray
方法的BitSet子类。要编写,您可以从该方法获取byte[]
数组并使用ByteBuffer.put(byte[])
(ByteBuffer docs)。要阅读,您可以使用get()
然后循环byte[]
并重建该位集。
(供参考:FileChannel docs)
编辑回答您的question below。
我认为你可以摆脱fc.position
,因为fc.read
和bf.getInt
都会提升他们当前的位置。
根据this answer,allocate
的参数应该是您希望通过调用fc.read
读取的字节数。因此,2*INT_BYTES
看起来对于第一个allocate
调用是正确的。第二个allocate
也看起来不错;不要打电话给fc.position
。
对于byteLen
,请尝试byteLen=(bitLen >> 3) + ((bitLen&0x07)?1:0)
。 bitLen>>3
除以8(2 ^ 3)进行截断。所以1..7位有零,8..15有一个,.......如果位数不是8的倍数,则需要多一个字节。在这种情况下((bitLen&0x07)?1:0)
为1,否则为0。
请记住,如果你不具有8的倍数,那么这些位将在末尾填充。例如,读取12位将从流中获取两个完整字节。