正确处理文件流和二进制流以及处理文件流

实际上,我尝试了对代码进行防错并最终使其看起来非常混乱。

我有一个function设置来读取某种类型的文件。 我希望函数在出现问题时返回false,如果一切正常则返回true。 我无法弄清楚如何构建一切。

我有一个尝试打开文件流的初始try-catch块。 在那之后,我在读取过程中进行了一些其他检查,例如文件大小和某些偏移处的值。 我设置的方式是使用if else语句。 如:

if(condition){ } else{ MessageBox.Show("There was an error"); br.Dispose(); fs.Dispose(); return false; } 

… br是二进制阅读器,fs是文件流。 像这样有很多块,这么多次写同样的东西似乎是不好的做法。 首先想到的是将整个事物包装在try-catch语句中并抛出exception而不是使用if else块。 我记得在阅读try-catch语句时,拥有它们是好的,但不要用它们包装所有内容。 说实话,我仍然不完全理解为什么在try catch语句中包装所有内容都是不好的做法,因为它们只有在出现错误时才会生效,在这种情况下程序正在向南移动…

此外,我是否必须关闭二进制阅读器和文件流,或者关闭一个关闭另一个? 有没有办法使用它们而不必处理它们?

如何使用using关键字? 这包括你在try – finally块中使用IDisposable ;

 bool success = true; using(var fs = new FileStream(fileName, FileMode.Create))) using(var br = new BinaryReader(fs)) { // do something success = result; } return success; 

嵌套的使用块将确保文件流和二进制阅读器始终正确关闭和处理。

您可以阅读有关在MSDN中使用的更多信息 。 它使IDisposable的使用更加整洁,无需显式的excpetion处理。

关于你的陈述:

我记得在阅读try-catch语句时,拥有它们是好的,但不要用它们包装所有内容。

我总是使用简单的规则,如果我无法处理并从特定代码块中的exception中恢复,请不要尝试捕获它。 允许exception将堆栈’冒泡’到一个更有意义的方法来捕获它。 使用这种方法,您会发现您不需要添加许多try-catch块,您将倾向于在与服务集成时使用它们(例如文件系统,网络等…),但您的业务逻辑几乎总是如此没有exception处理机制。

只需对您的一次性对象使用using关键字即可。 在using关键字的块中,您可以throwexception或return而不必担心处置; 它会自动发生在你身上。

try-catch块不是一个好主意,因为存在一个更好的选择: try-finally块。 但是using关键字甚至更好,因为它基本上扩展为try-finally块,它负责处理对象。

关闭文件流也将关闭二进制阅读器,因此将处理它们。 为什么要在不处理它们的情况下使用它们? 处理它们更好,通过using处理它们是最好的事情。

我认为确保文件流处理的最佳方法是使用以下using块来包装它们的用法

 using (FileStream) { .... } 

是的,这是不好的做法。

您应该抛出exception,而不是返回指示问题是否发生的布尔值。 例:

 if (headNotValid) throw new Exception("Header was not valid"); 

在某些情况下,建议创建一个新的exception类。

使用inheritance自IDisposable类时,应使用using指令。

 using (var stream = new FileStream(filename)) { } 

即使在using块中抛出exception,这也可以保证您的流被丢弃。

总之,我更喜欢这样的事情:

 private void string ParseFile(string filename) { using (var stream = new FileStream(filename)) { if (somethingNotValid) throw new Exception(...); return ...; } } 

在你的主要:

 { try { var value = ParseFile(filename); } catch (Exception) { Console.WriteLine(..); } } 

使用using关键字。 using您可以重写这样的内容:

 public static int CountCars() { SqlConnection conn = new SqlConnection(connectionString); try { SqlCommand cmd = conn.CreateCommand(); conn.Open(); try { cmd.CommandText = "SELECT COUNT(1) FROM Carsd"; return (int)cmd.ExecuteScalar(); } finally { if(cmd != null) cmd.Dispose(); } } finally { if(cmd != null) conn.Dispose(); } } 

进入这个:

 public static int CountCars() { using(SqlConnection conn = new SqlConnection(connectionString)) using(SqlCommand cmd = conn.CreateCommand()) { conn.Open(); cmd.CommandText = "SELECT COUNT(1) FROM Carsd"; return (int)cmd.ExecuteScalar(); } } 

两个代码片段在编译时将生成完全相同的IL代码。 这些例子来自http://coding.abel.nu/2011/12/idisposable-and-using-in-c/ ,其中我写了一些关于使用和IDisposable更多细节。