下载文件并自动保存到文件夹中

10

我正在尝试制作一个用于从我的网站下载文件的用户界面。该网站包含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


1
请在问题中直接发布您的代码相关部分,不要使用外部链接。 - Anders Abel
你是否试图覆盖浏览器对保存文件UI的实现? 如果你将文件写入流并指定内容类型为文件,那么这将更容易... 另外,如果我没记错的话,你没有访问客户端文件系统的权限...你不能将文件下载到客户端路径,因此将其作为输入是没有用的。 - Whimsical
我认为这是客户端软件,即在客户机上作为进程运行。 - J. Steen
textBox1.Text的值是多少? - Bob Vale
所以你在谈论嵌入式Internet Explorer控件(即WebBrowser类)?也许你应该明确地说出来。虽然从你的方法名称中可以看出,但我一开始并没有注意到这一点。 - CodesInChaos
显示剩余5条评论
6个回答

20
我的程序完全符合您的要求,没有任何提示或其他信息,请参见以下代码。
此代码将在必要时创建所有必要的目录:
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
    }

因此,使用这两个代码片段,您可以创建所有目录,然后告诉下载器(不提示您将文件下载到该位置)。


如果从服务器的受保护文件夹中获取该文件,应该怎么办?在这种情况下,您无法直接从服务器获取文件,但是如果服务器已经处理了文件以下载并发送回浏览器,则可以获取该文件。在这种情况下,如何保存该文件而不显示保存文件提示框?有什么建议吗? - Vipin Kr. Singh
@VipinKr.Singh那正是我现在面临的情况。 - Leo Gurdian

20

如果您不想使用 "WebClient" 或者需要使用 System.Windows.Forms.WebBrowser,例如因为您想先模拟登录,那么您可以使用这个扩展的 WebBrowser。它钩取了 Windows URLMON 库中的 "URLDownloadToFile" 方法,并使用 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);
            }
        }
    }

3
你太棒了!我花了三天的时间寻找这种解决方案! - Maciej
1
完美答案。 - ujjaval
1
@dataCore 非常感谢!非常有帮助。没有提示。我喜欢使用p/Invoke。:) - Leo Gurdian
1
这正是我所需要的。 - Kevbo
1
太棒了!!!非常感谢。 - Namachi R
显示剩余5条评论

16
为什么不完全绕过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");
    }

2

你的解决方案基本可行。有几个要点需要考虑以保持简单:

  • 仅针对您知道将发生下载的特定URL取消默认导航,否则用户将无法导航到任何地方。这意味着您不应更改网站下载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");
}

这个解决方案应该是可行的,但很容易被破坏。尝试考虑一些列出可下载文件的网络服务,并为其制作自定义UI。这样会更简单,您将控制整个过程。


我也尝试过制作自定义UI,但没有成功。我还处于非常基础的学习阶段,经常卡住。但感谢您的时间和帮助,我会回来更新状态的。 - Victor Bjelkholm
从URL中获取文件名是可能的,只需要尝试使用以下代码:string filename = Path.GetFileName(e.Url.LocalPath) - rotman
是的,但有很多情况下这并没有意义,特别是如果下载URL的形式为“download?id=x”,你将会得到每个文件名的“download”。 - Julien Lebosquain

1

请查看http://www.csharp-examples.net/download-files/和WebClient的MSDN文档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!");
}

问题在于我希望我的应用程序下载文件,而不是运行在WebBrowser中的Internet Explorer。当我点击一个zip文件的链接时,会出现保存文件弹出窗口并要求我选择一些东西。我希望用户单击zip时自动下载文件。 - Victor Bjelkholm

0
一个更简单的解决方案是使用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");
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接