2009-05-05 19 views
7

Sau khi viết ra một số nội dung đã xử lý cho luồng đầu ra, tôi cần phải xem lại phần đầu của luồng và viết ra một số siêu dữ liệu nội dung. Dữ liệu tôi viết là rất lớn, nhiều như 4Gb, và có thể được ghi trực tiếp vào một tập tin hoặc một bộ đệm trong bộ nhớ, tùy thuộc vào các yếu tố môi trường khác nhau.Làm cách nào để triển khai OutputStream mà tôi có thể tua lại?

Làm cách nào để triển khai OutputStream cho phép tôi viết tiêu đề sau khi hoàn thành việc viết nội dung?

+0

Nó không đáng tiếc, nhưng đó là phần lớn vì tôi phải thay đổi thiết kế của mình do những cân nhắc khác. Nó vẫn là một câu trả lời hay. –

Trả lời

10

Đây là luồng đầu ra tệp truy cập ngẫu nhiên. Lưu ý rằng nếu sử dụng nó cho một lượng lớn đầu ra được truyền trực tiếp, bạn có thể tạm thời bọc nó trong BufferedOutputStream để tránh rất nhiều ghi nhỏ (chỉ cần chắc chắn xóa nó trước khi loại bỏ trình bao bọc hoặc sử dụng trực tiếp luồng bên dưới). Lưu ý:

import java.io.*; 

/** 
* A positionable file output stream. 
* <p> 
* Threading Design : [x] Single Threaded [ ] Threadsafe [ ] Immutable [ ] Isolated 
*/ 

public class RandomFileOutputStream 
extends OutputStream 
{ 

// ***************************************************************************** 
// INSTANCE PROPERTIES 
// ***************************************************************************** 

protected RandomAccessFile    randomFile;        // the random file to write to 
protected boolean      sync;         // whether to synchronize every write 

// ***************************************************************************** 
// INSTANCE CONSTRUCTION/INITIALIZATON/FINALIZATION, OPEN/CLOSE 
// ***************************************************************************** 

public RandomFileOutputStream(String fnm) throws IOException { 
    this(fnm,false); 
    } 

public RandomFileOutputStream(String fnm, boolean syn) throws IOException { 
    this(new File(fnm),syn); 
    } 

public RandomFileOutputStream(File fil) throws IOException { 
    this(fil,false); 
    } 

public RandomFileOutputStream(File fil, boolean syn) throws IOException { 
    super(); 

    File        par;         // parent file 

    fil=fil.getAbsoluteFile(); 
    if((par=fil.getParentFile())!=null) { IoUtil.createDir(par); } 
    randomFile=new RandomAccessFile(fil,"rw"); 
    sync=syn; 
    } 

// ***************************************************************************** 
// INSTANCE METHODS - OUTPUT STREAM IMPLEMENTATION 
// ***************************************************************************** 

public void write(int val) throws IOException { 
    randomFile.write(val); 
    if(sync) { randomFile.getFD().sync(); } 
    } 

public void write(byte[] val) throws IOException { 
    randomFile.write(val); 
    if(sync) { randomFile.getFD().sync(); } 
    } 

public void write(byte[] val, int off, int len) throws IOException { 
    randomFile.write(val,off,len); 
    if(sync) { randomFile.getFD().sync(); } 
    } 

public void flush() throws IOException { 
    if(sync) { randomFile.getFD().sync(); } 
    } 

public void close() throws IOException { 
    randomFile.close(); 
    } 

// ***************************************************************************** 
// INSTANCE METHODS - RANDOM ACCESS EXTENSIONS 
// ***************************************************************************** 

public long getFilePointer() throws IOException { 
    return randomFile.getFilePointer(); 
    } 

public void setFilePointer(long pos) throws IOException { 
    randomFile.seek(pos); 
    } 

public long getFileSize() throws IOException { 
    return randomFile.length(); 
    } 

public void setFileSize(long len) throws IOException { 
    randomFile.setLength(len); 
    } 

public FileDescriptor getFD() throws IOException { 
    return randomFile.getFD(); 
    } 

} // END PUBLIC CLASS 
2

Nếu bạn biết kích cỡ của tiêu đề, ban đầu bạn có thể viết tiêu đề trống, sau đó quay lại để sửa đầu trang với RandomAccessFile ở cuối. Nếu bạn không biết kích thước của tiêu đề thì bạn có một cơ sở mà các hệ thống tập tin nói chung không cho phép bạn chèn dữ liệu. Vì vậy, bạn cần phải ghi vào một tập tin tạm thời và sau đó viết các tập tin thực sự.

+0

Chúng tôi biết kích thước của tiêu đề, nhưng không có cách nào chúng tôi có thể tìm thấy để có một OuptutStream chung cho phép viết tại một điểm tùy ý trong luồng. –

+0

Bạn viết nó ra. Đóng tệp. Mở một RandomAccessFile. Viết tiêu đề. Đóng RandomAccessFile. –

+1

(Lưu ý rằng RandomAccessFile cho mỗi hoạt động hiệu suất hút, vì vậy sử dụng các hoạt động khối lớn.) –

0

Một cách sẽ được để viết nội dung ban đầu cho một bộ nhớ đệm đầu tiên, sau đó tiêu đề vào dòng đầu ra 'thực tế', tiếp theo là tuôn ra của đệm nội dung và từ đó chỉ ghi vào luồng không được đệm. Có vẻ như phân khúc ban đầu sẽ không kéo dài quá lâu, để làm cho bộ đệm hợp lý. Để thực hiện nó, bạn có thể sử dụng ByteArrayOutputStream để đệm, và sau đó có lớp OutputStream của bạn lấy dòng đầu ra "thực" làm đối số; và chỉ cần chuyển đổi giữa hai khi cần thiết. Bạn có thể cần mở rộng API OutputStream để cho phép xác định siêu dữ liệu để viết là gì, vì trình kích hoạt đó chuyển đổi từ chế độ đệm.

Như đã đề cập trong câu trả lời khác, RandomAccessFile cũng sẽ hoạt động, mặc dù sẽ không triển khai OutputStream.

+1

"Dữ liệu tôi đang viết là rất lớn, nhiều như 4Gb" – DJClayworth

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