在上個(gè)專題《Java網(wǎng)絡(luò)編程之URI、URL研究(上)》中我們介紹了URI、URL的慨念和體系結(jié)構(gòu),以及如何使用URI在本文中我將繼續(xù)向大家介紹如何使用URL和MIME(多用途的網(wǎng)際郵件擴(kuò)充協(xié)議)的概念以及它如何與URL發(fā)生聯(lián)系的。
網(wǎng)絡(luò)API通過提供URL類讓我們能在源代碼層使用URL。每一個(gè)URL對(duì)象都封裝了資源的標(biāo)識(shí)符和協(xié)議處理程序。前面的技巧顯示了獲得
URL對(duì)象的途徑之一是調(diào)用URI對(duì)象的toURL()方法。但是這種選擇不一定方便(為什么在需要URL對(duì)象的時(shí)候必須建立URI對(duì)象呢?)。作為代
替,你可以調(diào)用URL構(gòu)造函數(shù)來建立URL對(duì)象。你也可以調(diào)用URL的方法來提取URL的組件,打開一個(gè)輸入流(input
stream)從資源中讀取信息,獲得某個(gè)能方便檢索資源數(shù)據(jù)的對(duì)象的引用,比較兩個(gè)URL對(duì)象中的URL,獲得到資源的連接對(duì)象,該連接對(duì)象允許代碼了
解(并寫入)更多的資源的信息。
URL類有六個(gè)構(gòu)造函數(shù)。其中最簡單的是URL(String
url),它有一個(gè)String類型的參數(shù),把URL分解為自己的組件,并把這些組件存儲(chǔ)在一個(gè)新的URL對(duì)象中。如果某個(gè)URL沒有包含協(xié)議處理程序或
該URL的協(xié)議是未知的,其它的五個(gè)構(gòu)造函數(shù)會(huì)產(chǎn)生一個(gè)java.net.MalformedURLException對(duì)象。
下面的代碼片斷演示了使用URL(String url)建立一個(gè)URL對(duì)象,該對(duì)象封裝了一個(gè)簡單的URL組件和http協(xié)議處理程序。
URL url = new URL ("
一旦擁有了URL對(duì)象,你就可以使用getAuthority()、getDefaultPort()、 getFile()、
getHost()、 getPath()、getPort()、
getProtocol()、getQuery()、getRef()和getUserInfo(). The
getDefaultPort()等方法提取各種組件。如果URL中沒有指定端口的部分,getDefaultPort()方法返回URL對(duì)象的協(xié)議處理
程序使用(資源定位)的默認(rèn)端口。getFile()方法返回路徑和查詢組件的結(jié)合體。getProtocol()方法返回決定資源的連接類型(例如
http、mailto、ftp)的協(xié)議的名稱。getRef()方法返回URL的部分片斷(我們所知道的引用)。最后,getUserInfo()方法
返回授權(quán)機(jī)構(gòu)組件的用戶信息部分。在這些URL組件提取方法中,如果某些組件不存在(如果沒有給URL對(duì)象的協(xié)議處理程序指定默認(rèn)的端口,它也返回-
1),這些方法就返回null或-1。
作為這些組件提取方法的補(bǔ)充,你還可以調(diào)用openStream()方法檢索java.io.InputStream引用。使用這種引用,你可以用面向字節(jié)的方式讀取資源。
列表4是URLDemo1的源代碼。該程序從命令行參數(shù)建立了一個(gè)URL對(duì)象,調(diào)用URL組件提取方法來檢索該URL的組件,調(diào)用URL的
openStream()方法打開與資源的連接并返回一個(gè)用于從資源讀取字節(jié)數(shù)據(jù)的InputStream引用,讀取/打印這些字節(jié),關(guān)閉輸入流。
列表4: URLDemo1.java
// URLDemo1.java
import java.io.*;
import java.net.*;
class URLDemo1
{
public static void main (String [] args) throws IOException
{
if (args.length != 1)
{
System.err.println ("usage: java URLDemo1 url");
return;
}
URL url = new URL (args [0]);
System.out.println ("Authority = "+ url.getAuthority ());
System.out.println ("Default port = " +url.getDefaultPort ());
System.out.println ("File = " +url.getFile ());
System.out.println ("Host = " +url.getHost ());
System.out.println ("Path = " +url.getPath ());
System.out.println ("Port = " +url.getPort ());
System.out.println ("Protocol = " +url.getProtocol ());
System.out.println ("Query = " +url.getQuery ());
System.out.println ("Ref = " +url.getRef ());
System.out.println ("User Info = " +url.getUserInfo ());
System.out.print ('\n');
InputStream is = url.openStream ();
int ch;
while ((ch = is.read ()) != -1)
System.out.print ((char) ch);
is.close ();
}
}
<html>
<head>
<title>
Java Jeff - Articles
</title>
<meta http-equiv=Content-Type content="text/html;
charset=ISO-8859-1">
<meta name=author content="Jeff Friesen">
<meta name=keywords content="java, virtual machine">
<script language=JavaScript>
if (navigator.appName == "Netscape")
document.write ("<br>");
</script>
</head>
<body bgcolor=#000000>
<center>
<table border=1 cellpadding=5 cellspacing=0>
<tr>
<td>
<table cellpadding=0 cellspacing=0>
<tr>
<td>
<a href=informit/informit.html>
<img alt=InformIT border=0 src=informit.gif></a>
</td>
</tr>
</table>
</td>
<td align=middle>
<img src=title.gif><br>
<a href=../welcome/welcome.html>
<img alt="Welcome to Java Jeff!" border=0 src=jupiter.jpg>
</a><br>
<img src=../common/clear_dot.gif vspace=5><br>
<a href=../ads/ads.html>
<img alt="Welcome to Java Jeff!" border=0
src=jupiter.jpg>
</td>
<td>
<table cellpadding=0 cellspacing=0>
<tr>
<td>
<a href=javaworld/javaworld.html>
<img alt=JavaWorld border=0 src=javaworld.gif></a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</center>
<br>
<font color=#ffffff>
<center>
Best viewed at a resolution of 1024x768 or higher.<br>
<img src=../common/clear_dot.gif vspace=5><br>
<i>
Copyright © 2001-2002, Jeff Friesen. All rights
reserved.
</i>
<p>
<a href=../index.html>
<img alt=Back border=0 src=../common/back.gif></a>
</center>
</font>
</body>
</html>
在上面的信息中,輸出標(biāo)識(shí)符80是默認(rèn)端口,HTTP是協(xié)議。上面給出的是輸出的HTML頁面的源代碼。
URL的openStream()方法通常返回抽象的InputStream類的一個(gè)具體的子類所建立的對(duì)象的引用。這意味著你必須按字節(jié)次序
讀取資源數(shù)據(jù),這種做法是恰當(dāng)?shù)模驗(yàn)槟悴恢缹⒁x取的數(shù)據(jù)是什么類型的。如果你事先知道要讀取的數(shù)據(jù)是文本的,并且每一行以換行符(\n)結(jié)束,你就
可以按行讀取而不是按字節(jié)讀取數(shù)據(jù)了。
下面的代碼片斷演示了把一個(gè)InputStream對(duì)象包裝進(jìn)java.io.InputStreamReader對(duì)象以從8位過渡到16
位字符,把結(jié)果對(duì)象包裝進(jìn)java.io.BufferedReader對(duì)象以訪問BufferedReader的readLine()方法,并調(diào)用
readLine()方法從資源讀取文本的所有行。
InputStream is = url.openStream ();
BufferedReader br = new BufferedReader (new InputStreamReader (is));
String line;
while ((line = br.readLine ()) != null)
System.out.println (line);
is.close ();
有時(shí)候按字節(jié)的次序讀取數(shù)據(jù)并不方便。例如,如果資源是JPEG文件,那么獲取一個(gè)圖像處理過程并向該過程注冊(cè)一個(gè)用戶使用數(shù)據(jù)的方法更好。當(dāng)圖像完整下載后立即顯示它并不困難。如果出現(xiàn)這種情況,你就有必要使用getContent()方法。
當(dāng)調(diào)用getContent()方法時(shí),它會(huì)返回某種對(duì)象的Object引用,而你可以調(diào)用該對(duì)象的方法(在轉(zhuǎn)換成適當(dāng)?shù)念愋秃螅捎酶奖愕姆绞綑z索數(shù)據(jù)。但是在調(diào)用該方法前,你必須使用instanceof驗(yàn)證對(duì)象的類型,防止類產(chǎn)生異常。
對(duì)于JPEG資源,getContent()返回一個(gè)對(duì)象,該對(duì)象的類實(shí)現(xiàn)了java.awt.Image.ImageProducer接
口。下面的代碼片斷演示了使用instanceof驗(yàn)證對(duì)象是ImageProducer的,并進(jìn)行了轉(zhuǎn)換。接下來可以調(diào)用ImageProducer方
法注冊(cè)一個(gè)用戶并初始化圖像的使用過程。
URL url = new URL (args [0]);
Object o = url.getContent ();
if (o instanceof ImageProducer)
{
ImageProducer ip = (ImageProducer) o;
// ...
}
技巧
調(diào)用URL的equals(Object o)和sameFile(Object o)方法來決定兩個(gè)URL是否相同。第一個(gè)方法包含了比較的片斷,而第二個(gè)方法沒有包含。你可以參閱SDK文檔查找更多信息。
查看一下getContent()方法的源代碼,你會(huì)找到openConnection().getContent()。此外,查看一下
openStream()方法的源代碼,你會(huì)發(fā)現(xiàn)openConnection().getInputStream()。每個(gè)方法都首先調(diào)用URL的
openConnection()方法。這個(gè)方法返回抽象的java.net.URLConnection類(描述與某些資源的連接)的一個(gè)子類建立的對(duì)
象的引用。URLConnection的方法反映了資源和連接的細(xì)節(jié)信息,使我們能編寫代碼向資源寫入信息。
列表5的URLDemo2源代碼演示了openConnection(),以及調(diào)用一些URLConnection的方法。
列表5: URLDemo2.java
// URLDemo2.java
import java.io.*;
import java.net.*;
import java.util.*;
class URLDemo2
{
public static void main (String [] args) throws IOException
{
if (args.length != 1)
{
System.err.println ("usage: java URLDemo2 url");
return;
}
URL url = new URL (args [0]);
// 返回代表某個(gè)資源的連接的新的特定協(xié)議對(duì)象的引用
URLConnection uc = url.openConnection ();
// 進(jìn)行連接
uc.connect ();
// 打印多種頭部字段的內(nèi)容
Map m = uc.getHeaderFields ();
Iterator i = m.entrySet ().iterator ();
while (i.hasNext ())
System.out.println (i.next ());
// 如果資源允許輸入和輸出操作就找出來
System.out.println ("Input allowed = " +uc.getDoInput ());
System.out.println ("Output allowed = " +uc.getDoOutput ());
}
}?
在
對(duì)openConnection()的調(diào)用返回后,調(diào)用了connect()方法--用于建立某種資源的連接。(盡管openConnection()方
法返回一個(gè)連接對(duì)象的引用,但是openConnection()不會(huì)連接到資源)。
URLConnection的getHeaderFields()方法返回一個(gè)對(duì)象的應(yīng)用,該對(duì)象的類實(shí)現(xiàn)了java.util.Map接口。該圖表
(map)包含頭部名稱和值的集合。什么是頭部(header)?頭部是基于文本的名稱/值對(duì),它識(shí)別資源數(shù)據(jù)的類型、數(shù)據(jù)的長度等等。
Date=[Sun, 17 Feb 2002 17:49:32 GMT]
Connection=[Keep-Alive]
Content-Type=[text/html; charset=iso-8859-1]
Accept-Ranges=[bytes]
Content-Length=[7214]
null=[HTTP/1.1 200 OK]
ETag=["4470e-1c2e-3bf29d5a"]
Keep-Alive=[timeout=15, max=100]
Server=[Apache/1.3.19 (Unix) Debian/GNU]
Last-Modified=[Wed, 14 Nov 2001 16:35:38 GMT]
Input allowed = true
Output allowed = false?
上面的輸出識(shí)別了很多頭部(包括Date、null、Content-Length、 Server、Last-Modified等等)和它們的值。輸出也顯示只允許從資源讀取數(shù)據(jù)。
你對(duì)一個(gè)程序是如何識(shí)別資源數(shù)據(jù)的是否感到驚奇?仔細(xì)看一下前面的輸出,你會(huì)看到叫做Content-Type的東西。Content-
Type是一個(gè)頭部,它識(shí)別了資源數(shù)據(jù)(內(nèi)容)的類型是text/html。text部分就是我們所知道的類型,html部分是我們所知道的子類型。(如
果內(nèi)容是普通的文本,Content-Type的值可能是text/plain。上面的類型表明內(nèi)容是文本的但不是沒有格式的)。Content-
Type頭部是我們所知道的多用途Internet郵件擴(kuò)展(MIME)的一部分。
MIME是傳統(tǒng)的傳輸消息的7位ASCII標(biāo)準(zhǔn)的一種擴(kuò)展。通過引入了多種頭部,MIME使視頻、聲音、圖像、不同字符集的文本與7位
ASCII結(jié)合起來。有了Content-Type,MIME可以識(shí)別Content-Length和其它標(biāo)準(zhǔn)的頭部。當(dāng)你使用
URLConnection類的時(shí)候,你會(huì)遇到getContentType()和getContentLength()。這些方法返回的值是
Content-Type和Content-Length頭部。
你也許聽說過HTML窗體(<form>、
</form>)和其它的HTML標(biāo)記。窗體使我們能夠從某種資源得到(GET)數(shù)據(jù)并按后來的處理把HTML窗體的字段數(shù)據(jù)發(fā)送(POST)到某種資
源。你能夠使用URLConnection類和MIME模擬可以得到和發(fā)送數(shù)據(jù)的HTML窗體。下面說明你怎樣完成這種事務(wù)。
假設(shè)你想把窗體數(shù)據(jù)發(fā)送(POST)到某個(gè)服務(wù)器程序。發(fā)送需要對(duì)窗體數(shù)據(jù)的操作。首先,窗體的數(shù)據(jù)必須組織為名稱/值對(duì)
(name/value pair),其次每個(gè)對(duì)必須指定為name=value格式,再次如果發(fā)送多個(gè)名稱/值對(duì),必須使用 &
符號(hào)把每對(duì)分開,最后的name內(nèi)容和value的內(nèi)容必須使用application/x-www-form-urlencoded
MIME類型編碼。例如x=y&a=b表現(xiàn)了兩個(gè)名稱/值對(duì)--x/y和a/b。
為了輔助編碼,Java提供了java.net.URLEncoder類,它聲明了一對(duì)靜態(tài)的encode()方法。每個(gè)方法有一個(gè)
String參數(shù)并返回包含已編碼的參數(shù)內(nèi)容的String對(duì)象的引用。例如,如果encode()發(fā)現(xiàn)參數(shù)中有空格,它在結(jié)果中用加號(hào)代替空格。
下面的代碼片斷演示了調(diào)用URLEncoder的encode(String s)方法,對(duì)a 空格 b字符串進(jìn)行編碼。結(jié)果a+b存儲(chǔ)在一個(gè)新的String對(duì)象中,result引用它。
String result = URLEncoder.encode ("a b");
作為準(zhǔn)備窗體數(shù)據(jù)的補(bǔ)充,必須告訴URLConnection對(duì)象數(shù)據(jù)已經(jīng)被發(fā)送了,因?yàn)閁RLConnection默認(rèn)的操作是獲取數(shù)
據(jù)。為了完成這種事務(wù),你可以首先把openConnection()的返回值轉(zhuǎn)換為HttpURLConnection類型(在確保該返回值的類型正確
后)。接著調(diào)用結(jié)果對(duì)象的setRequestMethod(String method)方法,把POST作為method參數(shù)引用的對(duì)象的值。
另一個(gè)必須完成的事務(wù)是調(diào)用URLConnection的setDoOutput(boolean
doOutput)方法,其參數(shù)的值必須為true。這種事務(wù)是必要的,因?yàn)閁RLConnection對(duì)象在默認(rèn)情況下不支持輸出。(接著程序最終可以
調(diào)用URLConnection的getOutputStream()方法,為發(fā)送的窗體數(shù)據(jù)返回一個(gè)資源的輸出流的引用)。
列表6是URLDemo3的源代碼,它演示了把窗體數(shù)據(jù)發(fā)送給某個(gè)"了解"application/x-www-form-urlencoded內(nèi)容類型的資源。它實(shí)現(xiàn)了前面提到的各種事務(wù)。
列表6: URLDemo3.java
// URLDemo3.java
import java.io.*;
import java.net.*;
class URLDemo3
{
public static void main (String [] args) throws IOException
{
// 檢查最后兩個(gè)參數(shù)和參數(shù)的數(shù)量
if (args.length < 2 || args.length % 2 != 0)
{
System.err.println ("usage: java URLDemo3 name value " +
"[name value ...]");
return;
}
// 建立程序連接服務(wù)器程序資源的URL對(duì)象,它返回一個(gè)窗體的名稱/值對(duì)
主站蜘蛛池模板:
嘉义县|
石家庄市|
阜新市|
岫岩|
甘谷县|
开鲁县|
东乡|
曲阜市|
方正县|
汽车|
泰州市|
叙永县|
哈巴河县|
宝山区|
璧山县|
策勒县|
怀安县|
平度市|
桃江县|
龙山县|
德庆县|
图木舒克市|
永和县|
清水河县|
苏尼特右旗|
沂南县|
金华市|
铜川市|
沙田区|
烟台市|
陇西县|
洞口县|
芜湖市|
泸西县|
奉贤区|
新津县|
衡水市|
呼玛县|
水城县|
如皋市|
普陀区|