要讀取/寫入二進制文件,我使用DataInputStream/DataOutputStream,他們有這種方法writeByte()/ readByte(),但我想要做的是讀/寫位?可能嗎?我想將它用於壓縮算法,所以當我壓縮時我想寫3位(對於一個數字,並且文件中有數百萬個這樣的數字),並且如果我每次都需要寫一個字節寫3位,我將寫入大量的冗餘數據...是否可以使用JAVA從文件中讀取/寫入位?
回答
無法直接讀取/寫入各個位,您可以讀取/寫入的最小單位是一個字節。
您可以使用標準的bitwise運算符來操縱一個字節,例如,得到一個字節的最低2位,你會做
byte b = in.readByte();
byte lowBits = b&0x3;
設置低4位爲1,並寫入字節:
b |= 0xf;
out.writeByte(b);
(注意,出於效率的考慮你可能要讀取/寫入的字節數組,而不是單個字節)
InputStreams和OutputStreams是字節流。
要讀取一個位,您需要讀取一個字節,然後使用位操作來檢查您關心的位。同樣,要寫位,你需要寫出包含你想要的位的字節。
是和否。在大多數現代計算機上,一個字節是最小的可尋址內存單元,因此您一次只能讀取/寫入整個字節。但是,您始終可以使用按位運算符來操作一個字節內的位。
位是以字節爲單位打包的,除了VHDL/Verilog之外,我沒有看到允許您將單個位附加到流中的語言。緩存你的位,並使用緩衝區將它們打包成一個字節進行寫操作,並且使用bitmasking。做相反的讀操作,即在你的緩衝區中保留一個指針,並且當你返回單獨的被屏蔽位時增加它。
Afaik在Java API中沒有這樣做的功能。但是,您當然可以讀取一個字節,然後使用位操作功能。寫作也一樣。
移到https://github.com/jinahya/bit-io
<dependency>
<!-- resides in central repo -->
<groupId>com.googlecode.jinahya</groupId>
<artifactId>bit-io</artifactId>
<version>1.0-alpha-13</version>
</dependency>
這是一個小型的方便庫,用於使用Java讀取/寫入任意長度的位。
final InputStream stream;
final BitInput input = new BitInput(new BitInput.StreamInput(stream));
final int b = input.readBoolean(); // reads a 1-bit boolean value
final int i = input.readUnsignedInt(3); // reads a 3-bit unsigned int
final long l = input.readLong(47); // reads a 47-bit signed long
input.align(1); // 8-bit byte align; padding
final WritableByteChannel channel;
final BitOutput output = new BitOutput(new BitOutput.ChannelOutput(channel));
output.writeBoolean(true); // writes a 1-bit boolean value
output.writeInt(17, 0x00); // writes a 17-bit signed int
output.writeUnsignedLong(54, 0x00L); // writes a 54-bit unsigned long
output.align(4); // 32-bit byte align; discarding
沒有辦法直接做。計算機可以處理的最小單位是一個字節(甚至布爾值佔用一個字節)。但是,您可以創建一個自定義的流類,它可以將需要寫入的位打包爲一個字節。然後,你可以爲這個類編寫一個包裝函數,它的write函數需要一些整型,檢查它是在0到7之間(或者-4和3 ......或者其他),以與BitInputStream類(下面)相同的方式提取這些位,並且對BitOutputStream的寫入方法進行相應的調用。你可能會認爲你只能創建一組IO流類,但是3不能均勻地分成8類。所以,如果你想獲得最佳的存儲效率,並且你不想努力工作,那麼你會陷入兩層抽象。下面是一個BitOutputStream類,一個相應的BitInputStream類和一個確保它們工作的程序。
import java.io.IOException;
import java.io.OutputStream;
class BitOutputStream {
private OutputStream out;
private boolean[] buffer = new boolean[8];
private int count = 0;
public BitOutputStream(OutputStream out) {
this.out = out;
}
public void write(boolean x) throws IOException {
this.count++;
this.buffer[8-this.count] = x;
if (this.count == 8){
int num = 0;
for (int index = 0; index < 8; index++){
num = 2*num + (this.buffer[index] ? 1 : 0);
}
this.out.write(num - 128);
this.count = 0;
}
}
public void close() throws IOException {
int num = 0;
for (int index = 0; index < 8; index++){
num = 2*num + (this.buffer[index] ? 1 : 0);
}
this.out.write(num - 128);
this.out.close();
}
}
我敢肯定有辦法收拾同位運算符的INT,從而避免扭轉輸入,但我並不想什麼難。
此外,您可能會注意到,有檢測到最後一位在此實現讀取本地沒有辦法,但我真的不想認爲該努力。
import java.io.IOException;
import java.io.InputStream;
class BitInputStream {
private InputStream in;
private int num = 0;
private int count = 8;
public BitInputStream(InputStream in) {
this.in = in;
}
public boolean read() throws IOException {
if (this.count == 8){
this.num = this.in.read() + 128;
this.count = 0;
}
boolean x = (num%2 == 1);
num /= 2;
this.count++;
return x;
}
public void close() throws IOException {
this.in.close();
}
}
你可能知道這一點,但你應該把一個BufferedStream在比特流和之間的FileStream或它會永遠需要。
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
class Test {
private static final int n = 1000000;
public static void main(String[] args) throws IOException {
Random random = new Random();
//Generate array
long startTime = System.nanoTime();
boolean[] outputArray = new boolean[n];
for (int index = 0; index < n; index++){
outputArray[index] = random.nextBoolean();
}
System.out.println("Array generated in " + (double)(System.nanoTime() - startTime)/1000/1000/1000 + " seconds.");
//Write to file
startTime = System.nanoTime();
BitOutputStream fout = new BitOutputStream(new BufferedOutputStream(new FileOutputStream("booleans.bin")));
for (int index = 0; index < n; index++){
fout.write(outputArray[index]);
}
fout.close();
System.out.println("Array written to file in " + (double)(System.nanoTime() - startTime)/1000/1000/1000 + " seconds.");
//Read from file
startTime = System.nanoTime();
BitInputStream fin = new BitInputStream(new BufferedInputStream(new FileInputStream("booleans.bin")));
boolean[] inputArray = new boolean[n];
for (int index = 0; index < n; index++){
inputArray[index] = fin.read();
}
fin.close();
System.out.println("Array read from file in " + (double)(System.nanoTime() - startTime)/1000/1000/1000 + " seconds.");
//Delete file
new File("booleans.bin").delete();
//Check equality
boolean equal = true;
for (int index = 0; index < n; index++){
if (outputArray[index] != inputArray[index]){
equal = false;
break;
}
}
System.out.println("Input " + (equal ? "equals " : "doesn't equal ") + "output.");
}
}
您必須知道,如果位數不是8的倍數,則最後一個字節將以前導零完成。如果沒有處理它可能會導致一些錯誤。 – Gregory 2016-09-22 15:08:31
下面的代碼應該工作
int[] mynumbers = {3,4};
BitSet compressedNumbers = new BitSet(mynumbers.length*3);
// let's say you encoded 3 as 101 and 4 as 010
String myNumbersAsBinaryString = "101010";
for (int i = 0; i < myNumbersAsBinaryString.length(); i++) {
if(myNumbersAsBinaryString.charAt(i) == '1')
compressedNumbers.set(i);
}
String path = Resources.getResource("myfile.out").getPath();
ObjectOutputStream outputStream = null;
try {
outputStream = new ObjectOutputStream(new FileOutputStream(path));
outputStream.writeObject(compressedNumbers);
} catch (IOException e) {
e.printStackTrace();
}
如果你只是寫位到一個文件中,Java的BitSet class可能是值得看一看。來自javadoc:
該類實現了根據需要增長的位向量。位集的每個組件都有一個布爾值。 BitSet的位由非負整數索引。各個索引位可以被檢查,設置或清除。一個BitSet可用於通過邏輯AND,邏輯或(OR)和邏輯異或操作來修改另一個BitSet的內容。
您可以將BitSets轉換爲long []和byte []將數據保存到文件。
'BitSet'在這裏如何相關? – 2016-04-02 11:11:53
- 1. 是否可以使用Java來讀取位圖文件頭?
- 2. 是否可以使用JavaScript從txt文件讀取/寫入文件?
- 3. 是否可以讀取和寫入文件只打開一次?
- 4. 是否可以從Azure ServiceConfiguration文件讀取IIS重寫規則?
- 5. 是否可以同時讀寫文件?
- 6. Java:文件讀取/寫入
- 7. Java - 文件讀取/寫入
- 8. 在java中可以使用eclipse讀取.txt文件的位置?
- 9. 使用xdocreport,是否可以從docx文件讀取圖形?
- 10. 是否可以使用FileReader從文件讀取?
- 11. 是否可以使用Perl讀取pdf文件中的文本?
- 12. 是否可以使用python suds從文件系統中讀取wsdl文件?
- 13. 用c從/中讀取/寫入文件
- 14. 是否可以讀取鎖定文件?
- 15. 是否可以讀取.exe文件?
- 16. 在Python中寫入文件,使用Arduino從文件中讀取
- 17. 是否可以從VB6讀取/寫入用C#編寫的類/結構?
- 18. 是否可以在單個文件中寫入和讀取多個DataFrame?
- 19. 鑑於tcl代碼仍在寫入,是否可以在tcl中讀取文件?
- 20. 是否可以使用Labview編寫/讀取文本文件的元數據?
- 21. 在java中使用ArrayList寫入和讀取文件(使用ArrayList)
- 22. 是否可以在放入apk文件中寫入文件?
- 23. 是否可以從批處理文件寫入excel文件?
- 24. 使用JavaScript可以讀取/寫入服務器上的文件
- 25. 從文件讀取並寫入到java文件中
- 26. 是否可以使用Javascript從網絡文件系統讀取文件?
- 27. Golang從文件中讀取 - 是否可以鎖定?
- 28. Grails是否可以從遠程文件目錄中讀取?
- 29. Java - 讀取和寫入文本文件
- 30. 是否有可能使用MMIO讀取Java的波形文件?
看來,我將不得不讀取/寫入字節和學習按位操作...謝謝大家的答案.... – 2010-11-19 00:11:49
謝謝你,爲效率點... – 2010-11-19 00:12:13
通過和b和0x3,aren只有2個最低有效位保存在低位? – 2016-04-02 07:18:54