2010-04-12 64 views
17

Tôi đang cố gắng đọc số dòng trong tệp nhị phân bằng cách sử dụng readObject, nhưng tôi nhận được IOException EOF. Tôi có làm điều này đúng không?Java FileInputStream ObjectInputStream đến cuối tệp EOF

FileInputStream istream = new FileInputStream(fileName); 
    ObjectInputStream ois = new ObjectInputStream(istream); 

    /** calculate number of items **/ 
    int line_count = 0; 
    while((String)ois.readObject() != null){    
     line_count++; 
    } 
+0

Tôi đang làm điều tương tự - nhưng tôi đang điều chỉnh nhật ký hoạt động. Tôi muốn nó đợi cho đến khi có nhiều dữ liệu hơn miễn là chương trình đang viết, nhưng hãy cho tôi biết khi nào nó được viết xong. Tôi không chắc chắn nếu có bất kỳ cách nào để làm điều này mà không bị bắt ngoại lệ. (Phần tailing hoạt động tốt, nó chỉ nhận được nó để thoát khi nó được thực hiện đó là bugging tôi) –

Trả lời

22

readObject() không trả lại null tại EOF. Bạn có thể bắt các EOFException và giải thích nó như EOF, nhưng điều này sẽ không phát hiện phân biệt EOF bình thường từ một tập tin đã được cắt ngắn.

Cách tiếp cận tốt hơn là sử dụng một số siêu dữ liệu. Tức là, thay vì yêu cầu ObjectInput số lượng đối tượng trong luồng, bạn nên lưu trữ số lượng ở đâu đó. Ví dụ, bạn có thể tạo một lớp siêu dữ liệu ghi lại số đếm và siêu dữ liệu khác và lưu trữ một cá thể làm đối tượng đầu tiên trong mỗi tệp. Hoặc bạn có thể tạo một lớp đánh dấu EOF đặc biệt và lưu trữ một cá thể làm đối tượng cuối cùng trong mỗi tệp.

+3

Nếu 'đối tượng' cuối cùng được ghi vào luồng là 'null', thì bạn sẽ đọc tham chiếu' null'. Nó là bình thường đối với 'null' là một phần của dạng nối tiếp, và có một đại diện đặc biệt cho nó ở định dạng nối tiếp. Một 'null' ở cuối, hoặc một số sentinel khác, là sạch hơn nhiều mà đếm. –

+0

Cảm ơn tôi vừa viết null sau khi tất cả các nội dung để tín hiệu nơi kết thúc của tập tin được. Nó làm việc hoàn hảo. – user69514

+0

Nhưng nó không thực hiện điều đó, trừ khi bạn cho rằng bạn chưa bao giờ viết một null tại bất kỳ điểm nào khác. Câu trả lời * đúng * là bắt EOFException và sử dụng * that * để chấm dứt vòng lặp. – EJP

0

Không, bạn cần biết có bao nhiêu đối tượng trong tệp nhị phân. Bạn có thể viết số lượng đối tượng ở đầu tệp (ví dụ bằng cách sử dụng writeInt) và đọc nó trong khi tải nó.

Một tùy chọn khác là gọi ois.available() và vòng lặp cho đến khi nó trả về 0. Tuy nhiên, tôi không chắc chắn nếu điều này là 100% chắc chắn.

+0

'Không, bạn cần biết có bao nhiêu đối tượng trong tệp nhị phân'. Không bạn không. 'Tôi không chắc chắn nếu điều này là 100% chắc chắn.' Nó không phải là. Có một tuyên bố cụ thể trong Javadoc về điều đó. – EJP

0

Có vẻ như vấn đề là với dữ liệu bạn đã viết. Giả sử dữ liệu được viết như mong đợi bởi mã này, không có vấn đề gì.

(Tôi thấy bạn đang đọc String s. ObectInputStream Đây không phải là để đọc các file văn bản. Sử dụng InputStreamReaderBufferedReader.readLine cho điều đó. Tương tự, nếu bạn đã viết các tập tin với DataOutputSteam.writeUTF, đọc nó với DataInputStream.readUTF)

+2

Không đúng. EOFException là bình thường, và trừ khi ông đã viết một null không có lý do để chấm dứt vòng lặp tại null vì vậy vòng lặp của ông là sai. – EJP

+0

@EJP Bạn làm gì? Tại sao không một 'null' được viết nếu một' null' được dự kiến ​​sẽ được đọc? –

+0

Đó chính xác là quan điểm của tôi. Nếu bạn muốn một null được đọc, viết một null. Nếu bạn muốn bắt được EOFException, hãy đóng luồng. Đây là hai hành động khác nhau. Conflating chúng không phục vụ mục đích hữu ích. – EJP

6

Không Catch EOFException và sử dụng nó để chấm dứt vòng lặp.

+1

Làm thế nào chính xác là nó nguy hiểm? Chương và câu xin vui lòng. Trong mọi trường hợp như tôi đã nói ở đây, bạn không có cách nào khác, trừ khi bạn viết 'null' vào ObjectOutputStream, trong trường hợp này bạn đang xóa tất cả các cách sử dụng hữu ích khác của hành động đó. – EJP

+4

Tom 1. Vui lòng ngừng vướng và trả lời câu hỏi. Hãy cho chúng tôi biết chính xác những gì 'nguy hiểm' về việc này: bắt (EOFException exc) { ngắt; } 2. Vui lòng cho chúng tôi biết cách đọc toàn bộ ObjectInputStream mà không bắt EOFException và không hạn chế người viết luồng đó về cách thực hiện. Bạn không thể. Nó không thể được thực hiện. EOFException là cơ chế duy nhất. – EJP

-1

Cách tốt nhất có thể để kết thúc vòng lặp có thể được thực hiện bằng cách thêm một đối tượng null vào cuối. Trong khi đọc đối tượng null có thể được sử dụng như một điều kiện biên để thoát khỏi vòng lặp. Việc nắm bắt EOFException cũng giải quyết được mục đích nhưng chỉ mất vài m

+4

câu trả lời của bạn có vẻ không đầy đủ, câu cuối cùng không hoàn thành – oers

+0

Và những gì bạn đã viết cho đến nay là không chính xác, vì nó làm cho nó không thể viết null ở bất kỳ nơi nào khác. – EJP

0

Phương thức có sẵn của ObjectInputStream không thể sử dụng để chấm dứt vòng lặp vì nó trả về 0 ngay cả khi có đối tượng được đọc trong tệp. Viết một null vào một tập tin doen't dường như là một giải pháp tốt vì các đối tượng có thể là null mà sau đó sẽ được hiểu là phần cuối của tệp. Tôi nghĩ rằng việc bắt EOFException để chấm dứt vòng lặp là một thực hành tốt hơn vì nếu EOFException xảy ra (hoặc vì bạn đã đến cuối tập tin hoặc một số lý do khác), bạn phải chấm dứt vòng lặp anyway.

+0

Phương thức 'available()' không thể được sử dụng cho mục đích này * bởi vì đó không phải là những gì nó cho. * Xem Javadoc. – EJP

18

Tôi đã có cùng một vấn đề ngay hôm nay. Mặc dù câu hỏi là khá cũ, vấn đề vẫn còn và không có giải pháp sạch được cung cấp. Bỏ qua EOFException nên tránh vì nó có thể bị ném khi một số đối tượng không được lưu chính xác. Viết null rõ ràng ngăn cản bạn sử dụng các giá trị null cho bất kỳ mục đích nào khác. Cuối cùng, sử dụng available() trên luồng đối tượng luôn trả về số không, vì số lượng đối tượng không xác định.

Giải pháp của tôi khá đơn giản. ObjectInputStream chỉ là trình bao bọc cho một số luồng khác, chẳng hạn như FileInputStream. Mặc dù ObjectInputStream.available() trả về 0, FileInputStream.available sẽ trả về một số giá trị.

FileInputStream istream = new FileInputStream(fileName); 
    ObjectInputStream ois = new ObjectInputStream(istream); 

    /** calculate number of items **/ 
    int line_count = 0; 
    while(istream.available() > 0) // check if the file stream is at the end 
    { 
     (String)ois.readObject(); // read from the object stream, 
            // which wraps the file stream 
     line_count++; 
    } 
+0

Điều này chỉ hoạt động nếu ObjectInputStream không thực hiện bất kỳ bộ đệm nào. Đây có phải là trường hợp không? Javadoc không nói gì về điều này. –

+0

có sẵn() không phải là thử nghiệm hợp lệ cho cuối luồng. Xem Javadoc. – EJP

+0

cách này được cho là giúp đỡ như thế nào? một phương thức gọi, 'ois.readObject()', mà ném lỗi, sẽ vẫn được gọi trong ví dụ của bạn và do đó sẽ ném một lỗi. ít nhất, nó không hoạt động đối với tôi ..:/ – Blauhirn

1

Thật lạ khi API không cung cấp giải pháp thanh lịch hơn cho điều này.Tôi đoán các EOFException sẽ làm việc nhưng tôi đã luôn luôn được khuyến khích để xem ngoại lệ như các sự kiện bất ngờ trong khi ở đây bạn thường sẽ mong đợi các dòng đối tượng để đi đến một kết thúc.

Tôi cố gắng để làm việc xung quanh này bằng cách viết một loại "đánh dấu" đối tượng để biểu thị sự kết thúc của dòng đối tượng:

import java.io.Serializable; 

public enum ObjectStreamStatus implements Serializable { 
    EOF 
} 


Sau đó, trong đoạn code đọc đối tượng i kiểm tra cho đối tượng EOF này trong đối tượng đọc vòng lặp.

+1

API * không thể * cung cấp một 'giải pháp thanh lịch hơn thế này'. Cần có kết quả ngoài băng. Một ngoại lệ là khả năng duy nhất. – EJP

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