스트림 리더를 폐기하면 스트림이 닫히나요?


166

쓰려는 메소드에 스트림을 보내고 있으며,이 메소드에서는 이진 리더 / wrtier를 사용하고 있습니다. 리더 / 라이터가 처리 using되지 않거나 참조되지 않은 경우 스트림도 닫힙니 까?

BinaryReader / Writer를 보내려고하지만 StreamReader도 사용하고 있습니다. 라이터 / 리더가 닫힐 때마다 스트림을 닫으면 상당히 번거 롭습니다.

답변:


204

예, StreamReader, StreamWriter, BinaryReader그리고 BinaryWriter당신이 호출 할 때 모든 가까운 / 자신의 기본 스트림을 처리 Dispose그들. 그들은 하지 않는 리더 / 라이터가 단지 쓰레기 불구 수집하는 경우 스트림 처분 - 당신이해야 항상 처분 리더 / 라이터의, 양호하게는 A의 using문. (실제로이 클래스 중 어느 것도 마무리 요소를 갖지 않아야합니다.)

개인적으로 나는 스트림에 대한 using 문을 선호합니다. using중괄호없이 명령문을 깔끔하게 중첩 할 수 있습니다 .

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

using스트림에 대한 문장이 약간 중복되어 있지만 ( StreamReader생성자가 예외를 throw 하지 않는 한 ) 나는 그것을 제거 StreamReader하고 나중에 스트림을 직접 사용하는 것이 가장 좋은 방법이라고 생각합니다. 의미론.


2
오, 좋을 것입니다. Dispose를 호출 할 때만 발생합니다.
Nefzen 2016 년

1
@Nefzen : 객체가 어떤 순서로 마무리되는지 보장 할 수 없기 때문입니다. StreamReader와 기본 스트림이 모두 최종화 대상인 경우 GC가 먼저 스트림을 마무리 할 수 ​​있습니다. 그러면 스트림 리더에서 스트림에 대한 참조가 없습니다. 따라서 종료시에는 관리되지 않는 리소스 만 해제 할 수 있습니다 (예 : FileStream은 종료시 Windows 파일 핸들을 닫음). 물론 폐기하지 않으면 스트림은 결국 수집되고 파일은 닫힙니다. 스트림을 처리하지 않는 것은 매우 나쁜 습관입니다.
JMarsch 2016 년

13
이 중첩은 VS 코드 분석기가 불평하게합니다. CA2202 : Microsoft.Usage : Object 'stream' can be disposed more than once in method '...'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.그냥 무시해야합니까? 나는 지금까지 예외를 얻지 못했습니다 ...
HB

15
@ HB :이 경우 무시하는 것이 안전합니다. 또는에 대한 생성자 호출에서 스트림을 만들 수 있습니다 StreamReader. IDisposable.Dispose" 문서 의 Dispose 메서드가 두 번 이상 호출되면 개체는 첫 번째 호출 이후의 모든 호출을 무시해야합니다. Dispose 메서드가 다음과 같은 경우 예외를 throw하면 안됩니다. 여러 번 호출했습니다. "
Jon Skeet

5
@ JonSkeet : 실제로 이것에 대한 페이지가 있습니다 , 당신은 맞습니다, 이것은 가짜입니다 :)
HB

45

이것은 오래된 것이지만 오늘 비슷한 일을하고 싶었고 일이 바뀌 었다는 것을 알았습니다. .net 4.5부터는 leaveOpen인수가 있습니다.

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

유일한 문제는 다른 매개 변수에 대해 무엇을 설정해야하는지 명확하지 않다는 것입니다. 도움이 필요합니다 :

에서 은 MSDN 페이지 에서는 StreamReader 생성자 (스트림)에 대한 :

이 생성자는 UTF8Encoding, stream 매개 변수를 사용하는 BaseStream 속성 및 내부 버퍼 크기를 1024 바이트로 인코딩을 초기화합니다.

그건 단지 잎 detectEncodingFromByteOrderMarks으로 판단 소스 코드 입니다true

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

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

이러한 기본값 중 일부가 노출되었거나 인수가 선택적인 경우 원하는 값을 지정할 수 있으면 좋을 것입니다.


아주 좋은 정보! 이 새로운 매개 변수에 대해 들어 본 적이 없으며 실제로 많은 의미가 있습니다.
julealgon

3
나와 같은 게으른 사람들에게 스트림을 열어 두는 짧은 대답은 다음과 같습니다.using (var streamReader = new StreamReader(myStream, Encoding.UTF8, true, 1024, true))
beawolf

29

그렇습니다. 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);
        }
    }
}

13

6 년 늦었지만 어쩌면 이것은 누군가를 도울 수 있습니다.

StreamReader는 연결이 끊어 질 때 연결을 닫습니다. 그러나 "StreamStream = ...) {...}"을 StreamReader / StreamWriter와 함께 사용하면 Stream이 두 번 처리 될 수 있습니다. 닫힙니다. VS의 코드 분석을 실행할 때 CA2202 경고가 발생합니다.

CA2202 에서 직접 가져온 다른 솔루션 페이지 은 try / finally 블록을 사용하는 것입니다. 올바르게 설정하면 연결이 한 번만 닫힙니다.

CA2202 하단 근처에서 다음을 사용하는 것이 좋습니다.

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

대신에...

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

2
경고는 수락 된 답변의 의견에서도 논의됩니다. Jon Skeet가 이에 대한 조언을 제공합니다.
Marcin

또한 using 문은 실제로 컴파일러에서 try-finally 블록으로 변환됩니다.
Jason Kelley

2

예. Dispose ()를 호출하고 IDisposable을 "사용"하면 개체가 모든 리소스를 정리해야합니다. 여기에는 파일 디스크립터를 비우고 닫는 스트림이 포함됩니다.

귀하의 경우 다른 방법으로 전달하려면 해당 방법이 using 블록에서 읽기 / 쓰기를 수행하지 않아야합니다.



당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.