简体   繁体   中英

Try, catch statement in C#

I have the following C# code for calculating each file's hash in a certain, user specified directory. The point is that it works fine, until it encounters a file that it cannot access. When it finds something like this, it just throws an error message and exits the program. What I want it instead to do is, throw an error message with the name of the file that cannot be accessed, write that there is an error in accessing that file, and continue executing the program with the other files in the directory. If someone can help me edit my code and achieve those things I would be glad.

    private void SHA256Directory(string directory)
    {
        try
        {
            SHA256 DirectorySHA256 = SHA256Managed.Create();
            byte[] hashValue;

            DirectoryInfo dir = new DirectoryInfo(directory);
            FileInfo[] files = dir.GetFiles();

            foreach (FileInfo fInfo in files)
            {
                FileStream fStream = fInfo.Open(FileMode.Open);
                fStream.Position = 0;
                hashValue = DirectorySHA256.ComputeHash(fStream);

                Console.WriteLine(fInfo.Name);
                Miscellaneous.ByteArrayToHex(hashValue);
                Miscellaneous.ByteArrayToBase64(hashValue);
                Console.WriteLine();

                fStream.Close();
            }

            return;
        }
        catch(DirectoryNotFoundException)
        {
            Console.WriteLine("Error: The directory specified could not be found.");
        }
        catch(IOException)
        {
            Console.WriteLine("Error: A file in the directory could not be accessed.");
        }
        catch(ArgumentNullException)
        {
            Console.WriteLine("Error: The argument cannot be null or empty.");
        }

    }

Move your try/catch inside the foreach . You haven't explained in your post, but I'm guessing that's where you encounter the exception.

In doing so, any exception caused by the code in there will be caught and allow the loop to continue.

Careful, though -- these two lines are still not exception-safe:

DirectoryInfo dir = new DirectoryInfo(directory);
FileInfo[] files = dir.GetFiles();

You'll want to account for that as well.

If you want it to show what exactly what file/directory caused the issue, just toString the exception, for example:

catch(DirectoryNotFoundException ex)
{
    Console.WriteLine("Error: The directory specified could not be found: " + ex.toString());
}

If toString doesn't give you the desired output, try ex.Message . I always just use toString though.

EDIT credit to Ken Henderson

When using any kind of Stream , you should put it in a using block. The garbage collector will Close the stream eventually, but its good practice to do this, as a using block will close the stream as soon as you're done using it:

using (FileStream fStream = fInfo.Open(FileMode.Open)) 
{
    fStream.Position = 0;
    hashValue = DirectorySHA256.ComputeHash(fStream);

    Console.WriteLine(fInfo.Name);
    Miscellaneous.ByteArrayToHex(hashValue);
    Miscellaneous.ByteArrayToBase64(hashValue);
    Console.WriteLine();
} // No need for fStream.Close() any more, the using block will take care of it for you

You should reorganize your code like this:

private void SHA256Directory(string directory)
{
    try
    {
        DirectoryInfo dir = new DirectoryInfo(directory);
        FileInfo[] files = dir.GetFiles();

        foreach (FileInfo fInfo in files)
        {
            try
            {
                SHA256 DirectorySHA256 = SHA256Managed.Create();
                byte[] hashValue;

                FileStream fStream = fInfo.Open(FileMode.Open);
                fStream.Position = 0;
                hashValue = DirectorySHA256.ComputeHash(fStream);

                Console.WriteLine(fInfo.Name);
                Miscellaneous.ByteArrayToHex(hashValue);
                Miscellaneous.ByteArrayToBase64(hashValue);
                Console.WriteLine();

                fStream.Close();
            }
            catch (...)
            {
                // Handle other exceptions here. Through finfo, you can
                // access the file name
            }
        }
    }
    catch (...)
    {
        // Handle directory/file iteration exceptions here
    }
}

Scope is the keyword here.

Your try catch surrounds the entire foreach. This means that when there is an error, it will exit out of the foreach. You want to have the try-catch closer to the point of origin (that being fInfo.Open(FileMode.Open) ). That way, after an error it can just continue processing the loop.

Try this instead:

private void SHA256Directory(string directory)
{
    SHA256 DirectorySHA256 = SHA256Managed.Create();
    byte[] hashValue;

    DirectoryInfo dir = new DirectoryInfo(directory);
    FileInfo[] files = dir.GetFiles();

    foreach (FileInfo fInfo in files)
    {
        try
        {
            FileStream fStream = fInfo.Open(FileMode.Open);
            fStream.Position = 0;
            hashValue = DirectorySHA256.ComputeHash(fStream);

            Console.WriteLine(fInfo.Name);
            Miscellaneous.ByteArrayToHex(hashValue);
            Miscellaneous.ByteArrayToBase64(hashValue);
            Console.WriteLine();

            fStream.Close();
        }
        catch(DirectoryNotFoundException)
        {
            Console.WriteLine("Error: The directory specified could not be found.");
        }
        catch(IOException)
        {
            Console.WriteLine("Error: A file in the directory could not be accessed.");
        }
        catch(ArgumentNullException)
        {
            Console.WriteLine("Error: The argument cannot be null or empty.");
        }
    }
    return;
}


}

您还应该处理UnauthorizedAccessException ,如果无法访问文件,则抛出该异常。

Might be I'm overseeing something, because the solution is rather simple, but;

place the Try-Catch block dealing with the access problems inside the for each - in case one file is not accessible, the exception is thrown, catched and after printing the error message the foreach is continued with the next file in the list.

private void SHA256Directory(string directory)
{
    try
    {
        SHA256 DirectorySHA256 = SHA256Managed.Create();
        byte[] hashValue;

        DirectoryInfo dir = new DirectoryInfo(directory);
        FileInfo[] files = dir.GetFiles();

        foreach (FileInfo fInfo in files)
        {
           try
           {


               FileStream fStream = fInfo.Open(FileMode.Open);
               fStream.Position = 0;
               hashValue = DirectorySHA256.ComputeHash(fStream);

               Console.WriteLine(fInfo.Name);
               Miscellaneous.ByteArrayToHex(hashValue);
               Miscellaneous.ByteArrayToBase64(hashValue);
               Console.WriteLine();

               fStream.Close();
            }
            catch(IOException)
            {
               Console.WriteLine("Error: A file in the directory could not be accessed.");
            }
        }

        return;
    }
    catch(DirectoryNotFoundException)
    {
        Console.WriteLine("Error: The directory specified could not be found.");
    }
    catch(ArgumentNullException)
    {
        Console.WriteLine("Error: The argument cannot be null or empty.");
    }

}

To know which file is not accessible you could use the following snippet :

catch(FileNotFoundException ex)
{
Console.writeLine("File not found " + ex.FileName);
}

handle UnauthorizedAccessException and put try statement in foreach statement.

private  void SHA256Directory(string directory)
    {
        SHA256 DirectorySHA256 = SHA256Managed.Create();
        byte[] hashValue;

        DirectoryInfo dir = new DirectoryInfo(directory);
        FileInfo[] files = dir.GetFiles();

        foreach (FileInfo fInfo in files)
        {
            try
            {
                FileStream fStream = fInfo.Open(FileMode.Open);
                fStream.Position = 0;
                hashValue = DirectorySHA256.ComputeHash(fStream);

                Console.WriteLine(fInfo.Name);
                Miscellaneous.ByteArrayToHex(hashValue);
                Miscellaneous.ByteArrayToBase64(hashValue);
                Console.WriteLine();

                fStream.Close();
            }
            catch (DirectoryNotFoundException)
            {
                Console.WriteLine("Error: The directory specified could not be found.");
            }
            catch (UnauthorizedAccessException)
            {
                Console.WriteLine("Error: A file in the directory could not be accessed.in {0}", fInfo.Name);
            }
            catch (ArgumentNullException)
            {
                Console.WriteLine("Error: The argument cannot be null or empty.");
            }
            catch (IOException)
            {
                Console.WriteLine("Error:IOExcepiton occured");
            }

        }

        return;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM