對Linux熟悉的讀者可能會對Linux經過wget下載文件有印象,這個工具功能很強大,在.NET環境下提到下載文件大多數人熟悉的是經過System.Net.WebClient進行下載,這個程序集能實現下載的功能,可是有缺陷,若是碰上相似於.../scripts/?dl=417這類的下載連接將沒法正確識別文件名,下載的文件一般會被命名爲dl=417這樣古怪的名字,其實對應的文件名是在訪問這個連接返回結果的HTTP頭中包含的。事實上微軟也提供了避免這些缺陷的程序集System.Net.HttpWebRequest 和 HttpWebResponse,本文將會使用這兩個程序集來實現PowerShell版wget的功能。web
代碼不怎麼複雜,基本上就是建立HttpWebRequest對象,設定UserAgent和CookieContainer以避免在遇到設置防盜鏈的服務器出現沒法下載的狀況。而後經過HttpWebRequest對象的GetResponse()方法從http頭中獲取目標文件的大小以及文件名,以便能在下載到文件時提示當前下載進度,在下載完文件後,列出當前目錄下對應的文件。代碼不復雜,有任何疑問的讀者能夠留言給我,進行交流,下面上代碼:shell
=====文件名:Get-WebFile.ps1=====
function Get-WebFile {
<# Author:fuhj(powershell#live.cn ,http://fuhaijun.com)
Downloads a file or page from the web
.Example
Get-WebFile http://mirrors.cnnic.cn/apache/couchdb/binary/win/1.4.0/setup-couchdb-1.4.0_R16B01.exe
Downloads the latest version of this file to the current directory
#>
[CmdletBinding(DefaultParameterSetName="NoCredentials")]
param(
# The URL of the file/page to download
[Parameter(Mandatory=$true,Position=0)]
[System.Uri][Alias("Url")]$Uri # = (Read-Host "The URL to download")
,
# A Path to save the downloaded content.
[string]$FileName
,
# Leave the file unblocked instead of blocked
[Switch]$Unblocked
,
# Rather than saving the downloaded content to a file, output it.
# This is for text documents like web pages and rss feeds, and allows you to avoid temporarily caching the text in a file.
[switch]$Passthru
,
# Supresses the Write-Progress during download
[switch]$Quiet
,
# The name of a variable to store the session (cookies) in
[String]$SessionVariableName
,
# Text to include at the front of the UserAgent string
[string]$UserAgent = "PowerShellWget/$(1.0)"
)
Write-Verbose "Downloading '$Uri'"
$EAP,$ErrorActionPreference = $ErrorActionPreference, "Stop"
$request = [System.Net.HttpWebRequest]::Create($Uri);
$ErrorActionPreference = $EAP
$request.UserAgent = $(
"{0} (PowerShell {1}; .NET CLR {2}; {3}; http://fuhaijun.com)" -f $UserAgent,
$(if($Host.Version){$Host.Version}else{"1.0"}),
[Environment]::Version,
[Environment]::OSVersion.ToString().Replace("Microsoft Windows ", "Win")
)
$Cookies = New-Object System.Net.CookieContainer
if($SessionVariableName) {
$Cookies = Get-Variable $SessionVariableName -Scope 1
}
$request.CookieContainer = $Cookies
if($SessionVariableName) {
Set-Variable $SessionVariableName -Scope 1 -Value $Cookies
}
try {
$res = $request.GetResponse();
} catch [System.Net.WebException] {
Write-Error $_.Exception -Category ResourceUnavailable
return
} catch {
Write-Error $_.Exception -Category NotImplemented
return
}
if((Test-Path variable:res) -and $res.StatusCode -eq 200) {
if($fileName -and !(Split-Path $fileName)) {
$fileName = Join-Path (Convert-Path (Get-Location -PSProvider "FileSystem")) $fileName
}
elseif((!$Passthru -and !$fileName) -or ($fileName -and (Test-Path -PathType "Container" $fileName)))
{
[string]$fileName = ([regex]'(?i)filename=(.*)$').Match( $res.Headers["Content-Disposition"] ).Groups[1].Value
$fileName = $fileName.trim("\/""'")
$ofs = ""
$fileName = [Regex]::Replace($fileName, "[$([Regex]::Escape(""$([System.IO.Path]::GetInvalidPathChars())$([IO.Path]::AltDirectorySeparatorChar)$([IO.Path]::DirectorySeparatorChar)""))]", "_")
$ofs = " "
if(!$fileName) {
$fileName = $res.ResponseUri.Segments[-1]
$fileName = $fileName.trim("\/")
if(!$fileName) {
$fileName = Read-Host "Please provide a file name"
}
$fileName = $fileName.trim("\/")
if(!([IO.FileInfo]$fileName).Extension) {
$fileName = $fileName + "." + $res.ContentType.Split(";")[0].Split("/")[1]
}
}
$fileName = Join-Path (Convert-Path (Get-Location -PSProvider "FileSystem")) $fileName
}
if($Passthru) {
$encoding = [System.Text.Encoding]::GetEncoding( $res.CharacterSet )
[string]$output = ""
}
[int]$goal = $res.ContentLength
$reader = $res.GetResponseStream()
if($fileName) {
try {
$writer = new-object System.IO.FileStream $fileName, "Create"
} catch {
Write-Error $_.Exception -Category WriteError
return
}
}
[byte[]]$buffer = new-object byte[] 4096
[int]$total = [int]$count = 0
do
{
$count = $reader.Read($buffer, 0, $buffer.Length);
if($fileName) {
$writer.Write($buffer, 0, $count);
}
if($Passthru){
$output += $encoding.GetString($buffer,0,$count)
} elseif(!$quiet) {
$total += $count
if($goal -gt 0) {
Write-Progress "Downloading $Uri" "Saving $total of $goal" -id 0 -percentComplete (($total/$goal)*100)
} else {
Write-Progress "Downloading $Uri" "Saving $total bytes..." -id 0
}
}
} while ($count -gt 0)
$reader.Close()
if($fileName) {
$writer.Flush()
$writer.Close()
}
if($Passthru){
$output
}
}
if(Test-Path variable:res) { $res.Close(); }
if($fileName) {
ls $fileName
}
}
調用方法,以下:apache
Get-WebFile http://mirrors.cnnic.cn/apache/couchdb/binary/win/1.4.0/setup-couchdb-1.4.0_R16B01.exewindows
這裏下載couchdb的最新windows安裝包。服務器
執行效果以下圖所示:cookie
可以看到在下載文件的過程當中會顯示當前已下載數和總的文件大小,而且有進度條顯示當前下載的進度,跟wget看起來是有些神似了。下載完畢後會顯示已經下載文件的狀況。session
做者: 付海軍
出處:http://fuhj02.blog.51cto.com
版權:本文版權歸做者和51cto共有
轉載:歡迎轉載,爲了保存做者的創做熱情,請按要求【轉載】,謝謝
要求:未經做者贊成,必須保留此段聲明;必須在文章中給出原文鏈接且保證內容完整!不然必究法律責任!
我的網站: http://www.fuhaijun.com/ide