2010-11-18 31 views
5

Để đọc/ghi các tệp nhị phân, tôi đang sử dụng DataInputStream/DataOutputStream, chúng có phương thức writeByte()/readByte(), nhưng những gì tôi muốn làm là đọc/ghi bit? Có thể không?Có thể đọc/ghi các bit từ một tệp bằng JAVA không?

Tôi muốn sử dụng thuật toán nén, vì vậy khi tôi nén tôi muốn viết 3 bit (cho một số và có hàng triệu số như vậy trong tệp) và nếu tôi viết một byte vào mọi lúc tôi cần để viết 3 bit, tôi sẽ ghi các tải dữ liệu thừa ...

Trả lời

5

Không thể đọc/ghi từng bit một cách trực tiếp, đơn vị nhỏ nhất bạn có thể đọc/ghi là một byte.

Bạn có thể sử dụng các toán tử chuẩn bitwise để thao tác một byte mặc dù, ví dụ: để có được 2 bit thấp nhất của một byte, bạn muốn làm

byte b = in.readByte(); 
byte lowBits = b&0x3; 

thiết lập thấp 4 bit là 1, và viết các byte:

b |= 0xf; 
out.writeByte(b); 

(Lưu ý, vì lợi ích của hiệu quả bạn có thể muốn đọc/ghi mảng byte và byte không đơn)

+0

Dường như tôi sẽ phải đọc/ghi byte và tìm hiểu các hoạt động bit ... Cảm ơn mọi người vì câu trả lời ... –

+0

Cảm ơn bạn, cho điểm hiệu quả ... –

+0

Bởi anding b and 0x3, aren 't chỉ có 2 bit quan trọng nhất được bảo tồn trong lowbits? –

2

InputStreams và OutputStream là các luồng byte.

Để đọc một chút, bạn cần phải đọc một byte và sau đó sử dụng thao tác bit để kiểm tra các bit bạn quan tâm. Tương tự như vậy, để viết bit, bạn sẽ cần phải viết các byte chứa các bit bạn muốn.

3

Có và không. Trên hầu hết các máy tính hiện đại, byte là bộ nhớ nhỏ nhất có thể định địa chỉ, do đó bạn chỉ có thể đọc/ghi toàn bộ byte tại một thời điểm. Tuy nhiên, bạn luôn có thể sử dụng các toán tử bitwise để thao tác các bit trong một byte.

1

Các bit được đóng gói theo byte và ngoài VHDL/Verilog Tôi không thấy ngôn ngữ nào cho phép bạn chắp thêm từng bit vào luồng. Cache lên các bit của bạn và đóng gói chúng thành một byte để ghi bằng cách sử dụng một bộ đệm và bitmasking. Làm ngược lại để đọc, tức là giữ một con trỏ trong bộ đệm của bạn và tăng nó khi bạn trả về các bit mặt nạ riêng lẻ.

1

Afaik không có chức năng để thực hiện việc này trong API Java. Tuy nhiên, bạn có thể đọc một byte và sau đó sử dụng các chức năng thao tác bit. Cùng đi viết.

1

chuyển đến https://github.com/jinahya/bit-io

Hãy xem tại http://jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/bit-io/src/main/java/com/googlecode/jinahya/io/

<dependency> 
    <!-- resides in central repo --> 
    <groupId>com.googlecode.jinahya</groupId> 
    <artifactId>bit-io</artifactId> 
    <version>1.0-alpha-13</version> 
</dependency> 

Đây là thư viện tiện dụng nhỏ để đọc/ghi chiều dài bit tùy ý với 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 
4

Không có cách nào để thực hiện trực tiếp. Các máy tính đơn vị nhỏ nhất có thể xử lý là một byte (thậm chí booleans mất một byte). Tuy nhiên bạn có thể tạo một lớp dòng tùy chỉnh gói một byte với các bit bạn muốn rồi viết nó. Sau đó, bạn có thể tạo ra một trình bao bọc cho lớp này, chức năng ghi của nó có một số kiểu không thể tách rời, kiểm tra rằng nó nằm trong khoảng từ 0 đến 7 (hoặc -4 và 3 ... hoặc bất kỳ thứ gì), trích xuất các bit theo cùng cách với lớp BitInputStream (bên dưới) và thực hiện các cuộc gọi tương ứng với phương thức ghi của BitOutputStream. Bạn có thể nghĩ rằng bạn chỉ có thể làm cho một bộ các lớp dòng IO, nhưng 3 không đi vào 8 đồng đều.Vì vậy, nếu bạn muốn hiệu quả lưu trữ tối ưu và bạn không muốn làm việc thực sự khó khăn, bạn đang loại mắc kẹt với hai lớp trừu tượng. Dưới đây là một lớp BitOutputStream, một lớp BitInputStream tương ứng và một chương trình đảm bảo chúng hoạt động.

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(); 
    } 

} 

Tôi chắc chắn có cách để đóng gói int với các nhà khai thác bit-khôn ngoan và do đó tránh phải đảo ngược đầu vào, nhưng tôi không nghĩ gì khó.

Ngoài ra, bạn có thể nhận thấy rằng không có cách nào địa phương để phát hiện rằng các bit cuối cùng đã được đọc trong việc thực hiện điều này, nhưng tôi thực sự không muốn nghĩ rằng cứng.

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(); 
    } 

} 

Bạn có thể biết điều này, nhưng bạn nên đặt BufferedStream vào giữa BitStream và FileStream của bạn hoặc sẽ mất vĩnh viễn.

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."); 
    } 

} 
+0

Bạn phải biết rằng nếu số bit không phải là bội số của 8, byte cuối cùng sẽ được hoàn thành với các số không. Nó có thể gây ra một số lỗi nếu nó không được xử lý. – Gregory

0

Mã dưới đây nên làm việc

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(); 
    } 
0

Nếu bạn chỉ viết bit vào một tập tin, Java BitSet class có thể là đáng xem. Từ javadoc:

Lớp này thực hiện một vectơ các bit phát triển khi cần. Mỗi thành phần của bộ bit có giá trị boolean. Các bit của một BitSet được lập chỉ mục bởi các số nguyên không âm. Các bit được lập chỉ mục riêng lẻ có thể được kiểm tra, thiết lập hoặc xóa. Một BitSet có thể được sử dụng để sửa đổi nội dung của một BitSet khác thông qua các phép toán logic AND, OR, OR, và OR độc quyền.

Bạn có thể chuyển đổi BitSets thành long [] và byte [] để lưu dữ liệu vào tệp.

+0

cách 'BitSet' có liên quan ở đây? –

Các vấn đề liên quan