一旦擁有了URL對象,你就可以使用getAuthority()、getDefaultPort()、 getFile()、
getHost()、 getPath()、getPort()、
getProtocol()、getQuery()、getRef()和getUserInfo(). The
getDefaultPort()等方法提取各種組件。如果URL中沒有指定端口的部分,getDefaultPort()方法返回URL對象的協議處理
程序使用(資源定位)的默認端口。getFile()方法返回路徑和查詢組件的結合體。getProtocol()方法返回決定資源的連接類型(例如
http、mailto、ftp)的協議的名稱。getRef()方法返回URL的部分片斷(我們所知道的引用)。最后,getUserInfo()方法
返回授權機構組件的用戶信息部分。在這些URL組件提取方法中,如果某些組件不存在(如果沒有給URL對象的協議處理程序指定默認的端口,它也返回-
1),這些方法就返回null或-1。
作為這些組件提取方法的補充,你還可以調用openStream()方法檢索java.io.InputStream引用。使用這種引用,你可以用面向字節的方式讀取資源。
列表4是URLDemo1的源代碼。該程序從命令行參數建立了一個URL對象,調用URL組件提取方法來檢索該URL的組件,調用URL的
openStream()方法打開與資源的連接并返回一個用于從資源讀取字節數據的InputStream引用,讀取/打印這些字節,關閉輸入流。
列表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>
在上面的信息中,輸出標識符80是默認端口,HTTP是協議。上面給出的是輸出的HTML頁面的源代碼。
URL的openStream()方法通常返回抽象的InputStream類的一個具體的子類所建立的對象的引用。這意味著你必須按字節次序
讀取資源數據,這種做法是恰當的,因為你不知道將要讀取的數據是什么類型的。如果你事先知道要讀取的數據是文本的,并且每一行以換行符(\n)結束,你就
可以按行讀取而不是按字節讀取數據了。
下面的代碼片斷演示了把一個InputStream對象包裝進java.io.InputStreamReader對象以從8位過渡到16
位字符,把結果對象包裝進java.io.BufferedReader對象以訪問BufferedReader的readLine()方法,并調用
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 ();
有時候按字節的次序讀取數據并不方便。例如,如果資源是JPEG文件,那么獲取一個圖像處理過程并向該過程注冊一個用戶使用數據的方法更好。當圖像完整下載后立即顯示它并不困難。如果出現這種情況,你就有必要使用getContent()方法。
當調用getContent()方法時,它會返回某種對象的Object引用,而你可以調用該對象的方法(在轉換成適當的類型后),采用更方便的方式檢索數據。但是在調用該方法前,你必須使用instanceof驗證對象的類型,防止類產生異常。
對于JPEG資源,getContent()返回一個對象,該對象的類實現了java.awt.Image.ImageProducer接
口。下面的代碼片斷演示了使用instanceof驗證對象是ImageProducer的,并進行了轉換。接下來可以調用ImageProducer方
法注冊一個用戶并初始化圖像的使用過程。
URL url = new URL (args [0]);
Object o = url.getContent ();
if (o instanceof ImageProducer)
{
ImageProducer ip = (ImageProducer) o;
// ...
}
技巧
調用URL的equals(Object o)和sameFile(Object o)方法來決定兩個URL是否相同。第一個方法包含了比較的片斷,而第二個方法沒有包含。你可以參閱SDK文檔查找更多信息。
查看一下getContent()方法的源代碼,你會找到openConnection().getContent()。此外,查看一下
openStream()方法的源代碼,你會發現openConnection().getInputStream()。每個方法都首先調用URL的
openConnection()方法。這個方法返回抽象的java.net.URLConnection類(描述與某些資源的連接)的一個子類建立的對
象的引用。URLConnection的方法反映了資源和連接的細節信息,使我們能編寫代碼向資源寫入信息。
列表5的URLDemo2源代碼演示了openConnection(),以及調用一些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]);
// 返回代表某個資源的連接的新的特定協議對象的引用
URLConnection uc = url.openConnection ();
// 進行連接
uc.connect ();
// 打印多種頭部字段的內容
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 ());
}
}?
在
對openConnection()的調用返回后,調用了connect()方法--用于建立某種資源的連接。(盡管openConnection()方
法返回一個連接對象的引用,但是openConnection()不會連接到資源)。
URLConnection的getHeaderFields()方法返回一個對象的應用,該對象的類實現了java.util.Map接口。該圖表
(map)包含頭部名稱和值的集合。什么是頭部(header)?頭部是基于文本的名稱/值對,它識別資源數據的類型、數據的長度等等。
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?
上面的輸出識別了很多頭部(包括Date、null、Content-Length、 Server、Last-Modified等等)和它們的值。輸出也顯示只允許從資源讀取數據。
你對一個程序是如何識別資源數據的是否感到驚奇?仔細看一下前面的輸出,你會看到叫做Content-Type的東西。Content-
Type是一個頭部,它識別了資源數據(內容)的類型是text/html。text部分就是我們所知道的類型,html部分是我們所知道的子類型。(如
果內容是普通的文本,Content-Type的值可能是text/plain。上面的類型表明內容是文本的但不是沒有格式的)。Content-
Type頭部是我們所知道的多用途Internet郵件擴展(MIME)的一部分。
MIME是傳統的傳輸消息的7位ASCII標準的一種擴展。通過引入了多種頭部,MIME使視頻、聲音、圖像、不同字符集的文本與7位
ASCII結合起來。有了Content-Type,MIME可以識別Content-Length和其它標準的頭部。當你使用
URLConnection類的時候,你會遇到getContentType()和getContentLength()。這些方法返回的值是
Content-Type和Content-Length頭部。
你也許聽說過HTML窗體(<form>、
</form>)和其它的HTML標記。窗體使我們能夠從某種資源得到(GET)數據并按后來的處理把HTML窗體的字段數據發送(POST)到某種資
源。你能夠使用URLConnection類和MIME模擬可以得到和發送數據的HTML窗體。下面說明你怎樣完成這種事務。
假設你想把窗體數據發送(POST)到某個服務器程序。發送需要對窗體數據的操作。首先,窗體的數據必須組織為名稱/值對
(name/value pair),其次每個對必須指定為name=value格式,再次如果發送多個名稱/值對,必須使用 &
符號把每對分開,最后的name內容和value的內容必須使用application/x-www-form-urlencoded
MIME類型編碼。例如x=y&a=b表現了兩個名稱/值對--x/y和a/b。
為了輔助編碼,Java提供了java.net.URLEncoder類,它聲明了一對靜態的encode()方法。每個方法有一個
String參數并返回包含已編碼的參數內容的String對象的引用。例如,如果encode()發現參數中有空格,它在結果中用加號代替空格。
下面的代碼片斷演示了調用URLEncoder的encode(String s)方法,對a 空格 b字符串進行編碼。結果a+b存儲在一個新的String對象中,result引用它。
String result = URLEncoder.encode ("a b");
作為準備窗體數據的補充,必須告訴URLConnection對象數據已經被發送了,因為URLConnection默認的操作是獲取數
據。為了完成這種事務,你可以首先把openConnection()的返回值轉換為HttpURLConnection類型(在確保該返回值的類型正確
后)。接著調用結果對象的setRequestMethod(String method)方法,把POST作為method參數引用的對象的值。
另一個必須完成的事務是調用URLConnection的setDoOutput(boolean
doOutput)方法,其參數的值必須為true。這種事務是必要的,因為URLConnection對象在默認情況下不支持輸出。(接著程序最終可以
調用URLConnection的getOutputStream()方法,為發送的窗體數據返回一個資源的輸出流的引用)。
列表6是URLDemo3的源代碼,它演示了把窗體數據發送給某個"了解"application/x-www-form-urlencoded內容類型的資源。它實現了前面提到的各種事務。
列表6: URLDemo3.java
// URLDemo3.java
import java.io.*;
import java.net.*;
class URLDemo3
{
public static void main (String [] args) throws IOException
{
// 檢查最后兩個參數和參數的數量
if (args.length < 2 || args.length % 2 != 0)
{
System.err.println ("usage: java URLDemo3 name value " +
"[name value ...]");
return;
}
// 建立程序連接服務器程序資源的URL對象,它返回一個窗體的名稱/值對