在 Java 中实现 writeBit 方法
Implementing a writeBit method in Java
所以我知道在 Java 中你不能将单个位写到文件中,你必须使用 writeByte。我有一些理解,有一种方法可以实现 writeBit 方法,该方法通过在 8 'bits' 连接在一起后调用 writeByte 来使用 writeByte。我希望像这样实现:
public void writeBit(char bit) {
try {
//functionality here
} catch (IOException e) {
System.out.println(e);
}
}
但我似乎无法开始。我知道我可能应该有一些属性来跟踪我连接了多少位,但除此之外我不知道如何实现它。
我想我的大问题是如何在不丢失连接的位字符串的情况下连续调用 writeBit,如果要使用 writeByte,writeBit 的实现会是什么样子?
附带说明一下,如果不清楚,我在这里使用 DataOutputStream。
用两个实例变量创建一个class,第一个变量是你到目前为止已经累积的位数,第二个是你累积了多少位数。使用移位和或操作向缓冲区中插入一个位(初始化为零),并增加位数。一旦你有八位,写入缓冲区,然后将缓冲区和计数归零。
最后,如果计数不为零,您需要通过将缓冲区写入一个字节来清除所有剩余的位,即使它包含的位少于八位。位序列的格式需要能够处理这种可能性,除非它确保始终写入八位的倍数。
我注意到有几个人谈到了使用两个实例变量,一个用于在您向其添加位时存储字节,另一个用于跟踪到目前为止已添加了多少位。虽然这是一个非常好的方法,但我想说明为什么您不需要第二个实例变量。
理论
无需跟踪到目前为止已添加了多少位。我们唯一需要的信息是“这个字节已经填满了吗?”。不要将字节初始化为 0,而是尝试将其初始化为值 1。然后每次添加一位时,将字节的位向左移动一位(使用位移运算符 <<
),然后在最右边添加新位。
实际上,它看起来像这样,其中 X
是新添加的位:
将字节初始化为值1:00000001
要插入一个新位,将位向左移动:00000010
并在最右边添加新位X
:0000001X
左移:000001X0
添加新位:000001XX
最终,您将从您的方法中写入 7 位,最左边的位将是 1
:1XXXXXXX
因此在您的方法中,您可以在每次调用时检查最左边的位是否已设置。如果是,那么您就知道您已准备好在此迭代中将字节写入文件。你会开始做同样的事情,向左移动然后添加新的位,所以现在你有 XXXXXXXX
。然后将现在已满的字节写入文件,然后将字节重置为值 1,以便循环可以重新开始。
正在编写代码
首先,您需要一个实例变量来跟踪这些位。它需要是 byte 类型,我就称它为 buffer
.
要将位向左移动一位,我们可以使用位移运算符<<
。而且,为了让我们的生活更轻松,甚至还有位移赋值运算符 <<=
,因此我们可以执行位移并将新值赋回给变量,所有操作都在一次操作中完成。这给我们留下了:
buffer <<= 1;
接下来我们需要做的是添加新位。如果您将一个值与 1 进行或运算,最右边的位将被设置,其余位将不受影响。如果您将值与 0 进行或运算,none 位会受到影响。如果新位是 1,我们可以使用这个技巧只设置最右边的位(|=
是 OR 赋值运算符):
buffer |= bit ? 1 : 0;
然后,此代码的最后一段是编写 if 语句来检查最左边的位是否已设置。如果是,那么当我们用 10000000
与它时,我们将得到 10000000
。如果没有,我们将得到 00000000
。 10000000
是十进制的 128
(或者 -128
,或者 256
,都可以),所以我们的表达式是:
(buffer & 128) == 128
结果
将所有这些部分放在一起,我们得到:
// Notice bit is type boolean
public void writeBit(boolean bit) {
// If the leftmost bit in buffer is set:
if ((buffer & 128) == 128) {
// Shift all the bits in buffer to the left 1 place
buffer <<= 1;
// Add the new bit in the rightmost place
buffer |= bit ? 1 : 0;
// Write the now-full byte to the file
// I'm just calling your DataOutputStream "dos" here
try {
dos.writeByte(buffer);
} catch (IOException e) {
throw new RuntimeException();
}
// Reset buffer to a value of 1
buffer = 1;
} else {
// Shift all the bits in buffer to the left 1 place
buffer <<= 1;
// Add the new bit in the rightmost place
buffer |= bit ? 1 : 0;
}
}
所以我知道在 Java 中你不能将单个位写到文件中,你必须使用 writeByte。我有一些理解,有一种方法可以实现 writeBit 方法,该方法通过在 8 'bits' 连接在一起后调用 writeByte 来使用 writeByte。我希望像这样实现:
public void writeBit(char bit) {
try {
//functionality here
} catch (IOException e) {
System.out.println(e);
}
}
但我似乎无法开始。我知道我可能应该有一些属性来跟踪我连接了多少位,但除此之外我不知道如何实现它。
我想我的大问题是如何在不丢失连接的位字符串的情况下连续调用 writeBit,如果要使用 writeByte,writeBit 的实现会是什么样子?
附带说明一下,如果不清楚,我在这里使用 DataOutputStream。
用两个实例变量创建一个class,第一个变量是你到目前为止已经累积的位数,第二个是你累积了多少位数。使用移位和或操作向缓冲区中插入一个位(初始化为零),并增加位数。一旦你有八位,写入缓冲区,然后将缓冲区和计数归零。
最后,如果计数不为零,您需要通过将缓冲区写入一个字节来清除所有剩余的位,即使它包含的位少于八位。位序列的格式需要能够处理这种可能性,除非它确保始终写入八位的倍数。
我注意到有几个人谈到了使用两个实例变量,一个用于在您向其添加位时存储字节,另一个用于跟踪到目前为止已添加了多少位。虽然这是一个非常好的方法,但我想说明为什么您不需要第二个实例变量。
理论
无需跟踪到目前为止已添加了多少位。我们唯一需要的信息是“这个字节已经填满了吗?”。不要将字节初始化为 0,而是尝试将其初始化为值 1。然后每次添加一位时,将字节的位向左移动一位(使用位移运算符 <<
),然后在最右边添加新位。
实际上,它看起来像这样,其中 X
是新添加的位:
将字节初始化为值1:00000001
要插入一个新位,将位向左移动:00000010
并在最右边添加新位X
:0000001X
左移:000001X0
添加新位:000001XX
最终,您将从您的方法中写入 7 位,最左边的位将是 1
:1XXXXXXX
因此在您的方法中,您可以在每次调用时检查最左边的位是否已设置。如果是,那么您就知道您已准备好在此迭代中将字节写入文件。你会开始做同样的事情,向左移动然后添加新的位,所以现在你有 XXXXXXXX
。然后将现在已满的字节写入文件,然后将字节重置为值 1,以便循环可以重新开始。
正在编写代码
首先,您需要一个实例变量来跟踪这些位。它需要是 byte 类型,我就称它为 buffer
.
要将位向左移动一位,我们可以使用位移运算符<<
。而且,为了让我们的生活更轻松,甚至还有位移赋值运算符 <<=
,因此我们可以执行位移并将新值赋回给变量,所有操作都在一次操作中完成。这给我们留下了:
buffer <<= 1;
接下来我们需要做的是添加新位。如果您将一个值与 1 进行或运算,最右边的位将被设置,其余位将不受影响。如果您将值与 0 进行或运算,none 位会受到影响。如果新位是 1,我们可以使用这个技巧只设置最右边的位(|=
是 OR 赋值运算符):
buffer |= bit ? 1 : 0;
然后,此代码的最后一段是编写 if 语句来检查最左边的位是否已设置。如果是,那么当我们用 10000000
与它时,我们将得到 10000000
。如果没有,我们将得到 00000000
。 10000000
是十进制的 128
(或者 -128
,或者 256
,都可以),所以我们的表达式是:
(buffer & 128) == 128
结果
将所有这些部分放在一起,我们得到:
// Notice bit is type boolean
public void writeBit(boolean bit) {
// If the leftmost bit in buffer is set:
if ((buffer & 128) == 128) {
// Shift all the bits in buffer to the left 1 place
buffer <<= 1;
// Add the new bit in the rightmost place
buffer |= bit ? 1 : 0;
// Write the now-full byte to the file
// I'm just calling your DataOutputStream "dos" here
try {
dos.writeByte(buffer);
} catch (IOException e) {
throw new RuntimeException();
}
// Reset buffer to a value of 1
buffer = 1;
} else {
// Shift all the bits in buffer to the left 1 place
buffer <<= 1;
// Add the new bit in the rightmost place
buffer |= bit ? 1 : 0;
}
}