java - 在 Java 中实现 writeBit 方法
问题描述
所以我知道在 Java 中你不能将单个位写到文件中,你必须使用 writeByte。我有一些理解,有一种方法可以实现 writeBit 方法,该方法通过在 8 个“位”连接在一起时调用 writeByte 来使用 writeByte。我希望像这样实现:
public void writeBit(char bit) {
try {
//functionality here
} catch (IOException e) {
System.out.println(e);
}
}
但我似乎无法开始。我知道我可能应该有一些属性来跟踪我连接了多少位,但除此之外,我不知道如何实现这一点。
我想我的大问题是如何在不丢失连接的位字符串的情况下连续调用 writeBit,如果要使用 writeByte,writeBit 的实现会是什么样子?
作为旁注,如果不清楚,我在这里使用 DataOutputStream。
解决方案
我注意到有几个人讨论过使用两个实例变量,一个用于在向字节添加位时存储字节,另一个用于跟踪到目前为止已添加了多少位。虽然这是一个非常好的方法,但我想说明为什么您不需要第二个实例变量。
理论
无需跟踪到目前为止添加了多少位。我们需要的唯一信息是“字节是否已填充?”。不要将字节初始化为 0,而是尝试将其初始化为值 1。然后每次添加位时,将字节的位向左移动一个位置(使用位移运算符<<
),然后将新位添加到最右边的地方。
在实践中,它看起来像这样,X
新添加的位在哪里:
将字节初始化为值 1:00000001
要插入新位,请将位左移:00000010
X
并在最右边的地方添加新的位:0000001X
左移:000001X0
添加新位:000001XX
最终,你会从你的方法中写入 7 位,最左边的位是1
:1XXXXXXX
因此,在您的方法中,您可以检查每次调用时是否设置了最左边的位。如果是,那么您知道您已准备好在此迭代中将字节写入文件。你会先做同样的事情,左移然后添加新的位,所以现在你有了XXXXXXXX
. 然后您将现在已满的字节写入文件,然后将字节重置为值 1,以便循环重新开始。
编写代码
首先,您需要一个实例变量来跟踪这些位。它需要是字节类型,我就叫它buffer
。
要将位向左移动一位,我们可以使用位移运算符,<<
. 而且,为了让我们的生活更轻松,甚至还有一个移位赋值运算符 ,<<=
因此我们可以在一次操作中执行移位并将新值赋回变量。这给我们留下了:
buffer <<= 1;
我们需要做的下一件事是添加新位。如果您将一个值与 1 进行或运算,则将设置最右边的位,而其余位将不受影响。如果您将值与 0 进行或运算,则不会影响任何位。如果新位为 1,我们可以使用此技巧仅设置最右边的位(The|=
是 OR 赋值运算符):
buffer |= bit ? 1 : 0;
然后,这段代码的最后一段是编写 if 语句来检查是否设置了最左边的位。如果是,那么当我们将它与 进行 AND 时10000000
,我们将得到10000000
。如果没有,我们将得到00000000
. 10000000
是128
十进制的(or -128
, or 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;
}
}
推荐阅读
- c++ - 将 nullptr 转换为 std::span
- string - Linting:比较 Verilog 参数和常量字符串
- javascript - 关闭鼠标悬停时打开的弹出菜单时防止恢复焦点
- c - 如何在动态链接库中调用全局变量?
- python - 如何使用循环创建和返回 5 行数据框
- python - 检测图像中不均匀照明的稳健算法[仅需要检测]
- linux - Linux 键盘快捷键
- c# - 为什么调用 webapi 方法会抛出错误,即路径无效?
- android - 如何将 Android SDK 添加到 Intellij?
- apache-kafka - kafka.zookeeper.ZooKeeperClientTimeoutException:超时等待连接状态:CONNECTING