C# 在C语言中处理文件时如何正确处理异常#

C# 在C语言中处理文件时如何正确处理异常#,c#,.net,exception,exception-handling,C#,.net,Exception,Exception Handling,我读过很多关于适当异常处理的博客/文章/书籍章节,但我仍然不清楚这个主题。我将试着用下面的例子来说明我的问题 考虑具有以下要求的类方法: 接收文件路径列表作为参数 读取每个文件的文件内容,如果尝试执行此操作时出现任何问题,请跳过 返回表示文件内容的对象列表 所以规格很简单,下面是我如何开始编码的: 公共类文件内容 { 公共字符串文件路径{get;set;} 公共字节[]内容{get;set;} 公共文件内容(字符串文件路径,字节[]内容) { this.FilePath=FilePath; 这个

我读过很多关于适当异常处理的博客/文章/书籍章节,但我仍然不清楚这个主题。我将试着用下面的例子来说明我的问题

考虑具有以下要求的类方法:

  • 接收文件路径列表作为参数
  • 读取每个文件的文件内容,如果尝试执行此操作时出现任何问题,请跳过
  • 返回表示文件内容的对象列表
  • 所以规格很简单,下面是我如何开始编码的:

    公共类文件内容
    {
    公共字符串文件路径{get;set;}
    公共字节[]内容{get;set;}
    公共文件内容(字符串文件路径,字节[]内容)
    {
    this.FilePath=FilePath;
    这个。内容=内容;
    }
    }
    静态列表GetFileContents(列表路径)
    {
    var resultList=新列表();
    foreach(路径中的变量路径)
    {
    //打开“路径”指向的文件
    //将文件读取到FileContent对象
    //将文件内容添加到结果列表
    //关闭文件
    }
    返回结果列表;
    }
    
    现在请注意2。根据规范,该方法应“跳过因某种原因无法读取内容的任何文件”。因此,发生这种情况可能有许多不同的原因(例如,文件不存在,由于缺乏安全权限而拒绝访问文件,文件被锁定并被其他应用程序使用等等),但问题是,我不应该在意原因是什么,我只想在可能的情况下读取文件的内容,或者在不存在的情况下跳过文件。我不在乎错误是什么

    那么如何正确地实现这个方法呢

    正确处理异常的第一条规则是永不捕获一般异常。那么这个代码就不好了:

    静态列表GetFileContents(列表路径)
    {
    var resultList=新列表();
    foreach(路径中的变量路径)
    {
    尝试
    {
    使用(FileStream-stream=File.Open(路径,FileMode.Open))
    使用(BinaryReader=新的BinaryReader(流))
    {
    int fileLength=(int)stream.Length;
    字节[]缓冲区=新字节[文件长度];
    reader.Read(缓冲区,0,文件长度);
    Add(新文件内容(路径、缓冲区));
    }
    }
    捕获(例外情况除外)
    {
    //此文件无法读取,请不要执行任何操作…只需跳过该文件
    }
    }
    返回结果列表;
    }
    

    正确异常处理的下一条规则是:只捕获您可以处理的特定异常。我不关心处理任何可能抛出的特定异常,我只想检查文件是否可以读取。我如何才能以适当的最佳实践方式做到这一点?

    我对这个问题的解决方案通常基于可能的例外情况的数量。如果只有几个,我为每个指定catch块。如果有很多可能,我会抓住所有的例外。强制开发人员总是捕获特定的异常可能会导致一些非常难看的代码。

    您的要求很明确-跳过无法读取的文件。那么,通用异常处理程序有什么问题呢?它允许您以一种简单、干净、可读、可扩展和可维护的方式执行任务

    如果在将来的任何日期,您希望以不同的方式处理多个可能的异常,您可以在常规异常之上添加特定异常的捕获

    那么您希望看到下面的代码?请注意,如果添加更多代码来处理文件读取,则必须将所有新异常添加到此列表中。这一切都是为了什么也不做

    try
    {
        // find, open, read files
    }
    catch(FileNotFoundException) { }
    catch(AccessViolation) { }
    catch(...) { }
    catch(...) { }
    catch(...) { }
    catch(...) { }
    catch(...) { }
    catch(...) { }
    
    约定是一种指导原则,是创建好代码的好方法,但不要为了保持某种奇怪的礼仪而使代码过于复杂

    对我来说,正确的礼仪是永远不要在浴室里说话。但是当老板在那里跟你打招呼时,你也会跟他打招呼。因此,如果您不想以不同的方式处理多个异常,则不需要捕获每个异常


    编辑:所以我建议如下

    try
    {
        // find, open, read files
    }
    catch { } // Ignore any and all exceptions
    
    上面告诉我不要在意抛出哪个异常。通过不指定异常,甚至只指定System.exception,我允许.NET默认使用它。所以下面的代码是相同的

    try
    {
        // find, open, read files
    }
    catch(Exception) { } // Ignore any and all exceptions
    
    或者,如果您至少要记录它:

    try
    {
        // find, open, read files
    }
    catch(Exception ex) { Logger.Log(ex); }  // Log any and all exceptions
    

    这种情况下你可以考虑的是,在<代码> FieloToFuntuxPosip>/Cuth>之间,因为它们太多,你不能捕捉到,并且最普通的<代码>异常< /代码>,仍然有层<代码> IOExabue/COD>。p>


    一般来说,您将尝试捕获尽可能具体的异常,但特别是如果您捕获异常时没有实际使用它们抛出错误,那么您最好捕获一组异常。尽管如此,您仍将尽量使其具体化

    如果您在一种方法中混合了不同的操作,更改代码将使您的问题更容易回答:

    static List<FileContent> GetFileContents(List<string> paths)
    {
        var resultList = new List<FileContent>();
    
        foreach (var path in paths)
        {
              if (CanReadFile(path){
                    resultList.Add(new FileContent(path, buffer));
              }
        return resultList;
    }
    
    static bool CanReadFile(string Path){
         try{
             using (FileStream stream = File.Open(path, FileMode.Open))
                using (BinaryReader reader = new BinaryReader(stream))
                {
                    int fileLength = (int)stream.Length;
                    byte[] buffer = new byte[fileLength];
                    reader.Read(buffer, 0, fileLength);
                }
         }catch(Exception){ //I do not care what when wrong, error when reading from file
             return false;
         }
         return true;
    }
    
    静态列表GetFileContents(列表路径)
    {
    var resultList=新列表();
    foreach(路径中的变量路径)
    {
    if(CanReadFile(path){
    Add(新文件内容(路径、缓冲区));
    }
    返回结果列表;
    }
    静态bool CanReadFile(字符串路径){
    试一试{
    使用(FileStream-stream=File.Open(路径,FileMode.Open))
    使用(BinaryReader=新的BinaryReader(流))
    {
    int fileLength=(int)stream.Length;
    字节[]缓冲区=新字节[文件长度];
    reader.Read(缓冲区,0,文件长度);
    }
    }catch(Exception){//我不在乎什么时候出错,什么时候从文件中读取错误
    返回false;
    }
    返回true;
    }