c5 URLs and URIs - The URL class

来源:互联网 发布:剑三正太捏脸数据冷漠 编辑:程序博客网 时间:2024/05/22 14:18

java.net.URL 是对Uniform Resource Locator的抽象,是个final类,即不能被继承,没有子类,它通过strategy design pattern,不同协议作strategy,URL是Context,在context中选择不同strategy。


URL是不可变的,一般一个URL对象创建完成,其field就不能再被修改,因此是线程安全的。


Creating New URLs

public URL(String url) throws MalformedURLExceptionpublic URL(String protocol, String hostname, String file)    throws MalformedURLExceptionpublic URL(String protocol, String host, int port, String file)    throws MalformedURLExceptionpublic URL(URL base, String relative) throws MalformedURLException

 抛 MalformedURLException,当被创建的URL的协议不支持时,或者URL语法错误时。

vm支持哪些协议要看当前vm的情况。通用的支持的协议有http,https,file,jar,ftp等。

如果你想用的协议不支持,可以在vm上安装protocal handler,但麻烦,得不偿失,不建议使用。


construct a URL from a string

try {  URL u = new URL("http://www.audubon.org/");} catch (MalformedURLException ex)  {  System.err.println(ex);}


当前VM支持哪些协议?

public static void main(String[] args) {  // hypertext transfer protocol    testProtocol("http://www.adc.org");  // secure http    testProtocol("https://www.amazon.com/exec/obidos/order2/");    // file transfer protocol    testProtocol("ftp://ibiblio.org/pub/languages/java/javafaq/");    // Simple Mail Transfer Protocol    testProtocol("mailto:elharo@ibiblio.org");    // telnet    testProtocol("telnet://dibner.poly.edu/");    // local file access    testProtocol("file:///etc/passwd");    // gopher    testProtocol("gopher://gopher.anc.org.za/");    // Lightweight Directory Access Protocol    testProtocol(        "ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US?postalAddress");    // JAR    testProtocol(        "jar:http://cafeaulait.org/books/javaio/ioexamples/javaio.jar!"         + "/com/macfaq/io/StreamCopier.class");    // NFS, Network File System    testProtocol("nfs://utopia.poly.edu/usr/tmp/");    // a custom protocol for JDBC    testProtocol("jdbc:mysql://luna.ibiblio.org:3306/NEWS");    // rmi, a custom protocol for remote method invocation    testProtocol("rmi://ibiblio.org/RenderEngine");    // custom protocols for HotJava    testProtocol("doc:/UsersGuide/release.html");    testProtocol("netdoc:/UsersGuide/release.html");    testProtocol("systemresource://www.adc.org/+/index.html");    testProtocol("verbatim:http://www.adc.org/");}private static void testProtocol(String url) {    try {      URL u = new URL(url);      System.out.println(u.getProtocol() + " is supported");    } catch (MalformedURLException ex) {      String protocol = url.substring(0, url.indexOf(':'));      System.out.println(protocol + " is not supported");    }}

output:

http is supportedhttps is supportedftp is supportedmailto is supportedtelnet is not supportedfile is supportedgopher is supportedldap is not supportedjar is supportednfs is not supportedjdbc is not supportedrmi is not supporteddoc is not supportedsystemresource is not supportednetdoc is supportedverbatim is not supported

上面的VM是运行在Windows的 java 7。如果是Android Dalvik VM只支持http,https,file,gar,ftp.


constructing a URL from its componets parts

public URL(String protocol, String hostname, String file)    throws MalformedURLException

port 为 -1,即使用protocol的默认端口,注意file要以“/”开头的,包括path,filename,和可选的fragment identifier,

public URL(String protocol, String host, int port, String file)    throws MalformedURLException
其它同上面的,port显示指明使用哪个端口。


Constructing relative URLs

try {  URL u1 = new URL("http://www.ibiblio.org/javafaq/index.html");  URL u2 = new URL (u1, "mailinglists.html");} catch (MalformedURLException ex) {  System.err.println(ex);}

上面的u2指向的url是 http://www.ibiblio.org/javafaq/mailinglists.html.


other sources of URL objects

还有其他方式可以得到URL,比如

在applets中的,getDocumentBase(),getCodeBase()

在java.io.File的 toURL(),

classloader不仅可以加载类还可以加载资源,比如ClassLoader.getSystemResource(String name) ,返回一个指向资源的URL。


Retrieving Data from a URL

public InputStream openStream() throws IOExceptionpublic URLConnection openConnection() throws IOExceptionpublic URLConnection openConnection(Proxy proxy) throws IOExceptionpublic Object getContent() throws IOExceptionpublic Object getContent(Class[] classes) throws IOException

public final InputStream openStream() throws IOException
openStream返回InputStream,从InputStream中可以读取数据,而读到的数据都是未经解析的原始内容:

如果读的是ASCII text,那就是ASCII,

如果是HTML file,那就是raw HTML,.

如果是imgage file,那就是binary image data,

不包含http头和与协议有关的信息!和读取其他InputStream没有区别。

try {  URL u = new URL("http://www.lolcats.com");  InputStream in = u.openStream();  int c;  while ((c = in.read()) != -1) System.out.write(c);  in.close();} catch (IOException ex) {  System.err.println(ex);}

如大部分网络程序一样,稳定地关闭流需要花费点心思。在jdk6及之前,需要在try外面声明一个null的InputStream is,在finally中判断如果is不为null,那就关闭is。

InputStream in = nulltry {  URL u = new URL("http://www.lolcats.com");  in = u.openStream();  int c;  while ((c = in.read()) != -1) System.out.write(c);} catch (IOException ex) {  System.err.println(ex);} finally {  try {    if (in != null) {      in.close();    }  } catch (IOException ex) {    // ignore  }}

但在jdk7中,引入了try-with-resource statement,即在try中声明InputStream is,系统会在结束前自动关闭流。

try {URL u = new URL("http://www.lolcats.com");try (InputStream in = u.openStream()) {int c;while ((c = in.read()) != -1)System.out.write(c);}} catch (IOException ex) {System.err.println(ex);}


Program:Download a  web page 

public static void main(String[] args) {if (args.length > 0) {InputStream in = null;try {// Open the URL for readingURL u = new URL(args[0]);in = u.openStream();// buffer the input to increase performancein = new BufferedInputStream(in);// chain the InputStream to a ReaderReader r = new InputStreamReader(in);int c;while ((c = r.read()) != -1) {System.out.print((char) c);}} catch (MalformedURLException ex) {System.err.println(args[0] + " is not a parseable URL");} catch (IOException ex) {System.err.println(ex);} finally {if (in != null) {try {in.close();} catch (IOException e) {// ignore}}}}}
在chaining InputStream到InputStreamReader时,使用本地默认的charset!


URL指向的资源并不一定就是text,可能是gif ,jpeg image,可能是MP3 sound file,或者其他任何东西,即使是text,server和client端使用的charset也并不一定一样!


用URL读不到http的header,但用openConnection()返回的HttpConnection可以。http header中的charset和document真正使用的charset可能也不一样!编码问题是Web较棘手的问题。

public URLConnection openConnection() throws IOException
openConnection()打开一个到指定URL的socket,并返回一个URLConnection对象。通过该方法,可以获取server发送的任何原始数据,和与协议有关的meta数据。

public URLConnection openConnection(Proxy proxy) throws IOException
使用代理连接服务器,如果协议不支持代理,则忽略代理,尝试直接连接。


public final Object getContent() throws IOException
从服务器获取数据,并且将其生成某种对象!

public final Object getContent(Class[] classes) throws IOException
告诉server,按classes返回client需要的类别的对象。

例如下例中,server如果可以返回String,则返回,不可以则返回Reader,还不可以则返回InputStream。

URL u = new URL("http://www.nwu.org");Class<?>[] types = new Class[3];types[0] = String.class;types[1] = Reader.class;types[2] = InputStream.class;Object o = u.getContent(types);
client要判断返回的类型

if (o instanceof String) {System.out.println(o);} else if (o instanceof Reader) {int c;Reader r = (Reader) o;while ((c = r.read()) != -1)System.out.print((char) c);r.close();} else if (o instanceof InputStream) {int c;InputStream in = (InputStream) o;while ((c = in.read()) != -1)System.out.write(c);in.close();} else {System.out.println("Error: unexpected type " + o.getClass());}



Splitting a URL into Pieces

一个URL由5部分组成

• The scheme, also known as the protocol• The authority• The path• The fragment identifier, also known as the section or ref• The query string
http://www.ibiblio.org/javafaq/books/jnp/index.html?isbn=1565922069#toc

getFile()返回一个String,从第一个“/”开始到“#”之前的。

/javafaq/books/jnp/index.html?isbn=1565922069

getPath(),类似getFile(),但不包含query部分。

/javafaq/books/jnp/index.html

getUserInfo(),有些URL中还有userinfo,或者有的还有password,userinfo在scheme后,host前,用@和host分开,http://elharo@java.oreilly.com/,userinfo是elharo。


Equality and Comparison

URL的equaels()方法,当2个URL在同一host,port,path,有相同的fragment identifier和query string,即指向同一资源时,认为2个URL  equael。

注意equaels()会连接DNS,意味着它是I/O blocking的,所以不可以将URL存放在HashMap等依赖equaels()方法的数据结构中。

另一个方面,equaels()并不会实际比较资源是否相同,比如,http://www.oreilly.com/  和 http://
www.oreilly.com/index.html  equaels时会不相等!(也即equaels要求2个URL的string必须完全相同)

sameFile()方法和equaels()基本一致,也要请求DNS,不一样的地方在:sameFile()不比较fragment identifier,比如  http://www.oreilly.com/index.html#p1  和 http://www.oreilly.com/index.html#q2  ,sameFile()返回true,equaels()返回false。


Conversion

URL有3个方法,可将instance转为其他形式

toString();toExternalForm();toURI();
toString():输出URL的绝对路径,不常用,不直接使用

toExternalForm():返回一个human-readable String,代表URL

toURI():转成对应的URI。相对URL,URI提供更精确的(accurate),更特殊的(specification-conformant)的行为。绝对化(absolutization)和编码(encodeing)时应该用URI,当要使用hashtable等依赖equaels()方法的数据结构时,应该使用URI,当需要从server下载内容时使用URL。

0 0
原创粉丝点击