.NET ファイル システム メソッドは、任意のメソッド呼び出しでスローできる例外 (システムがストレスを受けた場合の OutOfMemoryException やプログラマ エラーによる NullReferenceException など) に加えて、次の例外をスローできます。
- System.IO.IOExceptionは、すべての System.IO 例外の種類の基底クラスです。 オペレーティング システムからのリターン コードが他の例外の種類に直接マップされないエラーに対してスローされます。
- System.IO.FileNotFoundException。
- System.IO.DirectoryNotFoundException。
- DriveNotFoundException。
- System.IO.PathTooLongException。
- System.OperationCanceledException。
- System.UnauthorizedAccessException。
- System.ArgumentExceptionは、.NET Framework および .NET Core 2.0 以前のバージョンで無効なパス文字に対してスローされます。
- System.NotSupportedException.NET Framework の無効なコロンに対してスローされます。
- System.Security.SecurityExceptionこれは、.NET Framework に必要なアクセス許可がない限られた信頼で実行されているアプリケーションに対してスローされます。 (.NET Framework では、完全信頼が既定です)。
エラー コードを例外にマッピングする
ファイル システムはオペレーティング システム リソースであるため、.NET Core と .NET Framework の両方の I/O メソッドは、基になるオペレーティング システムへの呼び出しをラップします。 オペレーティング システムによって実行されるコードで I/O エラーが発生すると、オペレーティング システムはエラー情報を .NET I/O メソッドに返します。 その後、このメソッドは、エラー情報 (通常はエラー コードの形式) を .NET 例外の種類に変換します。 ほとんどの場合、エラー コードを対応する例外の種類に直接変換することでこれを行います。メソッド呼び出しのコンテキストに基づくエラーの特別なマッピングは実行されません。
たとえば、Windows オペレーティング システムでは、 ERROR_FILE_NOT_FOUND
(または0x02) のエラー コードを返すメソッド呼び出しが FileNotFoundExceptionにマップされ、 ERROR_PATH_NOT_FOUND
(または0x03) のエラー コードが DirectoryNotFoundExceptionにマップされます。
ただし、オペレーティング システムが特定のエラー コードを返す正確な条件は、多くの場合、文書化されていないか、文書化が不十分です。 その結果、予期しない例外が発生する可能性があります。 たとえば、ファイルではなくディレクトリを操作しているため、 DirectoryInfo コンストラクターに無効なディレクトリ パスを指定すると、 DirectoryNotFoundExceptionがスローされます。 ただし、 FileNotFoundExceptionをスローする場合もあります。
I/O 操作での例外処理
このオペレーティング システムへの依存により、同じ例外条件 (この例ではディレクトリが見つからないエラーなど) により、I/O メソッドが I/O 例外のクラス全体のいずれかをスローする可能性があります。 つまり、I/O API を呼び出すときは、次の表に示すように、これらの例外の大部分またはすべてを処理するようにコードを準備する必要があります。
例外の種類 | .NET Core/.NET 5 以降 | .NET Framework |
---|---|---|
IOException | イエス | イエス |
FileNotFoundException | イエス | イエス |
DirectoryNotFoundException | イエス | イエス |
DriveNotFoundException | イエス | イエス |
PathTooLongException | イエス | イエス |
OperationCanceledException | イエス | イエス |
UnauthorizedAccessException | イエス | イエス |
ArgumentException | .NET Core 2.0 以前 | イエス |
NotSupportedException | いいえ | イエス |
SecurityException | いいえ | 制限付き信頼のみ |
IOException の処理
System.IO名前空間の例外の基本クラスとして、定義済みの例外の種類にマップされていないエラー コードに対しても、IOExceptionがスローされます。 これは、任意の I/O 操作によってスローできることを意味します。
Von Bedeutung
IOExceptionはSystem.IO名前空間の他の例外型の基底クラスであるため、他の I/O 関連の例外を処理した後、catch
ブロックで処理する必要があります。
さらに、.NET Core 2.1 以降では、パスの正確性の検証チェック (たとえば、パスに無効な文字が存在しないことを確認するため) が削除され、ランタイムは、独自の検証コードではなく、オペレーティング システムのエラー コードからマップされた例外をスローします。 この場合にスローされる可能性が最も高い例外は IOExceptionですが、他の例外の種類もスローされる可能性があります。
例外処理コードでは、常に最後の IOException を処理する必要があることに注意してください。 それ以外の場合は、他のすべての IO 例外の基底クラスであるため、派生クラスの catch ブロックは評価されません。
IOExceptionの場合は、IOException.HResult プロパティから追加のエラー情報を取得できます。 HResult 値を Win32 エラー コードに変換するには、32 ビット値の上位 16 ビットを除去します。 次の表に、 IOExceptionでラップされる可能性があるエラー コードを示します。
HResult | 定数 | 説明 |
---|---|---|
共有違反エラー | 32 | ファイル名がないか、ファイルまたはディレクトリが使用中です。 |
ERROR_FILE_EXISTS | 80 | ファイルは既に存在します。 |
無効なパラメーターエラー | 87 | メソッドに指定された引数が無効です。 |
すでに存在するエラー | 183 | ファイルまたはディレクトリは既に存在します。 |
次の例に示すように、catch ステートメントで When
句を使用してこれらを処理できます。
using System;
using System.IO;
using System.Text;
class Program
{
static void Main()
{
var sw = OpenStream(@".\textfile.txt");
if (sw is null)
return;
sw.WriteLine("This is the first line.");
sw.WriteLine("This is the second line.");
sw.Close();
}
static StreamWriter? OpenStream(string path)
{
if (path is null)
{
Console.WriteLine("You did not supply a file path.");
return null;
}
try
{
var fs = new FileStream(path, FileMode.CreateNew);
return new StreamWriter(fs);
}
catch (FileNotFoundException)
{
Console.WriteLine("The file or directory cannot be found.");
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("The file or directory cannot be found.");
}
catch (DriveNotFoundException)
{
Console.WriteLine("The drive specified in 'path' is invalid.");
}
catch (PathTooLongException)
{
Console.WriteLine("'path' exceeds the maximum supported path length.");
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("You do not have permission to create this file.");
}
catch (IOException e) when ((e.HResult & 0x0000FFFF) == 32)
{
Console.WriteLine("There is a sharing violation.");
}
catch (IOException e) when ((e.HResult & 0x0000FFFF) == 80)
{
Console.WriteLine("The file already exists.");
}
catch (IOException e)
{
Console.WriteLine($"An exception occurred:\nError code: " +
$"{e.HResult & 0x0000FFFF}\nMessage: {e.Message}");
}
return null;
}
}
Imports System.IO
Module Program
Sub Main(args As String())
Dim sw = OpenStream(".\textfile.txt")
If sw Is Nothing Then Return
sw.WriteLine("This is the first line.")
sw.WriteLine("This is the second line.")
sw.Close()
End Sub
Function OpenStream(path As String) As StreamWriter
If path Is Nothing Then
Console.WriteLine("You did not supply a file path.")
Return Nothing
End If
Try
Dim fs As New FileStream(path, FileMode.CreateNew)
Return New StreamWriter(fs)
Catch e As FileNotFoundException
Console.WriteLine("The file or directory cannot be found.")
Catch e As DirectoryNotFoundException
Console.WriteLine("The file or directory cannot be found.")
Catch e As DriveNotFoundException
Console.WriteLine("The drive specified in 'path' is invalid.")
Catch e As PathTooLongException
Console.WriteLine("'path' exceeds the maximum supported path length.")
Catch e As UnauthorizedAccessException
Console.WriteLine("You do not have permission to create this file.")
Catch e As IOException When (e.HResult And &h0000FFFF) = 32
Console.WriteLine("There is a sharing violation.")
Catch e As IOException When (e.HResult And &h0000FFFF) = 80
Console.WriteLine("The file already exists.")
Catch e As IOException
Console.WriteLine($"An exception occurred:{vbCrLf}Error code: " +
$"{e.HResult And &h0000FFFF}{vbCrLf}Message: {e.Message}")
End Try
Return Nothing
End Function
End Module
こちらも参照ください
.NET