正在处理StreamReader,该StreamReader读取范围外定义的流
本文关键字:StreamReader 定义 范围 处理 读取 | 更新日期: 2023-09-27 18:22:44
在接受Stream
参数的实用程序方法中,我依赖一些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);
}
}
您可以使用闭包来反转控件。也就是说,创建一个这样的方法:
// 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将其清理干净(因为让stuff实现IDisposable
的全部目的是从一开始就避免这种情况)。由于这是一个接受Stream
作为输入的库函数,因此假设方法使用者将创建流,因此正如您所指出的,也有责任最终关闭流。但对于敏感资源,如果您担心确保绝对进行清理,反转有时是一种有用的技术。
StreamReader只有在您对其调用dispose时才关闭/处置其底层流。如果读取器/写入器只是垃圾收集,则它们不会处理流。