在接受Stream
参数的实用程序方法中,我依靠某些StreamReader
来分析数据。
我不想在我的方法中关闭传入的流。我想让调用者方法决定处理流。
不处理已打开的StreamReader
是否安全?我的意思是,它最终会被自动处理吗?它会导致内存泄漏吗?
这是我的实用方法。它的目标是读取一个Stream,并将其内容作为字符串返回,无论数据如何编码:
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);
}
}
答案 0 :(得分: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();
}
<强>更新强>
当然,这种反转方法是一个偏好问题,如下面的评论所述。关键是确保流关闭而不是允许它浮动,直到GC清理它(因为具有填充工具IDisposable
的整个点是为了避免这种情况开始)。由于这是一个接受Stream
作为输入的库函数,因此假设方法使用者将创建流,因此,正如您所指出的那样,也有责任最终关闭流。但对于敏感资源而言,如果您担心确保清理,则反转有时是一种有用的技术。
答案 1 :(得分:0)
只有在对它们调用Dispose时,StreamReader才会关闭/处置它们的基础流。如果读者/作者只是垃圾收集,他们不会处理流。