ここでは、指定されたパス(文字列)が絶対パス(フルパス)か相対パスかを調べる方法を紹介します。
なおここでは、基本的には、パスとして正しくない文字列がパスとして指定されることは考慮しません。文字列がパスとして正しいかどうか調べる方法は、「ファイル名に使用できない文字列が含まれていないか調べる」等を参考にしてください。
.NET Frameworkで用意されているメソッドの中では、Path.IsPathRootedメソッドがその目的に一番近いでしょう。IsPathRootedメソッドがTrueを返せば絶対パス、Falseを返せば相対パスと判断できます。
このメソッドは、指定されたパスに不正な文字(Path.GetInvalidPathCharsメソッドで定義されている文字)が使われていないかをチェックして、使われていれば例外ArgumentExceptionをスローします。
このメソッドは、指定された文字列の1文字目が「\」(または、「/」)か、2文字目が「:」の時にTrueを返すようです。よって、例えば「\file.txt」(カレントドライブのルートにあるfile.txt)や、「C:file.txt」(ドライブCのカレントディレクトリにあるfile.txt)でもTrueを返します。もしこれらのパスを相対パスと判断したいのであれば、このメソッドだけでは不十分です。
補足:この問題は、MSDNの「Path.IsPathRooted Method (System.IO)」にあるCommunity Additionsで指摘されています。その影響か、MSDNでのPath.IsPathRootedメソッドの説明は、.NET Framework 3.5までは、「指定したパス文字列に絶対パス情報または相対パスの情報が含まれているかを示す値を取得します。」でしたが、.NET Framework 4.0からは、「指定したパス文字列にルートが含まれているかどうかを示す値を取得します。」に変わりました。
以下に、Path.IsPathRootedメソッドの使用例と、その結果を幾つか示します。
'Imports System.IO Console.WriteLine(Path.IsPathRooted("C:\file.txt")) 'true Console.WriteLine(Path.IsPathRooted("\\pc\s\file.txt")) 'true Console.WriteLine(Path.IsPathRooted("\file.txt")) 'true Console.WriteLine(Path.IsPathRooted("file.txt")) 'false Console.WriteLine(Path.IsPathRooted(".\file.txt")) 'false Console.WriteLine(Path.IsPathRooted("..\file.txt")) 'false Console.WriteLine(Path.IsPathRooted("C:file.txt")) 'true
//using System.IO; Console.WriteLine(Path.IsPathRooted(@"C:\file.txt")); //true Console.WriteLine(Path.IsPathRooted(@"\\pc\s\file.txt")); //true Console.WriteLine(Path.IsPathRooted(@"\file.txt")); //true Console.WriteLine(Path.IsPathRooted(@"file.txt")); //false Console.WriteLine(Path.IsPathRooted(@".\file.txt")); //false Console.WriteLine(Path.IsPathRooted(@"..\file.txt")); //false Console.WriteLine(Path.IsPathRooted(@"C:file.txt")); //true
「Naming Files, Paths, and Namespaces (Windows)」によると、「\\」で始まるか、「:\」を含むか、「\」で始まっているパス以外のパスは、カレントディレクトリからの相対パスになるということです。
この内「\」で始まるパスは、通常相対パスと判断したいところですので、ここでは「\\」で始まるか、2文字目以降が「:\」である場合のみ絶対パスと判断することにして、メソッドを作ってみました。
'Imports System.IO ''' <summary> ''' 指定したパス文字列が絶対パスか相対パスかを判断する。 ''' </summary> ''' <param name="p">判断するパス。</param> ''' <returns>絶対パスと判断した場合は、True。それ以外は、False。</returns> Public Shared Function IsAbsolatePath(p As String) As Boolean Dim len As Integer = p.Length If (2 <= len AndAlso _ (p(0) = Path.DirectorySeparatorChar OrElse _ p(0) = Path.AltDirectorySeparatorChar) AndAlso _ (p(1) = Path.DirectorySeparatorChar OrElse _ p(1) = Path.AltDirectorySeparatorChar)) OrElse _ (3 <= len AndAlso _ p(1) = Path.VolumeSeparatorChar AndAlso _ (p(2) = Path.DirectorySeparatorChar OrElse _ p(2) = Path.AltDirectorySeparatorChar)) Then Return True End If Return False End Function
//using System.IO; /// <summary> /// 指定したパス文字列が絶対パスか相対パスかを判断する。 /// </summary> /// <param name="p">判断するパス。</param> /// <returns>絶対パスと判断した場合は、True。それ以外は、False。</returns> public static bool IsAbsolatePath(string p) { int len = p.Length; if ((2 <= len && (p[0] == Path.DirectorySeparatorChar || p[0] == Path.AltDirectorySeparatorChar) && (p[1] == Path.DirectorySeparatorChar || p[1] == Path.AltDirectorySeparatorChar)) || (3 <= len && p[1] == Path.VolumeSeparatorChar && (p[2] == Path.DirectorySeparatorChar || p[2] == Path.AltDirectorySeparatorChar))) { return true; } return false; }
Path.GetFullPathメソッドは、相対パスを渡すと絶対パスを返し、絶対パスを渡すとそのまま返します。よって、Path.GetFullPathメソッドに渡したパスと返されたパスが同じ場合は絶対パス、異なる場合は相対パスと判断できます。
ただしこのメソッドは、短いファイル名を渡すと長いファイル名に変換したり、パスに「..」や「.」が含まれていると正規化したりするため、渡したパスが絶対パスでもそれとは異なるパス文字列を返す可能性があります。
このメソッドは、Path.IsPathRootedメソッドと同様、パスとして不正な文字が含まれていないか調べる他、パスの長さなど、パスとして正しいかをある程度チェックし、正しくなければ例外をスローします。また、パスが存在する場合はファイルシステムにアクセスし、アクセスできない時は例外SecurityExceptionをスローします。
'Imports System.IO '絶対パスか調べるパス Dim p As String = "c:\dir\file.txt" 'GetFullPathメソッドが同じ文字列を返したら、絶対パスと判断する If Path.GetFullPath(p).Equals(p) Then Console.WriteLine("絶対パスです。") Else Console.WriteLine("絶対パスではありません。") End If
//using System.IO; //絶対パスか調べるパス string p = @"c:\dir\file.txt"; //GetFullPathメソッドが同じ文字列を返したら、絶対パスと判断する if (Path.GetFullPath(p).Equals(p)) { Console.WriteLine("絶対パスです。"); } else { Console.WriteLine("絶対パスではありません。"); }
Uriコンストラクタの1番目の引数にパスを、2番目の引数にUriKind.Absoluteを指定すると、パスが相対パスだった場合に例外がスローされます。Uriコンストラクタの代わりにUri.TryCreateメソッドを使用すると、例外を発生することなく、その確認ができます。このメソッドは、.NET Framework 2.0以降で使用できます。
基本的には、このメソッドで調べるのは指定されたURIが正しいか(Uriオブジェクトを作成できるか)ですが、Windowsパスも指定できます。また、今まで紹介してきた方法では「file:///」形式のパスを正しく判断できませんが、この方法ではできます(できない方が良いかもしれませんが...)。
このメソッドは「http://」などのURIでもTrueを返しますが、Windowsパスや「file:///」であることを確認するなら、作成されたUriオブジェクトのIsFileプロパティを調べればよいでしょう。また、IsUncプロパティによって、UNCパスかどうかが分かります。
Dim u As Uri Console.WriteLine(Uri.TryCreate("C:\file.txt", UriKind.Absolute, u)) 'true Console.WriteLine(Uri.TryCreate("\\pc\s\file.txt", UriKind.Absolute, u)) 'true Console.WriteLine(Uri.TryCreate("\file.txt", UriKind.Absolute, u)) 'false Console.WriteLine(Uri.TryCreate("file.txt", UriKind.Absolute, u)) 'false Console.WriteLine(Uri.TryCreate(".\file.txt", UriKind.Absolute, u)) 'false Console.WriteLine(Uri.TryCreate("..\file.txt", UriKind.Absolute, u)) 'false Console.WriteLine(Uri.TryCreate("C:file.txt", UriKind.Absolute, u)) 'false Console.WriteLine(Uri.TryCreate("file:///C:/file.txt", UriKind.Absolute, u)) 'true
Uri u; Console.WriteLine(Uri.TryCreate(@"C:\file.txt", UriKind.Absolute, out u)); //true Console.WriteLine(Uri.TryCreate(@"\\pc\s\file.txt", UriKind.Absolute, out u)); //true Console.WriteLine(Uri.TryCreate(@"\file.txt", UriKind.Absolute, out u)); //false Console.WriteLine(Uri.TryCreate(@"file.txt", UriKind.Absolute, out u)); //false Console.WriteLine(Uri.TryCreate(@".\file.txt", UriKind.Absolute, out u)); //false Console.WriteLine(Uri.TryCreate(@"..\file.txt", UriKind.Absolute, out u)); //false Console.WriteLine(Uri.TryCreate(@"C:file.txt", UriKind.Absolute, out u)); //false Console.WriteLine(Uri.TryCreate(@"file:///C:/file.txt", UriKind.Absolute, out u)); //true