/*** 2015 October 7**** The author disclaims copyright to this source code. In place of** a legal notice, here is a blessing:**** May you do good and not evil.** May you find forgiveness for yourself and forgive others.** May you share freely, never taking more than you give.***************************************************************************** This file contains C# code to download a single file based on a URI.*/using System;using System.ComponentModel;using System.Diagnostics;using System.IO;using System.Net;using System.Reflection;using System.Runtime.InteropServices;using System.Threading;///////////////////////////////////////////////////////////////////////////////#region Assembly Metadata[assembly: AssemblyTitle("GetFile Tool")][assembly: AssemblyDescription("Download a single file based on a URI.")][assembly: AssemblyCompany("SQLite Development Team")][assembly: AssemblyProduct("SQLite")][assembly: AssemblyCopyright("Public Domain")][assembly: ComVisible(false)][assembly: Guid("5c4b3728-1693-4a33-a218-8e6973ca15a6")][assembly: AssemblyVersion("1.0.*")]#if DEBUG[assembly: AssemblyConfiguration("Debug")]#else[assembly: AssemblyConfiguration("Release")]#endif#endregion///////////////////////////////////////////////////////////////////////////////namespace GetFile{/// <summary>/// This enumeration is used to represent all the possible exit codes from/// this tool./// </summary>internal enum ExitCode{/// <summary>/// The file download was a success./// </summary>Success = 0,/// <summary>/// The command line arguments are missing (i.e. null). Generally,/// this should not happen./// </summary>MissingArgs = 1,/// <summary>/// The wrong number of command line arguments was supplied./// </summary>WrongNumArgs = 2,/// <summary>/// The URI specified on the command line could not be parsed as a/// supported absolute URI./// </summary>BadUri = 3,/// <summary>/// The file name portion of the URI specified on the command line/// could not be extracted from it./// </summary>BadFileName = 4,/// <summary>/// The temporary directory is either invalid (i.e. null) or does not/// represent an available directory./// </summary>BadTempPath = 5,/// <summary>/// An exception was caught in <see cref="Main" />. Generally, this/// should not happen./// </summary>Exception = 6,/// <summary>/// The file download was canceled. This tool does not make use of/// the <see cref="WebClient.CancelAsync" /> method; therefore, this/// should not happen./// </summary>DownloadCanceled = 7,/// <summary>/// The file download encountered an error. Further information about/// this error should be displayed on the console./// </summary>DownloadError = 8}///////////////////////////////////////////////////////////////////////////internal static class Program{#region Private Data/// <summary>/// This is used to synchronize multithreaded access to the/// <see cref="previousPercent" /> and <see cref="exitCode"/>/// fields./// </summary>private static readonly object syncRoot = new object();////////////////////////////////////////////////////////////////////////// <summary>/// This event will be signed when the file download has completed,/// even if the file download itself was canceled or unsuccessful./// </summary>private static EventWaitHandle doneEvent;////////////////////////////////////////////////////////////////////////// <summary>/// The previous file download completion percentage seen by the/// <see cref="DownloadProgressChanged" /> event handler. This value/// is never decreased, nor is it ever reset to zero./// </summary>private static int previousPercent = 0;////////////////////////////////////////////////////////////////////////// <summary>/// This will be the exit code returned by this tool after the file/// download completes, successfully or otherwise. This value is only/// changed by the <see cref="DownloadFileCompleted" /> event handler./// </summary>private static ExitCode exitCode = ExitCode.Success;#endregion///////////////////////////////////////////////////////////////////////#region Private Support Methods/// <summary>/// This method displays an error message to the console and/or/// displays the command line usage information for this tool./// </summary>/// <param name="message">/// The error message to display, if any./// </param>/// <param name="usage">/// Non-zero to display the command line usage information./// </param>private static void Error(string message,bool usage){if (message != null)Console.WriteLine(message);string fileName = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);Console.WriteLine(String.Format("usage: {0} <uri> [fileName]", fileName));}////////////////////////////////////////////////////////////////////////// <summary>/// This method attempts to determine the file name portion of the/// specified URI./// </summary>/// <param name="uri">/// The URI to process./// </param>/// <returns>/// The file name portion of the specified URI -OR- null if it cannot/// be determined./// </returns>private static string GetFileName(Uri uri){if (uri == null)return null;string pathAndQuery = uri.PathAndQuery;if (String.IsNullOrEmpty(pathAndQuery))return null;int index = pathAndQuery.LastIndexOf('/');if ((index < 0) || (index == pathAndQuery.Length))return null;return pathAndQuery.Substring(index + 1);}#endregion///////////////////////////////////////////////////////////////////////#region Private Event Handlers/// <summary>/// This method is an event handler that is called when the file/// download completion percentage changes. It will display progress/// on the console. Special care is taken to make sure that progress/// events are not displayed out-of-order, even if duplicate and/or/// out-of-order events are received./// </summary>/// <param name="sender">/// The source of the event./// </param>/// <param name="e">/// Information for the event being processed./// </param>private static void DownloadProgressChanged(object sender,DownloadProgressChangedEventArgs e){if (e != null){int percent = e.ProgressPercentage;lock (syncRoot){if (percent > previousPercent){Console.Write('.');if ((percent % 10) == 0)Console.Write(" {0}% ", percent);previousPercent = percent;}}}}////////////////////////////////////////////////////////////////////////// <summary>/// This method is an event handler that is called when the file/// download has completed, successfully or otherwise. It will/// display the overall result of the file download on the console,/// including any <see cref="Exception" /> information, if applicable./// The <see cref="exitCode" /> field is changed by this method to/// indicate the overall result of the file download and the event/// within the <see cref="doneEvent" /> field will be signaled./// </summary>/// <param name="sender">/// The source of the event./// </param>/// <param name="e">/// Information for the event being processed./// </param>private static void DownloadFileCompleted(object sender,AsyncCompletedEventArgs e){if (e != null){lock (syncRoot){if (previousPercent < 100)Console.Write(' ');}if (e.Cancelled){Console.WriteLine("Canceled");lock (syncRoot){exitCode = ExitCode.DownloadCanceled;}}else{Exception error = e.Error;if (error != null){Console.WriteLine("Error: {0}", error);lock (syncRoot){exitCode = ExitCode.DownloadError;}}else{Console.WriteLine("Done");}}}if (doneEvent != null)doneEvent.Set();}#endregion///////////////////////////////////////////////////////////////////////#region Program Entry Point/// <summary>/// This is the entry-point for this tool. It handles processing the/// command line arguments, setting up the web client, downloading the/// file, and saving it to the file system./// </summary>/// <param name="args">/// The command line arguments./// </param>/// <returns>/// Zero upon success; non-zero on failure. This will be one of the/// values from the <see cref="ExitCode" /> enumeration./// </returns>private static int Main(string[] args){//// NOTE: Sanity check the command line arguments.//if (args == null){Error(null, true);return (int)ExitCode.MissingArgs;}if ((args.Length < 1) || (args.Length > 2)){Error(null, true);return (int)ExitCode.WrongNumArgs;}//// NOTE: Attempt to convert the first (and only) command line// argument to an absolute URI.//Uri uri;if (!Uri.TryCreate(args[0], UriKind.Absolute, out uri)){Error("Could not create absolute URI from argument.", false);return (int)ExitCode.BadUri;}//// NOTE: If a file name was specified on the command line, try to// use it (without its directory name); otherwise, fallback// to using the file name portion of the URI.//string fileName = (args.Length == 2) ?Path.GetFileName(args[1]) : null;if (String.IsNullOrEmpty(fileName)){//// NOTE: Attempt to extract the file name portion of the URI// we just created.//fileName = GetFileName(uri);if (fileName == null){Error("Could not extract file name from URI.", false);return (int)ExitCode.BadFileName;}}//// NOTE: Grab the temporary path setup for this process. If it is// unavailable, we will not continue.//string directory = Path.GetTempPath();if (String.IsNullOrEmpty(directory) ||!Directory.Exists(directory)){Error("Temporary directory is invalid or unavailable.", false);return (int)ExitCode.BadTempPath;}try{//// HACK: For use of the TLS 1.2 security protocol because some// web servers fail without it. In order to support the// .NET Framework 2.0+ at compilation time, must use its// integer constant here.//ServicePointManager.SecurityProtocol =(SecurityProtocolType)0xC00;using (WebClient webClient = new WebClient()){//// NOTE: Create the event used to signal completion of the// file download.//doneEvent = new ManualResetEvent(false);//// NOTE: Hookup the event handlers we care about on the web// client. These are necessary because the file is// downloaded asynchronously.//webClient.DownloadProgressChanged +=new DownloadProgressChangedEventHandler(DownloadProgressChanged);webClient.DownloadFileCompleted +=new AsyncCompletedEventHandler(DownloadFileCompleted);//// NOTE: Build the fully qualified path and file name,// within the temporary directory, where the file to// be downloaded will be saved.//fileName = Path.Combine(directory, fileName);//// NOTE: If the file name already exists (in the temporary)// directory, delete it.//// TODO: Perhaps an error should be raised here instead?//if (File.Exists(fileName))File.Delete(fileName);//// NOTE: After kicking off the asynchronous file download// process, wait [forever] until the "done" event is// signaled.//Console.WriteLine("Downloading \"{0}\" to \"{1}\"...", uri, fileName);webClient.DownloadFileAsync(uri, fileName);doneEvent.WaitOne();}lock (syncRoot){return (int)exitCode;}}catch (Exception e){//// NOTE: An exception was caught. Report it via the console// and return failure.//Error(e.ToString(), false);return (int)ExitCode.Exception;}}#endregion}}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。