サイトからファイルをダウンロードするためのUIを作成しようとしています。サイトにはZipファイルがあり、これらはユーザーが入力したディレクトリにダウンロードする必要があります。ただし、ファイルのダウンロードに成功せず、一時フォルダーからファイルが開きます。
コード:
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
e.Cancel = true;
string filepath = null;
filepath = textBox1.Text;
WebClient client = new WebClient();
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileAsync(e.Url, filepath);
}
完全なソースコード: http://en.paidpaste.com/LqEmiQ
WebClientのファイル処理部分を完全にバイパスしないのはなぜですか。おそらくこれに似たもの:
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
e.Cancel = true;
WebClient client = new WebClient();
client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
client.DownloadDataAsync(e.Url);
}
void client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
string filepath = textBox1.Text;
File.WriteAllBytes(filepath, e.Result);
MessageBox.Show("File downloaded");
}
私のプログラムはあなたが望んでいることを正確に行います。プロンプトも何もありません。次のコードをご覧ください。
このコードは、必要なディレクトリがすべて存在しない場合は作成します。
Directory.CreateDirectory(C:\dir\dira\dirb); // This code will create all of these directories
このコードは、指定されたファイルを指定されたディレクトリにダウンロードします(前のスニペットによって作成された後:
private void install()
{
WebClient webClient = new WebClient(); // Creates a webclient
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed); // Uses the Event Handler to check whether the download is complete
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged); // Uses the Event Handler to check for progress made
webClient.DownloadFileAsync(new Uri("http://www.com/newfile.Zip"), @"C\newfile.Zip"); // Defines the URL and destination directory for the downloaded file
}
したがって、これらの2つのコードを使用して、すべてのディレクトリを作成し、ダウンローダーに指示することができます(その場所にファイルをダウンロードするよう求められません)。
「WebClient」を使用したくない場合、および/またはSystem.Windows.Forms.WebBrowserを使用する必要がある場合最初にログインをシミュレートするため、Windows URLMON Libから「URLDownloadToFile」メソッドをフックし、WebBrowserのコンテキストを使用するこの拡張WebBrowserを使用できます。
情報: http://www.pinvoke.net/default.aspx/urlmon/URLDownloadToFile%20.html
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace dataCoreLib.Net.Webpage
{
public class WebBrowserWithDownloadAbility : WebBrowser
{
/// <summary>
/// The URLMON library contains this function, URLDownloadToFile, which is a way
/// to download files without user prompts. The ExecWB( _SAVEAS ) function always
/// prompts the user, even if _DONTPROMPTUSER parameter is specified, for "internet
/// security reasons". This function gets around those reasons.
/// </summary>
/// <param name="callerPointer">Pointer to caller object (AX).</param>
/// <param name="url">String of the URL.</param>
/// <param name="filePathWithName">String of the destination filename/path.</param>
/// <param name="reserved">[reserved].</param>
/// <param name="callBack">A callback function to monitor progress or abort.</param>
/// <returns>0 for okay.</returns>
/// source: http://www.pinvoke.net/default.aspx/urlmon/URLDownloadToFile%20.html
[DllImport("urlmon.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern Int32 URLDownloadToFile(
[MarshalAs(UnmanagedType.IUnknown)] object callerPointer,
[MarshalAs(UnmanagedType.LPWStr)] string url,
[MarshalAs(UnmanagedType.LPWStr)] string filePathWithName,
Int32 reserved,
IntPtr callBack);
/// <summary>
/// Download a file from the webpage and save it to the destination without promting the user
/// </summary>
/// <param name="url">the url with the file</param>
/// <param name="destinationFullPathWithName">the absolut full path with the filename as destination</param>
/// <returns></returns>
public FileInfo DownloadFile(string url, string destinationFullPathWithName)
{
URLDownloadToFile(null, url, destinationFullPathWithName, 0, IntPtr.Zero);
return new FileInfo(destinationFullPathWithName);
}
}
}
まあ、あなたのソリューションはほとんど動作します。シンプルにするために考慮すべきことがいくつかあります。
ダウンロードが発生することがわかっている特定のURLについてのみデフォルトのナビゲーションをキャンセルします。そうしないと、ユーザーはどこにもナビゲートできません。つまり、WebサイトのダウンロードURLを変更する必要はありません。
DownloadFileAsync
はContent-Disposition
ヘッダーでサーバーから報告された名前を知らないため、指定するか、可能であれば元のURLから計算する必要があります。フォルダを指定して、ファイル名が自動的に取得されることを期待することはできません。
DownloadCompleted
コールバックからのダウンロードサーバーエラーを処理する必要があります。これは、Webブラウザーコントロールがもう処理しないためです。
サンプルコード。textBox1
で指定されたディレクトリにダウンロードされますが、ファイル名はランダムで、追加のエラー処理はありません。
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e) {
/* change this to match your URL. For example, if the URL always is something like "getfile.php?file=xxx", try e.Url.ToString().Contains("getfile.php?") */
if (e.Url.ToString().EndsWith(".Zip")) {
e.Cancel = true;
string filePath = Path.Combine(textBox1.Text, Path.GetRandomFileName());
var client = new WebClient();
client.DownloadFileCompleted += client_DownloadFileCompleted;
client.DownloadFileAsync(e.Url, filePath);
}
}
private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) {
MessageBox.Show("File downloaded");
}
このソリューションは動作するはずですが、非常に簡単に破ることができます。ダウンロード可能なファイルをリストするWebサービスを検討し、カスタムUIを作成してください。よりシンプルになり、プロセス全体を制御できます。
http://www.csharp-examples.net/download-files/ とwebclientのmsdn docsをご覧ください http://msdn.Microsoft.com/en-us/ library/system.net.webclient.aspx
私の提案は、同期ダウンロードをより簡単にすることです。これを試行しているときに、webclientパラメーターが間違っているか、ファイルの形式が間違っているかどうかを知ることができます。
コードサンプルは次のとおりです。
private void btnDownload_Click(object sender, EventArgs e)
{
string filepath = textBox1.Text;
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
webClient.DownloadFileAsync(new Uri("http://mysite.com/myfile.txt"), filepath);
}
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
private void Completed(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("Download completed!");
}
もっと簡単な解決策は、Chromeを使用してファイルをダウンロードすることです。この方法では、保存ボタンを手動でクリックする必要はありません。
using System;
using System.Diagnostics;
using System.ComponentModel;
namespace MyProcessSample
{
class MyProcess
{
public static void Main()
{
Process myProcess = new Process();
myProcess.Start("chrome.exe","http://www.com/newfile.Zip");
}
}
}