C#でURI文字列からファイル名を取得する


206

文字列URIからファイル名を取得するこのメソッドがあります。より堅牢にするために何ができますか?

private string GetFileName(string hrefLink)
{
    string[] parts = hrefLink.Split('/');
    string fileName = "";

    if (parts.Length > 0)
        fileName = parts[parts.Length - 1];
    else
        fileName = hrefLink;

    return fileName;
}

回答:


388

System.Uriオブジェクトを作成し、IsFileを使用してそれがファイルであることを確認してから、Uri.LocalPathを使用してファイル名を抽出できます。

これは、URIの有効性をチェックする手段も提供するため、はるかに安全です。


コメントに応じて編集:

完全なファイル名だけを取得するには、次のようにします。

Uri uri = new Uri(hreflink);
if (uri.IsFile) {
    string filename = System.IO.Path.GetFileName(uri.LocalPath);
}

これはすべてのエラーチェックを行い、プラットフォームに依存しません。特別なケースはすべて迅速かつ簡単に処理されます。


私は同意します。Uriクラスは既にこの機能を備えているので、実際に使用してください。+1
ドクタージョーンズ

2
そうですが、完全なファイルパスではなく、ファイル名だけが必要です。Uri.LocalPathでそのステップを実行するために私はまだ残っていませんか?
ポールウィート2009

2
@paulwhit:その場合、Uri.LocalPathの結果にはPath.GetFileNameを使用する必要があります。これは完全に安全で、高度にチェックされた方法で処理されます。これが含まれるように回答を編集します。参照:msdn.microsoft.com/en-us/library/...
リードCopsey

49
isFileはスキームだけを見ているように見えます。つまり、「www / myFile.jpg」はfalseを返し、「file://www/something.jpg」はtrueを返すため、この場合は役に立ちません。
dethSwatch

6
クエリ文字列にも注意してください。http://www.test.com/file1.txt?a=b結果はfile1.txt?a=b
Julian

76

Uri.IsFileはhttp URLでは機能しません。「file://」でのみ機能します。MSDNから:「SchemeプロパティがUriSchemeFileと等しい場合、IsFileプロパティはtrueです。」だからあなたはそれに依存することはできません。

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.LocalPath);

Uri.LocalPathはWindows固有の変換を行い、Windows以外の環境では正しく機能しません。これを行うポータブルな方法については、以下の私の答えを参照してください。
Kostub Deshmukh 2016

あなたが使用することはできませんがUri.IsFile、HTTP URL /スキームに試験を実施し、正常に使用したA HTTP URLからファイル名を抽出することができますSystem.IO.Path.GetFileName(url);
アレックスPandrea

50

他のほとんどの回答は不完全であるか、パスの後に来るもの(クエリ文字列/ハッシュ)を処理しません。

readonly static Uri SomeBaseUri = new Uri("http://canbeanything");

static string GetFileNameFromUrl(string url)
{
    Uri uri;
    if (!Uri.TryCreate(url, UriKind.Absolute, out uri))
        uri = new Uri(SomeBaseUri, url);

    return Path.GetFileName(uri.LocalPath);
}

試験結果:

GetFileNameFromUrl("");                                         // ""
GetFileNameFromUrl("test");                                     // "test"
GetFileNameFromUrl("test.xml");                                 // "test.xml"
GetFileNameFromUrl("/test.xml");                                // "test.xml"
GetFileNameFromUrl("/test.xml?q=1");                            // "test.xml"
GetFileNameFromUrl("/test.xml?q=1&x=3");                        // "test.xml"
GetFileNameFromUrl("test.xml?q=1&x=3");                         // "test.xml"
GetFileNameFromUrl("http://www.a.com/test.xml?q=1&x=3");        // "test.xml"
GetFileNameFromUrl("http://www.a.com/test.xml?q=1&x=3#aidjsf"); // "test.xml"
GetFileNameFromUrl("http://www.a.com/a/b/c/d");                 // "d"
GetFileNameFromUrl("http://www.a.com/a/b/c/d/e/");              // ""

7
なぜGetFileNameFromUrl("test")結果的になるの"test.xml" ですか、それとも単なるタイプミスですか?
ckittel

27

受け入れられた回答は、httpのURLには問題があります。さらにUri.LocalPath、Windows固有の変換も行われ、誰かが指摘したように、そこにクエリ文字列を残します。より良い方法は、Uri.AbsolutePath

これをhttp URLに対して行う正しい方法は次のとおりです。

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.AbsolutePath);

7
http://example.com/dir/hello%20world.txtこのようなエスケープされたURLの場合は戻りhello%20world.txtますが、Uri.LocalPathアプローチは戻ることに注意してください hello world.txt
Jeff Moser 2017

22

私はこれがあなたが必要とすることをすると思います:

var uri = new Uri(hreflink);
var filename = uri.Segments.Last();

2
これは確かにエレガントなソリューションのように見えますが、これは絶対URIでのみ機能し、エンコード/エスケープされた値を返します(Uri.UnescapeDataString()%20および+をスペースに変更するために使用)。
ロナルド

8
using System.IO;

private String GetFileName(String hrefLink)
{
    return Path.GetFileName(hrefLink.Replace("/", "\\"));
}

もちろん、これはファイル名を解析したことを前提としています。

編集#2:

using System.IO;

private String GetFileName(String hrefLink)
{
    return Path.GetFileName(Uri.UnescapeDataString(hrefLink).Replace("/", "\\"));
}

これは、ファイル名のスペースなどを処理する必要があります。


3
コロンはすべてのプラットフォームのパスで受け入れられないため、この種のハックは、たとえば* nixバリアントで実行されているMono.NETでは失敗する可能性があります。OPが必要とすることを実行するように特別に設計されているため、System.Uriを使用する方が適切です。
richardtallent 2009

1
有効ポイント!私はいつもMonoを忘れています。私はスペースなどを考えましたが、コロンは考えていませんでした。
マイク

2

これはあなたが使用できる私のサンプルです:

        public static string GetFileNameValidChar(string fileName)
    {
        foreach (var item in System.IO.Path.GetInvalidFileNameChars())
        {
            fileName = fileName.Replace(item.ToString(), "");
        }
        return fileName;
    }

    public static string GetFileNameFromUrl(string url)
    {
        string fileName = "";
        if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
        {
            fileName = GetFileNameValidChar(Path.GetFileName(uri.AbsolutePath));
        }
        string ext = "";
        if (!string.IsNullOrEmpty(fileName))
        {
            ext = Path.GetExtension(fileName);
            if (string.IsNullOrEmpty(ext))
                ext = ".html";
            else
                ext = "";
            return GetFileNameValidChar(fileName + ext);

        }

        fileName = Path.GetFileName(url);
        if (string.IsNullOrEmpty(fileName))
        {
            fileName = "noName";
        }
        ext = Path.GetExtension(fileName);
        if (string.IsNullOrEmpty(ext))
            ext = ".html";
        else
            ext = "";
        fileName = fileName + ext;
        if (!fileName.StartsWith("?"))
            fileName = fileName.Split('?').FirstOrDefault();
        fileName = fileName.Split('&').LastOrDefault().Split('=').LastOrDefault();
        return GetFileNameValidChar(fileName);
    }

使用法:

var fileName = GetFileNameFromUrl("http://cdn.p30download.com/?b=p30dl-software&f=Mozilla.Firefox.v58.0.x86_p30download.com.zip");

0

シンプルでわかりやすい:

            Uri uri = new Uri(documentAttachment.DocumentAttachment.PreSignedUrl);
            fileName = Path.GetFileName(uri.LocalPath);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.