Bit level IO optimization

I have created my own Bit-Level IO stream. It works perfectly, however there is noticable speed issues for large streams.

Can anyone suggest how i may optimize these classes further?


/*
      $Log: BitInputStream.java,v $
      Revision 1.2  2005/02/04 13:51:05  moogie
      -fixed FileDataInfo transfer
      -fixed Directory Transfer
      -made hashtables synchronized
      -fixed miscelanous bugs
      -modified the client gui to use the multiple ID file data request.
      
      Revision 1.1  2005/02/01 06:36:35  moogie
      - added FileName String Compression (Huffman)
      - no longer storing the full path on serverside... is now being derived
      - added binary RunLengthEncoding for potential use in file transfer
      
 */
 
/**
 * @author Nicholas Klaebe
 */
 
package compression;
import java.io.*;
 
public class BitInputStream 
{
      InputStream fis;      // The parent IO stream
      int count;                  // The current bit position in the current byte
      long totalCount;      // The number of bits written
      byte value;                  // The current byte;
      byte[] buffer;            // The byte buffer containing bytes read in from the parent IO stream
      int buffCount;            // the current position in the buffer
      int buffSize;            // the size of the populated buffer
      boolean returnVal;      
      private static final int EOF_INT=-1;
      
      /**
       * Constructor
       * @param fis1            The base inputStream
       * @param size            size of the input buffer
       */
      public BitInputStream(InputStream fis1,int size)  
      {
            count=0;
            buffer=new byte[size];
            buffCount=0;
            totalCount=0;
            fis=fis1;
      }
            
      /**
       * read in a single bit
       * @return bit read
       * @throws IOException
       */
      public boolean read() throws IOException
      {
            if (count==0)
            {
                  if (buffCount==0)
                  {
                        buffSize=0;
                        while (buffSize==0)
                        {
                              buffSize=fis.read(buffer,0,buffer.length);
                        }
                        if (buffSize==EOF_INT) 
                        {
                              throw new IOException("END OF FILE");
                        } 
                                     
                  }
                  value=buffer[buffCount];
                  buffCount++;
                  if (buffCount==buffSize) buffCount=0;
            }
            
            returnVal=(((value>>(7-count) &0x01)>0)?true:false);
                  
            count++;
            totalCount++;
            if (count==8) count=0;
            
            return returnVal;
      }
      /**
       * reads in the next char, if not on a 8bit boundary then the stream is aligned to the next byte
       * @return byte read
       * @throws IOException
       */
      public char readChar() throws IOException
      {
            byte[] b= new byte[1];
            alignToNextByte();
            fis.read(b);
            totalCount+=8;
            return (char) b[0];
      }
      
      /**
       * aligns the bit stream to the next byte boundary
       * @throws IOException
       */
      public void alignToNextByte() throws IOException
      {
            while (count!=0)
            {
                  read();
            }
      }
      
      /**
       * read in a specified number of bits
       * @param bits      the number of bits to be read (between 1 and 64)
       * @return a long integer containg the bits read
       * @throws IOException
       */
 
      public long read(int bits) throws IOException
      {
            long val=0;
            int mask=0x01;
            boolean[] bitsRead=new boolean[bits];
                  
            for (int i=0;i<bits;i++)
            {
                  bitsRead[i]=read();
            }
            for (int j=bits-1;j>-1;j--)
            {
                        
                  val=val<<1;
                  if (bitsRead[j]) 
                  {
                        val=val|mask;
                  }
            }
            return val;
      }
      /**
       * attempts to read bytes into the array given
       * @param temp            the array being populated
       * @param start            the starting index
       * @param end            the ending index
       * @return                  the bytes read in
       * @throws IOException
       */
      public int read(byte[] temp,int start,int end) throws IOException
      {
            totalCount+=end-start;
            return fis.read(temp,start,end);
      }
}
 


/*$Log: BitOutputStream.java,v $
/*Revision 1.1  2005/02/01 06:36:35  moogie
/*- added FileName String Compression (Huffman)
/*- no longer storing the full path on serverside... is now being derived
/*- added binary RunLengthEncoding for potential use in file transfer
/**/
 
/**
 * @author Nicholas Klaebe
 */
 
package compression;
import java.io.*;
 
public class BitOutputStream
      {
            int value;                        // The byte in which the encoded bits are firstly stored.
            int count;                        // The number of bits written into value.
            byte[] buffer;                  // A byte buffer which is filled with 'value' each time value is full. Used for wirting to file.
            int buffCount;                  // The current number of 'values' written into the buffer.
            long masterCount;            // The overall count of bits that have been written
            OutputStream fos;
            
            /**
             * constructor
             * @param fos1      The outputstream which this bit stream writes to
             */
            public BitOutputStream(OutputStream fos1)
            {
                  fos=fos1;
                  value=0;
                  count=0;
                  buffer=new byte[4096];
                  buffCount=0;
                  masterCount=0;
            }
            
            /**
             * Writes the passed value (temp) to the file using the given number of bits
             * @param temp            the value to be written
             * @param bits            the number if bits to write
             * @throws IOException
             */
            public void write(long temp,int bits) throws IOException
            {
 
      
 
                        for (int j = 0, mask = 1; j < bits; j++, mask <<= 1)
                        {  
                              value=value<<1;count++;
                              if  ((temp & mask) > 0)
                              {
                                    value=value|0x01;
                              }
                              addToBuffer();
                        }
            }
            
            /**
             * write a single bit to the stream
             * @param bit            The bit to write
             * @throws IOException
             */
            public void write(boolean bit) throws IOException
            {
                  value=value<<1;count++;
                  if  (bit)
                  {
                        value=value|0x01;
                  }
                  addToBuffer();
                        
            }
            
            /**
             * writes a single char (converted to a byte) to the output stream aligning with the next byte boundary
             * @param c             the char to write
             * @throws IOException
             */
            
            public void write(char c) throws IOException
            {
                        flush();
                        byte[] b=new byte[1];
                        b[0]=(byte) c;
                        fos.write(b);
                        masterCount+=8;
                        
            }
 
            /**
             * adds bits stored in 'value' to a buffer which will be saved to a file
             * if the current bit count since last storing into the buffer is less than 8 then return without adding it to the buffer
             * @throws IOException
             */            
      
            public void addToBuffer() throws IOException
            {
                  masterCount++;
            
                  if (count<8) return;
 
                  //byte temp=(byte) (value);
                  buffer[buffCount]=(byte) (value);;
                  buffCount++;
            
                  if (buffCount==buffer.length)
                  {
                        fos.write(buffer,0,buffCount);
                        buffCount=0;
                  }
                  value=0;
                  count=0;
            }
            
            /**
             * writes a single byte to the output stream aligning with the next byte boundary
             * @param b            the byte to write
             * @throws IOException
             */
            public void write(byte[] b) throws IOException
            {
                  flush();
                  fos.write(b);
            }
            
            /**
             * align the output stream with the next byte boundary
             * @throws IOException
             */
            
            public void flush() throws IOException
            {
                  // pad out the last byte if necessary
                  
                  if (count>0)
                  {
                        masterCount+=(8-count-1);
                        value=value<<(8-count);
                        count=8;
                        addToBuffer();
                  }
                  if (buffCount>0)
                  {
                        
                        fos.write(buffer,0,buffCount);
                        buffCount=0;
                  }
                  
            }
            
            /**
             * close the output stream
             * @throws IOException
             */
            
            public void close() throws IOException
            {
                  flush();
                  fos.close();
            }
      }

How fast is it? My arithmetic / range coder could compress at 250 kB/s, it used bit stream on background.
Why ary you creating new byte?
Doesn’t this means a one new object for every char?

Well, i get about 1.5 -2 meg per second. ( i have not quantified this figure)

Where do i create a new byte?

I think he means this:

   public void write(char c) throws IOException
  {
    flush();
    byte[] b=new byte[1];
    b[0]=(byte) c;
    fos.write(b);
    masterCount+=8;
     
  } 

Why don’t you use the method write(int b) instead of write(byte[] b)? In any case the byte[] version of write will call the int version.

ah, oops that is a bit of legacy code which i have forgot to trim out. It is not needed or used by the application which uses these Bit IO classes.