I am trying to developing a java card application. There will a dynamic input string which will contain a phone number in a byte array like:
byte[] number =new byte[] {1,2,3,4,5,6,7,8,9,5};
I want this array to be changed into following array:
byte[] changed num = {(byte)0x0C, (byte)0x91, (byte)0x19, (byte)0x21, (byte)0x43, (byte)0x65, (byte)0x87, (byte)0x59}
Where first three bytes will be same always and remaining 5 will be update from the incoming array.
I have tried the following:
public static void main(String args[]){
byte[] number =new byte[] {1,2,3,4,5,6,7,8,9,5};
byte[] changednum = new byte[8];
changednum[0] = (byte)0x0C;
changednum[1] = (byte)0x91;
changednum[2] = (byte)0x19;
changednum[3] = (byte)0x(number[0] + number[1]*10);
changednum[4] = (byte)0x(number[2] + number[3]*10);
changednum[5] = (byte)0x(number[4] + number[5]*10);
changednum[6] = (byte)0x(number[6] + number[7]*10);
changednum[7] = (byte)0x(number[8] + number[9]*10);
System.out.println(Arrays.toString(changednum));
}
}
But the last 5 values are not being converted to byte value
s.
This line
changednum[3] = (byte)0x(number[0] + number[1]*10);
could be done with a complicate set of String manipulation how simple maths will do what you want.
changednum[3] = (byte)(number[0] + number[1]*16);
The *16 is needed because you appear to be assuming the number is in hexadecimal.
You could use a loop
for (int i = 0; i < 4; i++)
changednum[i+3] = (byte)(number[i*2] + number[i*2+1]*16);
or using += to avoid the cast
for (int i = 0; i < 4; i++)
changednum[i+3] += number[i*2] + number[i*2+1] * 16;
or you can write
for (int i = 0; i < 4; i++)
changednum[i+3] += number[i*2] + (number[i*2+1] << 4);
Although it is not very important in the standard edition of Java in this case, performance is often crucial in Java Card. This solution is slightly faster than the accepted answer thanks to bitwise operators and it is a valid Java Card code without 32-bit integers:
for (short i = 3, j = 0; i < 7; i++, j += 2) {
changednum[i] = (byte) ((number[j+1] << 4) | (number[j] & 0x0F));
}
You can use the method Integer.toHexString, that will do the convertion,
you need to carefully note that casting explicity integer to byte will truncate its value in a range between -128 to 127
final int f = -2211;
System.out.println(f);
System.out.println((byte) f);
System.out.println(Integer.toHexString((byte) f));
The other answers lack readability, in my opinion.
This solution uses separate methods and a ByteBuffer to make the methods work without passing an offset and other plumbing. It has weird things like constants and well thought out identifiers, exceptions, JavaDoc and other scary concepts from the book of maintainability.
package nl.owlstead.stackoverflow;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
/**
* Helper class to create telephone numbers with headers for Java card using
* reverse packed BCD format.
*
* #param buffer
* a buffer with enough space for the 3 byte header
*/
public final class OverlyDesignedTelephoneNumberHelper {
private static final int TELEPHONE_NUMBER_SIZE = 10;
private static final int NIBBLE_SIZE = 4;
private static final byte[] HEADER = { (byte) 0x0C, (byte) 0x91,
(byte) 0x19 };
/**
* Adds the header for the telephone number to the given buffer.
*
* #param buffer
* a buffer with enough space for the 3 byte header
* #throws NullPointerException
* if the buffer is null
* #throws BufferOverflowException
* if the buffer doesn't have enough space for the header
*/
private static void addTelephoneNumberHeader(final ByteBuffer buffer) {
buffer.put(HEADER);
}
/**
* Adds the telephone number to the given buffer.
*
* #param buffer
* a buffer with enough space for the 3 byte header
* #param number
* the number in BCD format, should be 10 bytes in size
* #throws IllegalArgumentException
* if the number is null or doesn't contain 10 BCD digits
* #throws NullPointerException
* if the buffer is null
* #throws BufferOverflowException
* if the buffer doesn't have enough space for the telephone
* number
*/
private static void addTelephoneNumber(final ByteBuffer buffer,
final byte[] number) {
if (number == null || number.length != TELEPHONE_NUMBER_SIZE) {
throw new IllegalArgumentException("Expecting 10 digit number");
}
for (int i = 0; i < number.length; i += 2) {
final byte lowDigit = number[i];
validateUnpackedBCDDigit(lowDigit);
final byte highDigit = number[i + 1];
validateUnpackedBCDDigit(highDigit);
buffer.put((byte) ((highDigit << NIBBLE_SIZE) | lowDigit));
}
}
/**
* Tests if the given unpacked BCD digit is within range.
*
* #param b
* the byte to test
* #throws IllegalArgumentException
* if it isn't
*/
private static void validateUnpackedBCDDigit(final byte b) {
if (b < 0 || b > 9) {
throw new IllegalArgumentException(
"Telefonenumber isn't all bytes representing digits in BCD");
}
}
public static void main(final String... args) {
final byte[] number = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 5 };
final ByteBuffer buf = ByteBuffer.allocate(HEADER.length
+ TELEPHONE_NUMBER_SIZE);
addTelephoneNumberHeader(buf);
addTelephoneNumber(buf, number);
buf.flip();
while (buf.hasRemaining()) {
System.out.printf("%02X", buf.get());
}
System.out.println();
}
private OverlyDesignedTelephoneNumberHelper() {
// avoid instantiation
}
}
Related
I am really new in sound processing and till date I have been able to understand (with a lot of help and criticism :P ) how to (1) take 2 frequencies and then generate audio out of it, alternatively.
Then, (2) write that audio as a .wav file that can be played by media players.
Then, (3) instead of time I took input from the user in the form of bits(8 bytes max) and when there is '0' in the given input I took the 1st frequency and in case of '1' the 2nd frequency.
I am attaching the above mentioned code, the '(3)' one, just for the sake of helping someone who needs it.
If you want to see my previous code, click here
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
public class AudioBits {
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
final double SAMPLING_RATE = 44100; // Audio sampling rate
float timeInterval = in.nextFloat(); //Time specified by user in milliseconds for each bit to be played
int frequency1 = in.nextInt(); //Frequency1 specified by the user in hz
int frequency2 = in.nextInt(); //Frequency2 specified by the user in hz
//To check if the user enters the value in the form of 0-1 or not, as that what is required
//And also the bits entered should not be greater than 8
while (!in.hasNext("[0-1]{1,8}")) {
System.out.println("Wrong input.");
in.next();
}
//Value in zero-one form. Where there is '0' it means one frequency and incase of '1' it means the other frequency
String binary = in.next();
//Converting the String value of one-zero form into its equivalent integer
int value = Integer.parseInt(binary, 2);
int binVal = 0b10000000; //Used to perform '&' operation with 'value'
//Size of buffer[], which in case of 2 sec is 88.2
float buffer[] = new float[((int) (timeInterval * SAMPLING_RATE)) / 1000];
//Size of buffer1[], which in case of 2 sec is 88.2
float buffer1[] = new float[((int) (timeInterval * SAMPLING_RATE)) / 1000];
for (int sample = 0; sample < buffer.length; sample++) { //range from zero to buffer.length
double cycle = sample / SAMPLING_RATE; //Fraction of cycle between samples
buffer[sample] = (float) (Math.sin(2 * Math.PI * frequency1 * cycle)); //value at every point of the cycle
}
for (int sample = 0; sample < buffer1.length; sample++) {
double cycle = sample / SAMPLING_RATE; //Fraction of cycle between samples
buffer1[sample] = (float) (Math.sin(2 * Math.PI * frequency2 * cycle));
}
byte byteBuffer[] = new byte[buffer.length * 2]; //Size of byteBuffer
byte byteBuffer1[] = new byte[buffer1.length * 2]; //Size of byteBuffer1
int count = 0;
//Analog to digital
for (int i = 0; i < byteBuffer.length; i++) {
int x = (int) (buffer[count++] * Short.MAX_VALUE);
byteBuffer[i++] = (byte) x;
byteBuffer[i] = (byte) (x / 256);
}
count = 0;
for (int i = 0; i < byteBuffer1.length; i++) {
int x = (int) (buffer1[count++] * Short.MAX_VALUE);
byteBuffer1[i++] = (byte) x;
byteBuffer1[i] = (byte) (x / 256);
}
byte[] merge = new byte[8 * byteBuffer.length]; //Merged Array's length
//Merging the two frequencies into one. Where there is '0' adding 1st frequency and in case of '1' adding 2nd
for (int i = 0; i < 8; i++) { //Loop for 8 Bits
int c = value & binVal; //'&' operation to check whether 'c' contains zero or not in every iteration
if (c == 0) {
System.arraycopy(byteBuffer, 0, merge, i * (byteBuffer.length), byteBuffer.length); //Adds 1st frequency
} else {
System.arraycopy(byteBuffer1, 0, merge, i * (byteBuffer.length), byteBuffer1.length); //Adds 2nd frequency
}
binVal = binVal >> 1; //Right Shifting the value of 'binVal' to be used for 'c'
}
File out = new File("E:/RecordAudio30.wav"); //The path where user want the file data to be written
//Construct an audio format, using 44100hz sampling rate, 16 bit samples, mono, and big
// endian byte ordering
AudioFormat format = new AudioFormat((float) SAMPLING_RATE, 16, 1, true, false);
// It uses 'merge' as its buffer array that contains bytes that may be read from the stream.
ByteArrayInputStream bais = new ByteArrayInputStream(merge);
//Constructs an audio input stream that has the requested format and length in sample frames, using audio data
//from the specified input stream.
AudioInputStream audioInputStream = new AudioInputStream(bais, format, (long) (8 * (byteBuffer.length / 2)));
//Writes a stream of bytes representing an audio file of the specified file type to the external file provided.
AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, out);
audioInputStream.close(); //Closes this audio input stream
}
}
I need to create a UUID or GUID in java 1.4. I get a classnotfound exception when i use: java.util.UUID.
There are similar questions here linked below, but none answer with a generator for Java 1.4:
Likelihood of collision using most significant bits of a UUID in Java
Create a GUID in Java
I have also found a few classes online:
http://johannburkard.de/software/uuid/
http://jackrabbit.apache.org/api/1.4/org/apache/jackrabbit/uuid/UUID.html
What would you suggest I use to create a UUID or GUID in java 1.4?
I suppose there is no chance convincing the client to get off an unsupported version of Java? Which if the answer is no then your only recourse is to use/modify one of the open source implementations from the web. You mentioned two of them in your question, another one you might want to look at is JUG.
And oh yea, your reference to java.util.UUID failed because it's only available in Java 5 and up.
Good luck!
java.util.UUID was added to JDK since 1.5.
For a simple lightweight implementation, take a look at this blog post: http://lzkyo.iteye.com/blog/453120.
Apache Commons ID (sandbox project, so you have to build from source, but I've used it and it works): project page, svn repo
You can also check try this project but I haven't used it.
Use the TechKey functionality within SAP ISA. that is what it is there for. Also it is compatiable with the ABAP Tables and well as any Portal and SAP J2EE Tables.
Unfortunately the UUID class is available since 1.5. I just implemented this utility class that creates UUIDs as String. Fell free to use and share. I hope it helps someone else!
package your.package.name;
import java.security.SecureRandom;
import java.util.Random;
/**
* Utility class that creates random-based UUIDs as Strings.
*
*/
public abstract class RandomUuidStringCreator {
private static final int RANDOM_VERSION = 4;
/**
* Returns a random-based UUID as String.
*
* It uses a thread local {#link SecureRandom}.
*
* #return a random-based UUID string
*/
public static String getRandomUuid() {
return getRandomUuid(SecureRandomLazyHolder.SECURE_RANDOM);
}
/**
* Returns a random-based UUID String.
*
* It uses any instance of {#link Random}.
*
* #return a random-based UUID string
*/
public static String getRandomUuid(Random random) {
long msb = 0;
long lsb = 0;
// (3) set all bit randomly
if (random instanceof SecureRandom) {
// Faster for instances of SecureRandom
final byte[] bytes = new byte[16];
random.nextBytes(bytes);
msb = toNumber(bytes, 0, 8); // first 8 bytes for MSB
lsb = toNumber(bytes, 8, 16); // last 8 bytes for LSB
} else {
msb = random.nextLong(); // first 8 bytes for MSB
lsb = random.nextLong(); // last 8 bytes for LSB
}
// Apply version and variant bits (required for RFC-4122 compliance)
msb = (msb & 0xffffffffffff0fffL) | (RANDOM_VERSION & 0x0f) << 12; // apply version bits
lsb = (lsb & 0x3fffffffffffffffL) | 0x8000000000000000L; // apply variant bits
// Convert MSB and LSB to hexadecimal
String msbHex = zerofill(Long.toHexString(msb), 16);
String lsbHex = zerofill(Long.toHexString(lsb), 16);
// Return the UUID
return format(msbHex + lsbHex);
}
private static long toNumber(final byte[] bytes, final int start, final int length) {
long result = 0;
for (int i = start; i < length; i++) {
result = (result << 8) | (bytes[i] & 0xff);
}
return result;
}
private static String zerofill(String string, int length) {
return new String(lpad(string.toCharArray(), length, '0'));
}
private static char[] lpad(char[] chars, int length, char fill) {
int delta = 0;
int limit = 0;
if (length > chars.length) {
delta = length - chars.length;
limit = length;
} else {
delta = 0;
limit = chars.length;
}
char[] output = new char[chars.length + delta];
for (int i = 0; i < limit; i++) {
if (i < delta) {
output[i] = fill;
} else {
output[i] = chars[i - delta];
}
}
return output;
}
private static String format(String string) {
char[] input = string.toCharArray();
char[] output = new char[36];
System.arraycopy(input, 0, output, 0, 8);
System.arraycopy(input, 8, output, 9, 4);
System.arraycopy(input, 12, output, 14, 4);
System.arraycopy(input, 16, output, 19, 4);
System.arraycopy(input, 20, output, 24, 12);
output[8] = '-';
output[13] = '-';
output[18] = '-';
output[23] = '-';
return new String(output);
}
// Holds lazy secure random
private static class SecureRandomLazyHolder {
static final Random SECURE_RANDOM = new SecureRandom();
}
/**
* For tests!
*/
public static void main(String[] args) {
System.out.println("// Using thread local `java.security.SecureRandom` (DEFAULT)");
System.out.println("RandomUuidCreator.getRandomUuid()");
System.out.println();
for (int i = 0; i < 5; i++) {
System.out.println(RandomUuidStringCreator.getRandomUuid());
}
System.out.println();
System.out.println("// Using `java.util.Random` (FASTER)");
System.out.println("RandomUuidCreator.getRandomUuid(new Random())");
System.out.println();
Random random = new Random();
for (int i = 0; i < 5; i++) {
System.out.println(RandomUuidStringCreator.getRandomUuid(random));
}
}
}
This is the output:
// Using `java.security.SecureRandom` (DEFAULT)
RandomUuidStringCreator.getRandomUuid()
'c4d1b0ec-c03a-4430-b210-bd692456d8f4'
'ddad65fb-aef9-4309-842d-284cef70e5f6'
'8b37cd8c-7390-4683-abed-524f97626995'
'd84b19bd-1fdb-4d76-ab7a-a845939c6934'
'ddb48e15-9512-4802-ace9-724d766643c6'
// Using `java.util.Random` (FASTER)
RandomUuidStringCreator.getRandomUuid(new Random())
'fa0a4861-6fa0-4258-8c8d-c89db9730b3e'
'bfe794fa-fe34-4ec3-aa93-5ec2e0897150'
'4c6441d8-10b5-4d8e-8dcf-6f1889d675e1'
'6f3012b7-e846-4173-8ffc-3a6e41893ea7'
'b73125a8-60f1-4dfd-b9fe-1a27aeb133a8'
I have an ByteArrayOutputStream connected with a Dataline from an AudioSource. I need to convert the Stream in some significative values that probally are the sound values taken from source or not ?
Well then how can I conver the byteArray (from ByteArrayOutStream.getByteArray()) in a intArray?. I googled it but with no luck .
p.s. the audioFormat that I used is : PCM_SIGNED 192.0Hz 16Bit big endian
Use a ByteBuffer. You can convert not only to different array types this way, but also deal with endian issues.
You can try the following:
ByteBuffer.wrap(byteArray).asIntBuffer().array()
When you do ByteArrayOutStream.toByteArray(), you get: byte[]. So now, I assume you need to convert byte[] to int.
You can do this:
/**
* Convert the byte array to an int.
*
* #param b The byte array
* #return The integer
*/
public static int byteArrayToInt(byte[] b) {
return byteArrayToInt(b, 0);
}
/**
* Convert the byte array to an int starting from the given offset.
*
* #param b The byte array
* #param offset The array offset
* #return The integer
*/
public static int byteArrayToInt(byte[] b, int offset) {
int value = 0;
for (int i = 0; i < 4; i++) {
int shift = (4 - 1 - i) * 8;
value += (b[i + offset] & 0x000000FF) << shift;
}
return value;
}
I need to store a couple binary sequences that are 16 bits in length into a byte array (of length 2). The one or two binary numbers don't change, so a function that does conversion might be overkill. Say for example the 16 bit binary sequence is 1111000011110001. How do I store that in a byte array of length two?
String val = "1111000011110001";
byte[] bval = new BigInteger(val, 2).toByteArray();
There are other options, but I found it best to use BigInteger class, that has conversion to byte array, for this kind of problems. I prefer if, because I can instantiate class from String, that can represent various bases like 8, 16, etc. and also output it as such.
Edit: Mondays ... :P
public static byte[] getRoger(String val) throws NumberFormatException,
NullPointerException {
byte[] result = new byte[2];
byte[] holder = new BigInteger(val, 2).toByteArray();
if (holder.length == 1) result[0] = holder[0];
else if (holder.length > 1) {
result[1] = holder[holder.length - 2];
result[0] = holder[holder.length - 1];
}
return result;
}
Example:
int bitarray = 12321;
String val = Integer.toString(bitarray, 2);
System.out.println(new StringBuilder().append(bitarray).append(':').append(val)
.append(':').append(Arrays.toString(getRoger(val))).append('\n'));
I have been disappointed with all of the solutions I have found to converting strings of bits to byte arrays and vice versa -- all have been buggy (even the BigInteger solution above), and very few are as efficient as they should be.
I realize the OP was only concerned with a bit string to an array of two bytes, which the BitInteger approach seems to work fine for. However, since this post is currently the first search result when searching "bit string to byte array java" in Google, I am going to post my general solution here for people dealing with huge strings and/or huge byte arrays.
Note that my solution below is the only solution I have ran that passes all of my test cases -- many online solutions to this relatively simple problem simply do not work.
Code
/**
* Zips (compresses) bit strings to byte arrays and unzips (decompresses)
* byte arrays to bit strings.
*
* #author ryan
*
*/
public class BitZip {
private static final byte[] BIT_MASKS = new byte[] {1, 2, 4, 8, 16, 32, 64, -128};
private static final int BITS_PER_BYTE = 8;
private static final int MAX_BIT_INDEX_IN_BYTE = BITS_PER_BYTE - 1;
/**
* Decompress the specified byte array to a string.
* <p>
* This function does not pad with zeros for any bit-string result
* with a length indivisible by 8.
*
* #param bytes The bytes to convert into a string of bits, with byte[0]
* consisting of the least significant bits in the byte array.
* #return The string of bits representing the byte array.
*/
public static final String unzip(final byte[] bytes) {
int byteCount = bytes.length;
int bitCount = byteCount * BITS_PER_BYTE;
char[] bits = new char[bitCount];
{
int bytesIndex = 0;
int iLeft = Math.max(bitCount - BITS_PER_BYTE, 0);
while (bytesIndex < byteCount) {
byte value = bytes[bytesIndex];
for (int b = MAX_BIT_INDEX_IN_BYTE; b >= 0; --b) {
bits[iLeft + b] = ((value % 2) == 0 ? '0' : '1');
value >>= 1;
}
iLeft = Math.max(iLeft - BITS_PER_BYTE, 0);
++bytesIndex;
}
}
return new String(bits).replaceFirst("^0+(?!$)", "");
}
/**
* Compresses the specified bit string to a byte array, ignoring trailing
* zeros past the most significant set bit.
*
* #param bits The string of bits (composed strictly of '0' and '1' characters)
* to convert into an array of bytes.
* #return The bits, as a byte array with byte[0] containing the least
* significant bits.
*/
public static final byte[] zip(final String bits) {
if ((bits == null) || bits.isEmpty()) {
// No observations -- return nothing.
return new byte[0];
}
char[] bitChars = bits.toCharArray();
int bitCount = bitChars.length;
int left;
for (left = 0; left < bitCount; ++left) {
// Ignore leading zeros.
if (bitChars[left] == '1') {
break;
}
}
if (bitCount == left) {
// Only '0's in the string.
return new byte[] {0};
}
int cBits = bitCount - left;
byte[] bytes = new byte[((cBits) / BITS_PER_BYTE) + (((cBits % BITS_PER_BYTE) > 0) ? 1 : 0)];
{
int iRight = bitCount - 1;
int iLeft = Math.max(bitCount - BITS_PER_BYTE, left);
int bytesIndex = 0;
byte _byte = 0;
while (bytesIndex < bytes.length) {
while (iLeft <= iRight) {
if (bitChars[iLeft] == '1') {
_byte |= BIT_MASKS[iRight - iLeft];
}
++iLeft;
}
bytes[bytesIndex++] = _byte;
iRight = Math.max(iRight - BITS_PER_BYTE, left);
iLeft = Math.max((1 + iRight) - BITS_PER_BYTE, left);
_byte = 0;
}
}
return bytes;
}
}
Performance
I was bored at work so I did some performance testing comparing against the accepted answer here for when N is large. (Pretending to ignore the fact that the BigInteger approach posted above doesn't even work properly as a general approach.)
This is running with a random bit string of size 5M and a random byte array of size 1M:
String -> byte[] -- BigInteger result: 39098ms
String -> byte[] -- BitZip result: 29ms
byte[] -> String -- Integer result: 138ms
byte[] -> String -- BitZip result: 71ms
And the code:
public static void main(String[] argv) {
int testByteLength = 1000000;
int testStringLength = 5000000;
// Independently random.
final byte[] randomBytes = new byte[testByteLength];
final String randomBitString;
{
StringBuilder sb = new StringBuilder();
Random rand = new Random();
for (int i = 0; i < testStringLength; ++i) {
int value = rand.nextInt(1 + i);
sb.append((value % 2) == 0 ? '0' : '1');
randomBytes[i % testByteLength] = (byte) value;
}
randomBitString = sb.toString();
}
byte[] resultCompress;
String resultDecompress;
{
Stopwatch s = new Stopwatch();
TimeUnit ms = TimeUnit.MILLISECONDS;
{
s.start();
{
resultCompress = compressFromBigIntegerToByteArray(randomBitString);
}
s.stop();
{
System.out.println("String -> byte[] -- BigInteger result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
{
s.start();
{
resultCompress = zip(randomBitString);
}
s.stop();
{
System.out.println("String -> byte[] -- BitZip result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
{
s.start();
{
resultDecompress = decompressFromIntegerParseInt(randomBytes);
}
s.stop();
{
System.out.println("byte[] -> String -- Integer result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
{
s.start();
{
resultDecompress = unzip(randomBytes);
}
s.stop();
{
System.out.println("byte[] -> String -- BitZip result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
}
}
If you have binary strings (literally String objects that contain only 1's and 0's), how would you output them as bits into a file?
This is for a text compressor I was working on; it's still bugging me, and it'd be nice to finally get it working. Thanks!
Easiest is to simply take 8 consecutive characters, turn them into a byte and output that byte. Pad with zeros at the end if you can recognize the end-of-stream, or add a header with length (in bits) at the beginning of the file.
The inner loop would look something like:
byte[] buffer = new byte[ ( string.length + 7 ) / 8 ];
for ( int i = 0; i < buffer.length; ++i ) {
byte current = 0;
for ( int j = 7; j >= 0; --j )
if ( string[ i * 8 + j ] == '1' )
current |= 1 << j;
output( current );
}
You'll need to make some adjustments, but that's the general idea.
If you're lucky, java.math.BigInteger may do everything for you.
String s = "11001010001010101110101001001110";
byte[] bytes = (new java.math.BigInteger(s, 2)).toByteArray();
This does depend on the byte order (big-endian) and right-aligning (if the number of bits is not a multiple of 8) being what you want but it may be simpler to modify the array afterwards than to do the character conversion yourself.
public class BitOutputStream extends FilterOutputStream
{
private int buffer = 0;
private int bitCount = 0;
public BitOutputStream(OutputStream out)
{
super(out);
}
public void writeBits(int value, int numBits) throws IOException
{
while(numBits>0)
{
numBits--;
int mix = ((value&1)<<bitCount++);
buffer|=mix;
value>>=1;
if(bitCount==8)
align8();
}
}
#Override
public void close() throws IOException
{
align8(); /* Flush any remaining partial bytes */
super.close();
}
public void align8() throws IOException
{
if(bitCount > 0)
{
bitCount=0;
write(buffer);
buffer=0;
}
}
}
And then...
if (nextChar == '0')
{
bos.writeBits(0, 1);
}
else
{
bos.writeBits(1, 1);
}
Assuming the String has a multiple of eight bits, (you can pad it otherwise), take advantage of Java's built in parsing in the Integer.valueOf method to do something like this:
String s = "11001010001010101110101001001110";
byte[] data = new byte[s.length() / 8];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) Integer.parseInt(s.substring(i * 8, (i + 1) * 8), 2);
}
Then you should be able to write the bytes to a FileOutputStream pretty simply.
On the other hand, if you looking for effeciency, you should consider not using a String to store the bits to begin with, but build up the bytes directly in your compressor.