検索
連載

サーバにより指定されたファイル名でファイルをダウンロードして保存するには?[C#、VB].NET TIPS

PC用表示 関連情報
Share
Tweet
LINE
Hatena
「.NET TIPS」のインデックス

連載目次

 Webからファイルをダウンロードする際、Webサイトによってはダウンロードするファイルの名前がサーバ側で設定されている場合がある。これは通常、サーバ側でHTTPヘッダに次のような文字列(Content-Dispositionヘッダ)を追加することにより行われる。

Content-Disposition: attachment; filename="<ファイル名>"

Content-Dispositionヘッダの記述例
Content-Dispositionヘッダの仕様についてはRFC 2183(英文)を参照。

 このような設定が行われているファイルを例えばIEでダウンロードする場合、ローカルに保存されるファイルには<ファイル名>部分で指定された名前が自動的に使用されるようになっている。

 しかし、プログラムで例えばWebClientクラス(System.Net名前空間)のDownloadFileメソッドを使用してダウンロードする場合(「TIPS:WebClientクラスでWebページを取得するには?」を参照)には、メソッドのパラメータとして、ダウンロードするファイルのURLとともに、そのファイルの保存時の名前を指定しなければならず、サーバ側で指定されたファイル名は利用できない。

サーバにより指定されたファイル名の取得

 ファイルをダウンロードするときにサーバ側で指定されたファイル名で保存するには、HttpWebRequestクラス/HttpWebResponseクラス(System.Net名前空間)を使用し(「TIPS:WebRequest/WebResponseクラスでWebページを取得するには?」を参照)、ダウンロードする前に上記のようなContent-Dispositionヘッダの内容を読み取り、ファイル名部分を独自に取得すればよい。

 具体的には、ダウンロード時のレスポンス(HttpWebResponseオブジェクト)からHeadersプロパティによりContent-Dispositionヘッダの内容を取得し、そこから「filename=」に続く文字列を切り出してファイル名とする。このような処理を行うサンプル・プログラムを次に示す。

指定された名前でファイルをダウンロードするサンプル・プログラム

 このサンプル・プログラムは、コマンドラインのオプションで指定されたURLからファイルをダウンロードして保存する(Content-Dispositionヘッダによりファイル名が指定されていない場合には、ファイル名を「download.tmp」とする)。

// downnoname.cs

using System;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;

class DownloadWithNoName {
  static void Main(string[] args) {

    if (args.Length == 0)
      return;
    string url = args[0];

    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
    HttpWebResponse res = (HttpWebResponse)req.GetResponse();

    string fileName = "download.tmp";

    // ヘッダ情報からファイル名の取得
    string dispos = res.Headers["Content-Disposition"];

    if (!String.IsNullOrEmpty(dispos)) {

      // filename=<ファイル名>の抜き出し
      Regex re = new Regex(@"
        filename\s*=\s*
        (?:
          ""(?<filename>[^""]*)""
          |
          (?<filename>[^;]*)
        )
        ", RegexOptions.IgnoreCase
         | RegexOptions.IgnorePatternWhitespace);

      Match m = re.Match(dispos);
      if (m.Success) {
        fileName = m.Groups["filename"].Value;
      }
    }

    // ファイルのダウンロード
    using (Stream st = res.GetResponseStream())
    using (FileStream fs = new FileStream(fileName, FileMode.Create)) {
      Byte[] buf = new Byte[1024];
      int count = 0;
      do {
        count = st.Read(buf, 0, buf.Length);
        fs.Write(buf, 0, count);
      } while (count != 0);
    }
    res.Close();
  }
}

// コンパイル方法:csc downnoname.cs

ファイルをダウンロードするC#のサンプル・プログラム(downnoname.cs)
downnoname.csのダウンロード

' downnoname.vb

Imports System
Imports System.IO
Imports System.Net
Imports System.Text.RegularExpressions

Class DownloadWithNoName
  Shared Sub main(ByVal args As String())

    If args.Length = 0 Then
      Return
    End If
    Dim url As String = args(0)

    Dim req As HttpWebRequest _
      = CType(WebRequest.Create(url), HttpWebRequest)
    Dim res As HttpWebResponse _
      = CType(req.GetResponse(), HttpWebResponse)

    Dim fileName As String = "download.tmp"

    ' ヘッダ情報からファイル名の取得
    Dim dispos As String = res.Headers("Content-Disposition")

    If Not String.IsNullOrEmpty(dispos) Then

      ' filename=<ファイル名>の抜き出し
      Dim re As New Regex( _
        "filename\s*=\s*           " & _
        "(?:                       " & _
        "  ""(?<filename>[^""]*)"" " & _
        "  |                       " & _
        "  (?<filename>[^;]*)      " & _
        ")                         " _
        , RegexOptions.IgnoreCase _
        Or RegexOptions.IgnorePatternWhitespace)

      Dim m As Match = re.Match(dispos)
      If m.Success Then
        fileName = m.Groups("filename").Value
      End If
    End If

    ' ファイルのダウンロード
    Using st As Stream = res.GetResponseStream()
      Using fs As New FileStream(fileName, FileMode.Create)
        Dim buf(1024) As Byte
        Dim count As Integer = 0
        Do
          count = st.Read(buf, 0, buf.Length)
          fs.Write(buf, 0, count)
        Loop While count <> 0
      End Using
    End Using
    res.Close()
  End Sub
End Class

' コンパイル方法:vbc downnoname.vb

ファイルをダウンロードするVBのサンプル・プログラム(downnoname.vb)
downnoname.vbのダウンロード

 Content-Dispositionヘッダの「filename=」に続くファイル名部分は、ダブル・クオーテーションで囲まれている場合とそうでない場合があるため、ここでは正規表現を使用して必要な個所を抜き出している(正規表現のパターン内での改行やRegexOptions.IgnorePatternWhitespaceについては「TIPS:正規表現のパターン内にコメント文を記述するには?」を参照)。なお、「filename="<ファイル名>"」は通常、Content-Dispositionヘッダの末尾に記述されるようである。

カテゴリ:クラス・ライブラリ 処理対象:ネットワーク
使用ライブラリ:HttpWebRequestクラス(System.Net名前空間)
使用ライブラリ:HttpWebResponseクラス(System.Net名前空間)
関連TIPS:WebClientクラスでWebページを取得するには?
関連TIPS:WebRequest/WebResponseクラスでWebページを取得するには?
関連TIPS:正規表現のパターン内にコメント文を記述するには?

「.NET TIPS」のインデックス

.NET TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

ページトップに戻る