2009-02-26 38 views
27

Sau khi cung cấp một số câu trả lời ở đây và đọc một số nhận xét, có vẻ như, trong thực tế, IOException không bao giờ được ném khi đóng cho tệp I/O.Có bao giờ ném một IOException?

Có trường hợp nào trong đó việc gọi gần trên luồng/Trình đọc/Writer thực sự đưa ra một IOException không?

Nếu ngoại lệ thực sự bị ném, nó nên được xử lý như thế nào?

Trả lời

12

Đối với tệp, bạn có thể không thấy IOException được ném thường xuyên trên close(), nhưng bạn chắc chắn sẽ thấy nó cho không phải tệp I/O như đóng socket vào mạng.

Here's an example của lỗi Java khi đóng socket UDP cuối cùng đã khiến IOException bị ném.

+0

yup, bất cứ điều gì có thể "biến mất" đều có thể khiến điều đó xảy ra. Một vụ tai nạn ổ đĩa cứng có thể có thể làm điều đó quá. – TofuBeer

27

Tôi đã tìm thấy hai trường hợp:

  • Mất kết nối mạng khi vẫn còn dữ liệu trong bộ đệm để được rửa.
  • Có hệ thống tệp lấp đầy (hoặc đạt đến giới hạn người dùng của bạn cho kích thước tệp) khi vẫn còn dữ liệu trong bộ đệm bị xóa.

Cả hai ví dụ này đều phụ thuộc vào điều gì đó xảy ra khi vẫn còn dữ liệu trong bộ đệm. Đóng xóa bộ đệm trước khi tệp đóng, vì vậy nếu có lỗi ghi dữ liệu vào tệp, nó sẽ phát ra một IOException.

Nếu bạn thực thi mã sau, hãy truyền tên của tệp để tạo trên ổ đĩa mạng, sau đó nhấn phím enter để rút cáp mạng, nó sẽ làm cho chương trình đưa ra một IOException.

import java.io.File; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.io.Writer; 

public class Test 
{ 
    public static void main(final String[] argv) 
    { 
     final File file; 

     file = new File(argv[0]); 
     process(file); 
    } 

    private static void process(final File file) 
    { 
     Writer writer; 

     writer = null; 

     try 
     { 
      writer = new FileWriter(file); 
      writer.write('a'); 
     } 
     catch(final IOException ex) 
     { 
      System.err.println("error opening file: " + file.getAbsolutePath()); 
     } 
     finally 
     { 
      if(writer != null) 
      { 
       try 
       { 
        try 
        { 
         System.out.println("Please press enter"); 
         System.in.read(); 
        } 
        catch(IOException ex) 
        { 
         System.err.println("error reading from the keyboard"); 
        } 

        writer.close(); 
       } 
       catch(final IOException ex) 
       { 
        System.err.println("See it can be thrown!"); 
       } 
      } 
     } 
    } 
} 

Kể từ Java 7 bạn có thể sử dụng thử-với-nguồn lực để thoát ra khỏi mớ hỗn độn này (không xoá mã thế hệ ngoại lệ rõ ràng cho sự vận hành close()):

private static void process(final File file) { 
    try (final Writer writer = new FileWriter(file)) { 
     writer.write('a'); 
    } catch (final IOException e) { 
     // handle exception 
    } 
} 

này sẽ tự kỳ diệu xử lý các ngoại lệ trong close() và nó thực hiện kiểm tra rõ ràng null nội bộ.

+0

Hãy vui vẻ với huy hiệu đó mà bạn chuẩn bị nhận ;-) –

+0

lol - cảm ơn. Đã phải đi tìm những gì nó đã được :-) – TofuBeer

+3

java có thể được thực sự xấu xí đôi khi ... – jmq

16

Khi điều đó xảy ra, nó sẽ được xử lý giống như bất kỳ số nào khác IOException, không bị bỏ qua âm thầm như bạn thường xuyên được đề xuất. Giả sử là, tôi đoán, rằng kể từ khi bạn đang thực hiện bằng cách sử dụng các dòng, nó không quan trọng nếu nó đã được làm sạch đúng cách.

Tuy nhiên, việc dọn dẹp đúng cách là điều quan trọng. Nếu hoạt động close() làm tăng ngoại lệ, có khả năng nó liên quan đến một số đầu ra, cam kết một số giao dịch (trong trường hợp kết nối cơ sở dữ liệu mà bạn nghĩ là chỉ đọc), v.v. — chắc chắn không phải là điều bị bỏ qua. Và, vì nó là hiếm, bạn không ảnh hưởng đáng kể độ tin cậy của ứng dụng của bạn đáng kể bằng cách hủy bỏ hoạt động.

+0

Ước gì tôi có thể chấp nhận hai câu trả lời. – TofuBeer

+3

Có, nhưng nếu bạn chỉ mở tệp để đọc thì sao? Sau đó, vấn đề xả nước hoặc cam kết không áp dụng. – sleske

+1

Một số hình thức "cam kết" có thể áp dụng, ví dụ như việc giải phóng khóa. Tôi đồng ý rằng sẽ rất ngạc nhiên khi thấy một ngoại lệ được nêu ra khi đóng bất kỳ loại tài nguyên "chỉ đọc" nào ... đây sẽ là một sự kiện hiếm hoi mà tôi chắc chắn muốn đăng nhập nó. Bỏ qua nó với một khối catch rỗng sẽ không cải thiện chất lượng của chương trình. – erickson

3

Kiểm tra những gì có thể xảy ra khi gọi gần, cách ẩn ngoại lệ có thể ảnh hưởng đến bạn và những gì bạn có thể thực hiện: blog post.

5

Cụ thể là FileInputStream.close không bị ném, ngay cả khi ổ đĩa cứng của bạn đang cháy. Có lẽ nó là như nhau cho đầu vào socket. Đối với các luồng đầu ra, bạn cũng có thể đang xả.Cho đến tương đối gần đây [xem timestamps] BufferedOutputStream được sử dụng để không đóng luồng cơ bản nếu flush bị ném.

(@MaartenBodewes muốn tôi chỉ ra rằng FileInputStream.close không ném không được chỉ định bởi các tài liệu API. Tại thời điểm bài đăng, thông lệ đề cập đến điều này liên quan đến JDK mặt trời (bây giờ được gọi là Oracle JDK và OpenJDK). Có vẻ như một quá trình reimplementation cũ được gọi là Apache Harmony mà Android được sử dụng để sử dụng có thể có hành vi khác nhau. Các triển khai khác có khả năng hoặc các phiên bản OpenJDK cũng có thể bị ném.)

+0

+1 cho "ngay cả khi ổ đĩa cứng của bạn đang cháy". Tôi muốn thấy rằng trong tài liệu Java, "ném một IOException nếu đĩa cứng của bạn đang cháy";) – aioobe

+0

API được xuất bản tuy nhiên không hứa hẹn như vậy: http://download.oracle.com/javase/6/docs /api/java/io/FileInputStream.html#close%28%29 – Raedwald

+0

@Raedwald Thật vậy. Câu hỏi đặt ra là "trong thực tế". –

1

Tôi cũng đã nhận thấy rằng PrintWriter thậm chí không có một điều khoản ném ....

+1

Tuy nhiên, nó có một cách để kiểm tra nếu một lỗi đã xảy ra. –

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