2013-07-17 1 views
1

Stream 매개 변수를 허용하는 유틸리티 메소드에서 나는 데이터를 분석하기 위해 StreamReader에 의존합니다.범위에서 정의 된 스트림을 읽는 StreamReader를 삭제 하시겠습니까?

내 방법으로 들어오는 스트림을 닫고 싶지 않습니다. 나는 호출자 메소드가 스트림을 처리하기로 결정할 수 있도록하고 싶다.

열린 상태로 처분하지 않는 것이 안전합니까? StreamReader? 내 말은 결국 자동적으로 처분 될 것인가? 메모리 누수가 발생합니까?

여기 내 유틸리티 방법입니다. 그것의 목표는 관계없이 데이터를 인코딩하는 방법, 스트림을 읽고 문자열로 내용을 반환하는 것입니다 :

public static string GetStringAutoDetectEncoding(Stream data, out Encoding actualEncoding) 
    { 
     // 1. Is there a Bye Order Mask ? 
     var candidateEncoding = DetectEncodingWithByteOrderMask(data); 

     // 2a. No BOM, the data is either UTF8 no BOM or ANSI 
     if (candidateEncoding == Encoding.Default) 
     { 
      var utf8NoBomEncoding = Encoding.GetEncoding("utf-8",new EncoderExceptionFallback(), new DecoderExceptionFallback()); 

      var positionBackup = data.Position; 
      var sr = new StreamReader(data, utf8NoBomEncoding); 
      try 
      { 
       // 3. Try as UTF8 With no BOM 
       var result = sr.ReadToEnd(); // will throw error if not UTF8 
       actualEncoding = utf8NoBomEncoding; // Probably an UTF8 no bom string 
       return result; 
      } 
      catch (DecoderFallbackException) 
      { 
       // 4. Rewind the stream and fallback to ASNI 
       data.Position = positionBackup; 
       var srFallback = new StreamReader(data, candidateEncoding); 
       actualEncoding = candidateEncoding; 
       return srFallback.ReadToEnd(); ; 
      } 
     } 
     // 2b. There is a BOM. Use the detected encoding 
     else 
     { 
      var sr = new StreamReader(data, candidateEncoding); 
      actualEncoding = candidateEncoding; 
      return sr.ReadToEnd(); ; 
     } 
    } 

그럼,이 같은 몇 가지 방법이 있습니다 :

void Foo(){ 
    using(var stream = File.OpenRead(@"c:\somefile")) { 
     Encoding detected; 
     var fileContent = MyUtilityClass.GetStringAutoDetectEncoding(stream, detected); 

     Console.WriteLine("Detected encoding: {0}", encoding); 
     Console.WriteLine("File content: {0}", fileContent); 
    } 
} 

답변

1

을 클로저를 사용하여 제어를 반전시킬 수 있습니다. 즉, 메소드 내에서 스트림 열기/닫기를 담당하는

// This method will open the stream, execute the streamClosure, and then close the stream. 
public static String StreamWork(Func<Stream, String> streamClosure) { 
    // Set up the stream here. 
    using (Stream stream = new MemoryStream()) { // Pretend the MemoryStream is your actual stream. 

     // Execute the closure. Return it's results. 
     return streamClosure(stream); 
    } 
} 

과 같은 메소드를 작성하십시오.

그러면 스트림을 필요로하는 모든 코드를 Func<Stream, String> 클로저로 마무리하고 전달합니다. StreamWork 메서드는 스트림을 열고 코드를 실행 한 다음 스트림을 닫습니다. 아래의 코멘트에 언급 한 바와 같이 물론

public static void Main() 
{ 
    // Wrap all of the work that needs to be done in a closure. 
    // This represents all the work that needs to be done while the stream is open. 
    Func<Stream, String> streamClosure = delegate(Stream stream) { 
     using (StreamReader streamReader = new StreamReader(stream)) { 
      return streamReader.ReadToEnd(); 
     } 
    }; 

    // Call StreamWork. This method handles creating/closing the stream. 
    String result = StreamWork(streamClosure); 
    Console.WriteLine(result); 
    Console.ReadLine(); 
} 

UPDATE

는 반전이 방법은 취향의 문제이다. 중요한 점은 GC가 클린업 할 때까지 스트림이 닫히는 것을 방지하는 것입니다 (IDisposable을 구현하는 모든 요소가 그런 종류의 상황을 피하기위한 것이므로). 이것은 Stream을 입력으로 받아들이는 라이브러리 함수이기 때문에, method-consumer가 스트림을 생성 할 것이므로 여러분이 지적한대로 결국 스트림을 닫아야 할 책임이 있습니다. 그러나 정리가 절대적으로 이루어 지는지 걱정해야하는 민감한 리소스의 경우 역전은 때때로 유용한 기술입니다.

+0

사실 내 유틸리티 메소드는 일반적인 용도의 라이브러리이지만 스트림을 여는 것은 내 프로그램에 있습니다. StreamReader의 논리가 프로그램으로 옮겨지면 코드 스 니펫을 이해할 수 없습니다. –

+0

동기 부여는 기본적으로 스트림을 열고 닫는 실제 작업을 처리하는 별도의 메서드를 갖는 것이지만 실제 작업은 스트림이 열려있는 동안 수행해야하는 작업은 별도로 정의되고 전달됩니다. 이렇게하면 스트림이 다른 메소드로 '누출'하지 않아도됩니다. GC가 주변에 올 때마다 스트림을 닫는 것이 좋지 않은 것처럼 보입니다. 그리고 물론'StreamReader'도'StreamWork' 함수에 재 배열 할 수 있습니다. 핵심은 메서드에서 스트림을 누출하지 않는다는 것입니다. – sircodesalot

+0

질문을 다시 읽었을 때 책임을 뒤집을 수 있다고 생각합니다. (내 업데이트 질문 참조). 사실, 내가 당신의 지시에 따라 간다면, 나는 (프로그램에서) 다음과 같이 끝날 것이다 :'var withOpenedStream = new Action > (a => {using (var stream = File.OpenRead (@ "c : \ temp.txt ")) {a (stream);}); MyUtility.GetStringAutoDetectEncoding (withOpenedStream, stream); 그리고 메서드 자체 : void GetStringAutoDetectEncoding (액션 <액션 > a, 스트림 s) {var 프로세스 = 새 액션 ((스트림) =>/* 스트림을 처리합니다. a (과정); }'. 꽤 못생긴 –

0

StreamReader Dispose를 호출 할 때만 기본 스트림을 닫거나 처리합니다. 리더/라이터가 가비지 수집 된 경우 스트림을 처리하지 않습니다.

+0

내가 말한 것을 반복하고 있습니다. 안전한지 모르겠습니다. –

관련 문제