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

发布于 2024-12-23 13:14:00 字数 667 浏览 2 评论 0原文

事实上,我尝试对我的代码进行防错,但最终使它看起来相当混乱。

我设置了一个函数来读取某种类型的文件。我希望函数在出现问题时返回 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 语句中并抛出异常,而不是使用 if else 块。我记得在阅读有关 try-catch 语句的内容时,拥有它们很好,但不要用它们包装所有内容。老实说,我仍然不完全理解为什么将所有内容都包装在 try catch 语句中是不好的做法,因为它们只有在出现错误时才会起作用,在这种情况下程序无论如何都会出错......

而且,我是否必须关闭二进制读取器和文件流,或者关闭其中一个会关闭另一个吗?有什么方法可以使用它们而不必丢弃它们吗?

As it is, I tried error-proofing my code and ended up making it look quite messy.

I have a function set up to read a certain type of file. I want the function to return false if there was a problem, or true if everything worked. I'm having trouble figuring out how to structure everything.

I have an initial try-catch block that tries to open a file stream. After that though, I have certain other checks I make during the reading process such as file size and values at certain offsets. The way I set it up was with if else statements. Such as:

if(condition){

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

...br being the binary reader and fs the filestream. There are many blocks like this, and it seems like bad practice to write the same thing so many times. The first thing that comes to mind is to wrap the entire thing in a try-catch statement and throw exceptions instead of using the if else blocks. I remember when reading about try-catch statements that it's good to have them, but not to wrap everything with them. To be honest, I still don't completely understand why it would be bad practice to wrap everything in try catch statements, as they only have an effect when there's an error, in which case the program is going south anyway...

Also, do I have to close the binary reader and file stream, or will closing one close the other? Is there any way to use them without having to dispose of them?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

世态炎凉 2024-12-30 13:14:00

使用 using 关键字怎么样?这将您对 IDisposable 的使用包装在 try - finally 块中;

bool success = true;

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

return success;

嵌套的 using 块将确保文件流和二进制读取器始终正确关闭和处置。

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

关于您的发言:

我记得在阅读有关 try-catch 语句时,最好
拥有它们,但不要用它们包裹所有东西。

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

How about making use of the using keyword? this wraps your use of an IDisposable in a try - finally block;

bool success = true;

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

return success;

The nested using blocks will ensure that both the filestream and binary reader are always properly closed and disposed.

You can read more about using in MSDN. It makes the use of IDisposable a little neater, removing the need for explicit excpetion handling.

Regarding your statement:

I remember when reading about try-catch statements that it's good to
have them, but not to wrap everything with them.

I always use the simple rule that if I cannot handle and recover from an exception within a particular block of code, don't try to catch it. Allow the exception to 'bubble up' the stack to a point where it makes more sense to catch it. With this approach you will find that you do not need to add many try-catch blocks, you will tend to use them at the point of integration with services (such as filesystem, network etc ...) but your business logic is almost always free of exception handling mechanisms.

漫雪独思 2024-12-30 13:14:00

只需对一次性物品使用 using 关键字即可。在 using 关键字块中,您可以抛出异常或返回,而不必担心处置;它会自动为你发生。

try-catch 块并不是一个好主意,只是因为存在更好的替代方案:try-finally 块。但 using 关键字甚至更好,因为它本质上扩展为 try-finally 块,并负责对象处置。

关闭文件流也会关闭二进制读取器,因此处理它们也会关闭。为什么要使用它们而不丢弃它们?处理它们更好,并且通过 using 处理它们是最好的办法。

Just use the using keyword for your disposable objects. Within the block of the using keyword you can throw exceptions or return without having to worry about disposal; it will happen automagically for you.

try-catch blocks are not a very good idea only because there exists a much better alternative: the try-finally blocks. But the using keyword is even better because it essentially expands into a try-finally block and it takes care of object disposal.

Closing the file stream will also close the binary reader, and so will disposing of them do. Why do you want to use them without disposing them? Disposing them is better, and disposing them via using is the best thing to do.

神回复 2024-12-30 13:14:00

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

using (FileStream)
{
    ....
}

I think the best way to make sure filestreams are disposed is to wrap their usage with the following using block

using (FileStream)
{
    ....
}
原来是傀儡 2024-12-30 13:14:00

是的,这是不好的做法。

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

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

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

当使用从 IDisposable 继承的类时,您应该使用 using 指令。

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

这保证了即使在 using 块内抛出异常,您的流也会被释放。

总之,我更喜欢这样的东西:

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

Yes, it is bad practice.

Instead of returning booleans that indicate whether a problem occurred or not, you should throw exceptions. Example:

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

In some cases it may be advisable to make a new exception class.

When working with classes that inherit from IDisposable you should use the using directive.

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

That guarantees, that your stream is disposed, even if a exception is thrown within the using block.

In summary, I would prefer something like this:

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

           return ...;
     }
}

And in your main:

{
     try
     {
          var value = ParseFile(filename);
     }
     catch (Exception)
     {
          Console.WriteLine(..);
     }
}
行雁书 2024-12-30 13:14:00

使用 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/,我在其中写了一些有关 using 和 IDisposable 的更多详细信息。

Use the using keyword. With using you can rewrite something like this:

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

into this:

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

}

Both code snippets will produce exactly the same IL code when compiled. The examples are from http://coding.abel.nu/2011/12/idisposable-and-using-in-c/ where I wrote some more details about using and IDisposable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文