HTTPで複数ファイルをPOSTしたい
WebClientクラスにはUploadFileとかDownloadFileとか便利なメソッドがたくさんありますが、複数ファイルのPOST機能は用意されていないらしく、仕方なくWebRequestを使って自作した。
- RequestのContentTypeは「multipart/form-data; boundary=1234567890」とする。(boundaryは何でも良さそうなので、適当な英数字を指定)
- RequestのStreamには、区切り文字列、ヘッダ、ファイル内容を、ファイルの数だけ繰り返す。この時、改行コードの位置と個数は重要。
--1234567890 Content-Disposition: form-data; name="フォーム名1"; filename="ファイル名1" Content-Type: application/octet-stream Content-Transfer-Encoding: binary (ここにファイル内容) --1234567890 Content-Disposition: form-data; name="フォーム名2"; filename="ファイル名2" Content-Type: application/octet-stream Content-Transfer-Encoding: binary (ここにファイル内容) --1234567890 Content-Disposition: form-data; name="フォーム名3"; filename="ファイル名3" ・ ・ ・ 以下略
コードはこんな感じ
using System; using System.Collections.Generic; using System.Net; using System.IO; namespace Upluad { class Program { static void Main(string[] args) { string url = "http://localhost:1588/Upload.aspx"; List<string> files = new List<string>(); files.Add("C:\\Tmp\\up\\test.zip"); files.Add("C:\\Tmp\\up\\test2.zip"); UploadFiles(url, files); } private static void UploadFiles(string url, List<string> files) { string tick = Environment.TickCount.ToString(); System.Text.Encoding enc = System.Text.Encoding.UTF8; WebRequest req = WebRequest.Create(url); req.Method = "POST"; req.ContentType = "multipart/form-data; boundary=" + tick; byte[] boundary = enc.GetBytes("--" + tick); byte[] crlf = enc.GetBytes("\r\n"); List<byte[]> headers = new List<byte[]>(); //ヘッダの作成とデータサイズの計算 long contentLen = 0; for (int i = 0; i < files.Count; i++) { //ヘッダ string header = "Content-Disposition: form-data; name=\"upfile" + i.ToString() + "\"; filename=\"" + Path.GetFileName(files[i]) + "\"\r\n" + "Content-Type: application/octet-stream\r\n" + "Content-Transfer-Encoding: binary\r\n\r\n"; headers.Add(enc.GetBytes(header)); //1ファイルごとのデータサイズ contentLen += headers[i].Length + new FileInfo(files[i]).Length; } //全体のデータサイズ req.ContentLength = contentLen + ((boundary.Length + crlf.Length + crlf.Length) * files.Count) + boundary.Length; //送信 using (Stream reqStream = req.GetRequestStream()) { for (int i = 0; i < files.Count; i++) { //送信ファイル using (FileStream fs = new FileStream(files[i], FileMode.Open, FileAccess.Read)) { //ヘッダ reqStream.Write(boundary, 0, boundary.Length); reqStream.Write(crlf, 0, crlf.Length); reqStream.Write(headers[i], 0, headers[i].Length); //ファイル内容 byte[] buf = new byte[0x1000]; int readSize = 0; while (true) { readSize = fs.Read(buf, 0, buf.Length); if (readSize == 0) break; reqStream.Write(buf, 0, readSize); } reqStream.Write(crlf, 0, crlf.Length); } } reqStream.Write(boundary, 0, boundary.Length); WebResponse res = req.GetResponse(); } } } }