2009-06-30 26 views
142

Tôi đang gửi luồng tới các phương thức để viết và trong các phương pháp đó tôi đang sử dụng trình đọc/ghi dữ liệu nhị phân. Khi người đọc/nhà văn được xử lý, hoặc bằng using hoặc chỉ khi nó không được tham chiếu, thì luồng cũng đã đóng chưa?Không xử lý streamreader đóng luồng?

Tôi sẽ gửi một BinaryReader/Writer, nhưng tôi đang sử dụng một StreamReader quá (có lẽ tôi nên đi xung quanh đó. Tôi chỉ sử dụng cho GetLine và ReadLine). Điều này là khá rắc rối nếu nó đóng dòng mỗi lần một nhà văn/đọc được đóng lại.

Trả lời

166

Có, StreamReader, StreamWriter, BinaryReaderBinaryWriter tất cả đóng/hủy luồng cơ bản của chúng khi bạn gọi Dispose trên chúng. Họ không vứt bỏ luồng nếu người đọc/người viết chỉ là rác được thu thập - bạn luôn phải vứt bỏ người đọc/người viết, tốt nhất với tuyên bố using. (Trên thực tế, không có lớp nào trong số các lớp này có finalizers, cũng không phải họ nên có.)

Cá nhân tôi cũng muốn có tuyên bố sử dụng cho luồng đó. Bạn có thể tổ using báo cáo mà không cần niềng răng khá gọn gàng:

using (Stream stream = ...) 
using (StreamReader reader = new StreamReader(stream, Encoding.Whatever)) 
{ 
} 

Mặc dù tuyên bố using cho dòng là hơi dư thừa (trừ trường hợp nhà xây dựng StreamReader ném một ngoại lệ) Tôi coi đó là thực hành tốt nhất như sau đó nếu bạn thoát khỏi StreamReader và chỉ sử dụng luồng trực tiếp vào một ngày sau đó, bạn sẽ có ngữ nghĩa xử lý phù hợp.

+2

oh tốt, nó chỉ xảy ra khi gọi Vứt bỏ, không phải khi được cho là hoàn thiện. – Nefzen

+1

@Nefzen: Đó là bởi vì không có gì đảm bảo thứ tự các đối tượng của bạn sẽ được hoàn thành. Nếu cả StreamReader và Luồng cơ bản đều đủ điều kiện để hoàn thành, GC có thể hoàn tất luồng trước tiên - sau đó trình tạo luồng sẽ không có tham chiếu đến luồng. Vì lý do này, bạn chỉ có thể phát hành các tài nguyên không được quản lý bên trong một finalize (ví dụ, một FileStream đóng cửa sổ của nó xử lý trong finalize của nó). Oh, và tất nhiên, nếu bạn không bao giờ vứt bỏ, luồng vẫn sẽ được thu thập cuối cùng (và tập tin đã đóng). Nó chỉ là một thực tế rất xấu để không vứt bỏ một dòng. – JMarsch

+9

Làm tổ này làm cho trình phân tích mã VS khiếu nại: 'CA2202: Microsoft.Usage: Object 'stream' có thể được xử lý nhiều lần trong phương thức '...'. Để tránh tạo ra một System.ObjectDisposedException bạn không nên gọi Dispose nhiều hơn một thời gian trên một đối tượng.' Nếu đó chỉ là bỏ qua? Tôi đã không nhận được bất kỳ trường hợp ngoại lệ cho đến nay ... –

-3

luồng được xử lý bằng cách sử dụng từ khóa "đang sử dụng" hoặc gọi rõ ràng vứt bỏ một cách rõ ràng

27

Vâng, đúng vậy. Bạn có thể xác minh điều này bằng cách xem xét việc thực hiện với Reflector.

protected override void Dispose(bool disposing) 
{ 
    try 
    { 
     if ((this.Closable && disposing) && (this.stream != null)) 
     { 
      this.stream.Close(); 
     } 
    } 
    finally 
    { 
     if (this.Closable && (this.stream != null)) 
     {  
      this.stream = null;  
      this.encoding = null; 
      this.decoder = null; 
      this.byteBuffer = null; 
      this.charBuffer = null; 
      this.charPos = 0; 
      this.charLen = 0; 
      base.Dispose(disposing); 
     } 
    } 
} 
2

Có. Gọi Dispose() trên và IDisposable (mà "sử dụng" không) nên làm cho một đối tượng dọn sạch tất cả các tài nguyên của nó. Điều này bao gồm các luồng xả và đóng các bộ mô tả tệp của chúng.

Nếu, trong trường hợp của bạn, bạn muốn chuyển nó vào các phương pháp khác, thì bạn cần đảm bảo rằng những phương pháp đó không thực hiện việc đọc/ghi trong khối sử dụng.

1

Một cách dễ dàng để khắc phục điều này nếu bạn cần phải ghi đè lên các lớp StreamWriter Phương pháp vứt bỏ. Xem bài viết của tôi vào đây để đoạn code trên như thế nào để làm điều đó:

Does .Disposing a StreamWriter close the underlying stream?

31

Đây là một cái cũ, nhưng tôi muốn làm một cái gì đó tương tự như ngày hôm nay và thấy rằng mọi thứ đã thay đổi. Kể từ .net 4.5, có một đối số leaveOpen:

public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen) 

Vấn đề duy nhất là không rõ ràng những gì cần đặt cho các thông số khác. Dưới đây là một số giúp đỡ:

Từ the msdn page cho StreamReader Constructor (Stream):

constructor này khởi mã hóa để UTF8Encoding, tài sản BaseStream sử dụng tham số dòng, và nội bộ kích thước đệm 1024 byte.

Đó chỉ là lá detectEncodingFromByteOrderMarks mà đánh giá bởi the source codetrue

public StreamReader(Stream stream) 
     : this(stream, true) { 
} 

public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks) 
     : this(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize) { 
} 

Nó sẽ được tốt đẹp nếu một số những giá trị mặc định được tiếp xúc hoặc nếu đối số là tùy chọn để chúng ta chỉ có thể xác định những mà chúng tôi muốn.

+0

Thông tin rất hay! Không bao giờ nghe nói về tham số mới này và nó thực sự làm cho rất nhiều ý nghĩa. – julealgon

+0

Đã không nhận thấy sự bổ sung mới trong 4.5, cảm ơn bạn! – TimothyP

8

Sáu năm muộn nhưng có thể điều này có thể giúp ai đó.

StreamReader đóng kết nối khi nó được xử lý. Tuy nhiên, "sử dụng (Luồng luồng = ...) {...}" với StreamReader/StreamWriter có thể dẫn đến Luồng bị xử lý hai lần: (1) khi đối tượng StreamReader được xử lý (2) và khi luồng Sử dụng luồng đóng cửa. Điều này dẫn đến cảnh báo CA2202 khi chạy phân tích mã của VS.

Một giải pháp khác, được lấy trực tiếp từ trang CA2202, là sử dụng khối thử/cuối cùng. Thiết lập chính xác, điều này sẽ chỉ đóng kết nối một lần.

Gần cuối CA2202, Microsoft khuyến cáo sử dụng như sau:

Stream stream = null; 
try 
{ 
    stream = new FileStream("file.txt", FileMode.OpenOrCreate); 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     stream = null; 
     // Use the writer object... 
    } 
} 
finally 
{ 
    if(stream != null) 
     stream.Dispose(); 
} 

thay vì ...

// Generates a CA2202 warning 
using (Stream stream = new FileStream("file.txt", FileMode.Open)) 
using (XmlReader reader = new XmlReader (stream)) 
{ 
    // Use the reader object... 
} 
+2

Có điều này rất hữu ích với tôi, bây giờ 7 năm sau :) – Sebastian

+0

Cảnh báo cũng được thảo luận trong phần bình luận của câu trả lời được chấp nhận. Jon Skeet cung cấp một số lời khuyên ở đó. – Marcin

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