JDK源码中的文档注释部分,将File类描述为:(物理)文件和路径的(逻辑)抽象表示。
用户接口和操作系统使用依赖于系统路径名称的字符串来表示“文件和路径”(user interfaces and
operating systems use system-dependent pathname-strings to name files and
directories),File类表示一个抽象的(abstract)、系统无关的(system-independent )
层次路径视图,一个抽象的路径名称包含两部分内容:
[1]一个可选的独立于系统的前缀字符串。——路径分隔符号:/或者\\
[2]0个或者多个文件名
以:
F:\Java-dependencies\apache-tomcat-9.0.43\apache-tomcat-9.0.43\conf\server.xml
或者
https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json为例,
--》抽象路径的首个名称可能是一个文件夹名称(F:\Java-dependencies\apache-tomcat-9.0.43\
apache-tomcat-9.0.43\conf\),也可能是一个主机名称(geo.datav.aliyun.com),每一级字符
序列都可以定位到一个文件夹(或者某一级域名),最后的名称则为文件名(server.xml、
100000_full.json)或者目录名。
结合实际代码,不难发现,即时磁盘上不存在某个路径或者文件,依旧可以通过new关键字创建File类的对象,这正是因为文件在逻辑概念层次上的——抽象性(abstract)和系统无关性(system-independent )。
但是,文件在物理概念层次,在实际移动、复制、删除、重命名一个File类对象时,又必须要求它对应的字符串路径在磁盘上真实存在,这正是因为——在JVM之下的操作系统底层,它使用依赖于系统路径名称的字符串来表示“文件和路径”(user interfaces and operating systems use system-dependent pathname-strings to name files and directories)
当前,文件路径又有相对路径和绝对路径之分,在此不做深究。只需明确一点:Java中用于表示文件的字符串路径,既可以是这样,又可以是那样:
这样:F:\Java-dependencies\apache-tomcat-9.0.43\apache-tomcat-9.0.43\conf\server.xml
那样:https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json
由1 File类文件注释浅析可知,既然文件路径可以抽象表示为:https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json,那么,网络资源实质上应当就是:存储于服务器上的一个普通文件,例如:pdf、xml、png、mp4…
文件有不同的类型,那么网络资源也自然是如此。文件的类型可以根据编码格式(GBK、UTF-8…)、后缀名(*.pdf、*.jpg、*.xml、*.png、*.mp3…)等进行区分,网络资源的类型如何进行区分呢?
网络资源,在HTTP超文本传输协议中,也使用content-type响应头标签来进行标识,用于告诉客户端——服务器端当前正在返回的网络资源的内容类型。这个Content-type可以通过ServletResponse的setContentType(String)方法进行设置,它将决定浏览器客户端以什么形式、什么编码去读取这个网络资源(文件)。例如:如下所示的context-type为text/html,表示当前正在访问的网络资源是一个HTML文件。
context-type属性的取值被称为MIME类型(即:媒体类型),常见的媒体格式如下所示,也可访问https://www.runoob.com/http/http-content-type.html 查看更多MIME类型取值。
通过上述解读,可知:网络资源本质上是存在于服务器上的一个普通文件资源,这个资源文件的类型也叫作MIME媒体类型,HTTP将其作为标准的一部分进行实现。那么,如何访问到这个网络资源呢?
网络资源的路径通过URL表示。
而URL(Uniform Resource Locator),叫做资源定位符。百度将其诠释为:
在WWW(World Wide Web)万维网上,每一网络资源都有统一的且在网上唯一的地址,该地址就叫URL(Uniform Resource Locator,统一资源定位器),它是万维网的统一资源定位标志,就是指网络地址。
将URL具象化,也就是我们通常看到的浏览器窗口地址栏里面的字符串。
URL-资源定位符由4部分组成:协议(protocol)、主机(host)、端口(port)、路径(path),一般其语法规则如下:
protocol :// hostname[:port] / path / [:parameters][?query]#fragment
例如:
https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json
则:
protocol:https
域名(hostname+port):geo.datav.aliyun.com(可借助域名服务器通过域名获取主机名和端口号)
path:areas_v3/bound/100000_full.json
也可使用:在线域名解析工具。
在Java编程语言中,将其URL抽象为java.net包下的URL类。有关其文档注释的部分解析如下:
URL类表示资源定位符(Uniform Resource Locator),指向万维网(the World
Wide Web)上的一个资源(Resource)。
一个资源可以是简单的文件或者目录(文件与目录在Java中被抽象为File类),或者也
可以是一个更加复杂的对象(其它类型:对于数据库或搜索引擎的一次查询操作)。
一个URL的端口号是可选的,若未明确指定,那么默认为80.
URL类可以实现类似于3.1中提到“域名解析”功能(但是这个URL类本身并不具有这个功能,而是由内部维护的URLStreamHandler抽象类来实现)
获取URL-https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json的基本信息。
package com.xwd.demo;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class URLDemo{
//methods
public static void main(String[] args) {
try {
URL url=new URL("https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json");
URLConnection connection=url.openConnection();
System.out.println(url.toString());
//获取通信协议
String protocol = url.getProtocol();
System.out.println("协议="+protocol);
//获取主机名
String host = url.getHost();
System.out.println("主机="+host);
//获取端口号
int port = url.getPort();
int defaultPort = url.getDefaultPort();
System.out.println("port:"+port+",defaultPort:"+defaultPort);
//获取请求参数
String query = url.getQuery();
System.out.println("查询参数="+query);
//
String userInfo = url.getUserInfo();
System.out.println("用户信息="+userInfo);
String ref = url.getRef();
System.out.println("URL的锚点#="+ref);
String authority = url.getAuthority();
System.out.println("权限="+authority);
//获取文件名称
String file = url.getFile();
System.out.println("文件名="+file);
//获取路径名称
String path = url.getPath();
System.out.println("文件路径"+path);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
基于上述解读,已经可以通过一个包含指向网络资源的URL拿到它对应的文件名和路径。那么,如何实现网络资源的读写操作呢?例如:将一个网络资源通过URL来下载到本地。
就像文件IO操作,网络资源的IO操作,需要先获取一个客户端到这个网络资源所在服务器之间的URL连接对象,然后通过这个连接对象来完成各种IO操作。基本原理如下图所示。
Java编程语言中提供了java.net.URLConnection来表示客户端与网络资源之间的连接通道。对其文档注释做如下简要解读,
URLConnection抽象类是表示所有代表客户端程序与URL之间的连接(link)的类的父类。
该类的对象可以通过调用URL的openConnection()方法创建,其用于读取、写入URL指向
的资源。
网络资源的下载操作,其示例代码如下:
package com.xwd.demo;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
/**
* @ClassName IODemo
* @Description: com.xwd.demo
* @Auther: xiwd
* @Date: 2022/2/4 - 02 - 04 - 16:27
* @version: 1.0
*/
public class IODemo {
//methods
public static void main(String[] args) {
URL url=null;
URLConnection connection=null;
InputStream inputStream=null;
OutputStream outputStream=null;
byte[] buffer=new byte[1024];
int len=-1;
try {
//提供URL-网络资源定位符
url = new URL("https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json");
//获取网络资源的名称
String file = url.getFile();
String filename= file.lastIndexOf("/")==-1?file: file.substring(file.lastIndexOf("/")+1,file.length());
//获取客户端与URL的连接对象
connection = url.openConnection();
//获取输入流对象
inputStream = connection.getInputStream();
//获取输出流对象——并指定网络资源的本地保存位置
outputStream = new FileOutputStream(filename);
//执行网络资源下载操作
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer,0,len);
}
System.out.println("SUCCESS");
} catch (IOException e) {
e.printStackTrace();
System.out.println("FAILED");
} finally {
//释放流资源
if (outputStream!=null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream!=null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
HttpURLConnection抽象类是URLConnection抽象类的子类。该类的一个对象可用于向指定网站发送GET请求、POST请求(但http服务器的底层网络连接可能会被多个对象所共享(一种HTTP服务器的多线程处理机制),在请求结束之后,调用close()方法可以使访问所占有的网络资源,但是不会对其它持久性连接(persistent connection)有任何影响。)。
它在URLConnection的基础上提供了如下便捷的方法:
int getResponseCode(); // 获取服务器的响应代码。
String getResponseMessage(); // 获取服务器的响应消息。
String getResponseMethod(); // 获取发送请求的方法。
void setRequestMethod(String method); // 设置发送请求的方法。
示例代码如下:
其中:GET请求获取的响应结果为一个HTML页面的源码,过于冗长,就没有打印;后续还可根据结合这个HTML页面的源码,引起dom4j.jar包,实现页面信息爬取操作。
package com.xwd.demo;
import com.sun.jmx.snmp.SnmpNull;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @ClassName IODemo
* @Description: com.xwd.demo
* @Auther: xiwd
* @Date: 2022/2/4 - 02 - 04 - 16:27
* @version: 1.0
*/
public class IODemo {
//methods
public static void main(String[] args) {
HttpURLConnectionTest();
}
//http://www.sdpxgd.com/search.php?searchword=画江湖
private static void HttpURLConnectionTest(Object... args) {
URL url= null;
HttpURLConnection connection =null;
InputStream inputStream=null;
BufferedReader reader=null;
try{
//获取URL对象
url = new URL("http://www.sdpxgd.com/search.php?searchword=%E7%94%BB%E6%B1%9F%E6%B9%96");
//获取HttpURLConnection对象
connection = (HttpURLConnection) url.openConnection();
//设置请求参数
connection.setDoOutput(false);//是否向HttpURLConnection输出
connection.setDoInput(true);//是否从HttpURLConnection读入
connection.setRequestMethod("GET");//设置请求方式
connection.setUseCaches(true);//设置是否使用缓存
connection.setInstanceFollowRedirects(true);//设置是否应当自动执行HTTP重定向
connection.setConnectTimeout(3000);//设置超时响应时间
//执行连接
connection.connect();
//获取状态码
int responseCode = connection.getResponseCode();
//获取数据
String msg="";
if (responseCode==200){
//获取输入流对象
inputStream = connection.getInputStream();
reader=new BufferedReader(new InputStreamReader(inputStream));
//读取信息
String line=null;
while ((line=reader.readLine())!=null)
msg+=line+"\n";
}
//查询结果打印
//System.out.println(msg);//这里打印的是搜索结果页面的HTML代码,内容太多,就不打印了
//打印响应体信息
Map<String, List<String>> headerFields = connection.getHeaderFields();
Set<Map.Entry<String, List<String>>> entries = headerFields.entrySet();
Iterator<Map.Entry<String, List<String>>> iterator = entries.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next().toString());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader!=null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//断开连接
if (connection!=null) {
connection.disconnect();
}
}
}
}