如何在Java中以位级精度读取和写入文件

时间:2014-04-20 22:11:36

标签: java file-io bit-manipulation bitset

我对位级读取和写入/从文件写起来都不是新鲜事。

我想在位级精度读取和写入文件。即在缓冲区中读取与写入时完全相同的位数。

这是我的尝试:

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的长度。

1 个答案:

答案 0 :(得分:1)

This answer包含一个具有toByteArray方法的BitSet子类。要编写,您可以从该方法获取byte[]数组并使用ByteBuffer.put(byte[])ByteBuffer docs)。要阅读,您可以使用get()然后循环byte[]并重建该位集。

(供参考:FileChannel docs

编辑回答您的question below

  • 我认为你可以摆脱fc.position,因为fc.readbf.getInt都会提升他们当前的位置。

  • 根据this answerallocate的参数应该是您希望通过调用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位将从流中获取两个完整字节。