Java笔记37
TCP案例
TCP实现发送消息
-
下面我们来分别编写一个客户端程序和一个服务端程序,使用用户端给服务端发送一句消息,然后使用服务端接收用户端发送过来的这句消息并打印输出。
-
客户端:
-
- 创建一个与服务端
Socket
类的实例对象,根据IP地址和端口连接服务器;
-
Socket
类:该类实现客户端套接字。 套接字是两台机器之间通讯的端点,用于完成两个应用程序之间的数据传输(可以理解为IP+端口)。该类有很多种构造方法,这里我们使用其中一种参数为IP地址和端口号的构造方法: -
Socket(InetAddress address, int port) //创建流套接字并将其连接到指定IP地址的指定端口号。
- 创建一个与服务端
-
- 使用
Socket
类中的getOutputStream()
方法,创建一个Socket
对象的字节输出流,使用write()
方法发送消息;
- 使用
-
- 关闭资源。
-
-
TcpClientDemo01.java
package com.clown.net.tcp;import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;//客户端
public class TcpClientDemo01 {public static void main(String[] args) {Socket socket = null;OutputStream os = null;try {//1. 需要知道服务端的IP地址、端口号InetAddress serverIP = InetAddress.getByName("127.0.0.1");int port = 9999;//2. 创建一个Socket连接socket = new Socket(serverIP, port);//3. 发送消息,字节输出流os = socket.getOutputStream();os.write("好好学习,天天向上".getBytes());} catch (Exception e) {e.printStackTrace();} finally {//4. 关闭资源if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}
-
服务端:
-
- 创建一个
ServerSocket
类的实例化对象,创建服务并设置端口号;
-
ServerSocket
类:这个类实现了服务器套接字。服务器套接字等待通过网络进入的请求。 它根据该请求执行一些操作,然后可能将结果返回给请求者。 这里我们也使用它的构造方法之一来创建端口: -
ServerSocket(int port) //创建绑定到指定端口的服务器套接字。
- 创建一个
-
- 使用
ServerSocket
类中的accept()
方法,监听客户端的连接,创建与客户端连接的Socket
对象;
-
public Socket accept() throws IOException //从连接请求队列中取出一个客户的连接请求,然后创建与客户连接的Socket对象,并将它返回。如果队列中没有连接请求,accept()方法就会一直等待,直到接收到了连接请求才返回。
- 使用
-
- 使用
Socket
类中的getInputStream()
方法,创建一个Socket
对象的字节输入流,接收用户端发送过来的消息;
- 如果要打印输出中文字符,最好使用管道流
ByteArrayOutputStream
和它的write(byte[] b, int off, int len)
方法,这样就能保证结果不会出现乱码。
- 使用
-
- 关闭资源;
-
-
TcpServerDemo01.java
package com.clown.net.tcp;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;//服务端
public class TcpServerDemo01 {public static void main(String[] args) {ServerSocket serverSocket = null;Socket socket = null;InputStream is = null;ByteArrayOutputStream baos = null;try {//1. 创建服务,需要建立一个端口serverSocket = new ServerSocket(9999);//2. 等待客户端连接过来socket = serverSocket.accept(); //阻塞式监听,会一直等待客户端连接//3. 读取客户端发送的消息,字节输入流is = socket.getInputStream();//管道流//ByteArrayOutputStream: 该类实现了将数据写入字节数组的输出流。 当数据写入缓冲区时,缓冲区会自动增长。baos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while ((len = is.read(buffer)) != -1) {//write(byte[] b, int off, int len); 从指定的字节数组写入 len个字节,从偏移量为 off开始,输出到这个字节数组输出流。baos.write(buffer, 0 , len);}System.out.println(baos.toString());} catch (IOException e) {e.printStackTrace();} finally {//4. 关闭资源if (baos != null) {try {baos.close();} catch (IOException e) {e.printStackTrace();}}if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}if (serverSocket != null) {try {serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}}
}
- 运行结果:
- 我们需要先运行服务端:
- 此时,服务端已启动,因为使用了
ServerSocket
类中的accept()
方法,所以服务端会阻塞,并一直等待客户端发送连接请求。这时,我们再启动客户端: - 观察服务端的运行结果:
- 客户端运行正常,没有发生异常。
- 观察此时服务端的运行结果:
- 与客户端建立连接之后,服务端运行正常,没有发生异常,且服务端成功接收并打印了用户端发送的消息。
TCP实现文件上传
- 首先,我们准备一个任意类型的文件(这里我准备的是一张图片:
galaxy.jpg
,我把它放在了我项目的根目录):
- 接着,我们来编写我们的客户端和服务端程序。为了更清晰地呈现代码结构,便于学习和理解,在下面的程序中,我没有使用
try/catch/finally
语句捕获异常,而是直接抛出了异常: - 客户端:
-
- 创建一个与服务端
Socket
类的实例对象,根据IP地址和端口连接服务器;
- 创建一个与服务端
-
- 使用
Socket
类中的getOutputStream()
方法,创建一个Socket
对象的字节输出流;
- 使用
-
- 创建一个文件字节输入流,读取我们准备上传的文件
-
- 使用
write()
方法将文件上传给客户端;
- 使用
-
- 发送完毕之后,需要禁用输出流,相当于通知客户端本身“数据已经发送完了”;
-
- 接收服务器的通知,确定服务器已接收完毕,客户端才能断开连接;
-
- 关闭资源。
-
TcpClientDemo02.java
package com.clown.net.tcp;import java.io.*;
import java.net.InetAddress;
import java.net.Socket;public class TcpClientDemo02 {public static void main(String[] args) throws Exception {//1. 创建一个与服务端连接的 Socket对象Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);//2. 创建一个 Socket对象的字节输出流OutputStream os = socket.getOutputStream();//3. 读取文件,创建一个文件字节输入流FileInputStream fis = new FileInputStream(new File("galaxy.jpg"));//4. 发送文件byte[] buffer = new byte[1024];int len;while ((len = fis.read(buffer)) != -1) {os.write(buffer, 0, len);}//5. 发送完毕之后,禁用输出流socket.shutdownOutput(); //我已经发送完了//6. 确定服务器已接收完毕,才能断开连接InputStream inputStream = socket.getInputStream();//管道流ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer2 = new byte[1024];int len2;while ((len2 = inputStream.read(buffer2))!= -1) {baos.write(buffer2, 0, len2);}System.out.println(baos.toString());//7. 关闭资源fis.close();os.close();socket.close();}}
- 服务端:
-
- 创建一个
ServerSocket
类的实例化对象,创建服务并设置端口号;
- 创建一个
-
- 使用
ServerSocket
类中的accept()
方法,监听客户端的连接,创建与客户端连接的Socket
对象;
- 使用
-
- 使用
Socket
类中的getInputStream()
方法,创建一个Socket
对象的字节输入流,接收用户端上传过来的文件;
- 使用
-
- 创建一个文件字节输出流,输出我们接收到的文件;
-
- 接收完毕之后,通知客户端可以断开连接了;
-
- 关闭资源。
-
TcpServerDemo02.java
package com.clown.net.tcp;import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class TcpServerDemo02 {public static void main(String[] args) throws Exception {//1. 创建服务,设置端口ServerSocket serverSocket = new ServerSocket(9000);//2. 监听客户端的连接,创建一个与客户的连接的 Socket对象Socket socket = serverSocket.accept(); //阻塞式监听,会一直等待客户端连接//3. 接收文件,创建一个Socket对象的字节输入流InputStream is = socket.getInputStream();//4. 文件输出,文件字节输出流FileOutputStream fos = new FileOutputStream(new File("receive.jpg"));byte[] buffer = new byte[1024];int len;while ((len = is.read(buffer)) != -1) {fos.write(buffer, 0, len);}//5. 接收完毕之后,通知客户端:我已接收完毕,你可以断开连接了OutputStream outputStream = socket.getOutputStream();outputStream.write("我已接收完毕,你可以断开连接了".getBytes());//6. 关闭资源fos.close();is.close();socket.close();serverSocket.close();}}
- 运行结果:
- 我们需要先运行服务端:
- 此时,服务端已启动,因为使用了
ServerSocket
类中的accept()
方法,所以服务端会阻塞,并一直等待客户端发送连接请求。这时,我们再启动客户端: - 观察客户端的运行结果:
- 客户端运行正常,没有发生异常,并且成功接收到了服务端发来的 “我已接收完毕,你可以断开连接” 的通知。
- 观察此时服务端的运行结果:
- 与客户端建立连接之后,服务端运行正常,没有发生异常。
- 最后,我们再查看一下我们的项目文件,检查文件是否已经上传成功:
- 确认了图片确实已经上传成功。
UDP案例
UDP实现发送消息
-
UDP没有明确的客户端与服务端的概念,只有发送端和接收端。
-
下面,我们就来分别写一个发送端和一个接收端,实现消息的发送:
-
在正式开始写之前,我们需要先了解以下知识:
-
DatagramSocket
类:此类表示用于发送和接收数据报包的套接字。数据报套接字是分组传送服务的发送或接收点。-
常用的构造方法:
-
DatagramSocket() DatagramSocket(int port) //参数:port-要使用的端口
-
-
DatagramPacket
类:该类表示数据报包。-
常用的构造方法:
-
DatagramPacket(byte buf[], int offset, int length, InetAddress address, int port) //参数:buf-数据包数据; offset-分组数据偏移量; length-分组数据长度; address-目的地址; port-目的端口号。 DatagramPacket(byte buf[], int offset, int length, SocketAddress address) //参数:buf-数据包数据; offset-分组数据偏移量; length-分组数据长度,address-目标套接字地址。 DatagramPacket(byte buf[], int offset, int length) //参数:buf-数据包数据; offset-分组数据偏移量; length-分组数据长度。
-
常用方法:
-
send(DatagramPacket p) //从此套接字发送数据报包 receive(DatagramPacket p) //从此套接字接收数据报包。该方法阻塞,直到接收到数据报 getAddress() //返回该数据报发送或接收数据报的计算机的 IP地址 getData() //返回数据缓冲区
-
-
-
发送端:
-
- 创建一个
DatagramSocket
类的实例对象;
- 创建一个
-
- 实例化一个
DatagramPacket
类的对象,来创建一个数据包,并把想要发送的数据和目的(接收端)IP地址及端口号作为参数,传入该数据包的构造方法;
- 实例化一个
-
- 使用
DatagramPacket
类中的send(DatagramPacket p)
方法发送数据;
- 使用
-
- 关闭资源。
-
UdpSenderDemo01
package com.clown.net.udp;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;//UDP,不需要建立连接
//发送端
public class UdpSenderDemo01 {public static void main(String[] args) throws Exception {//1. 建立一个 DatagramSocket//DatagramSocket: 此类表示用于发送和接收数据报套接字。DatagramSocket socket = new DatagramSocket();//2. 建立一个包//要发送的消息String msg = "你好啊,接收端!";//要发送给谁InetAddress localhost = InetAddress.getByName("localhost"); //IP地址int port = 9090; //端口号//DatagramPacket: 该类表示数据报包//构造方法: DatagramPacket(byte buf[], int offset, int length, InetAddress address, int port);//参数: buf-数据包数据; offset-分组数据偏移量; length-分组数据长度; address-目的地址; port-目的端口号。DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);//3. 发送包//send(DatagramPacket p); 从此套接字发送数据报包socket.send(packet);//4. 关闭资源socket.close();}}
- 接收端:
-
- 创建一个
DatagramSocket
类的实例对象,并设置端口号;
- 创建一个
-
- 建立一个缓冲区并设置它的大小,根据该容器建立一个数据包(
DatagramPacket
),用于接收发送过来的数据;
- 建立一个缓冲区并设置它的大小,根据该容器建立一个数据包(
-
- 使用
DatagramPacket
类中的receive(DatagramPacket p)
方法接收数据包,该方法为阻塞方法,它会一直等待,直到接收到发送端发来的数据包;
- 使用
-
- 关闭资源。
-
UdpReceiverDemo01
package com.clown.net.udp;import java.net.DatagramPacket;
import java.net.DatagramSocket;//还是需要一个阻塞方法,监听发送端发送数据
//接收端
public class UdpReceiverDemo01 {public static void main(String[] args) throws Exception {//1. 设置端口DatagramSocket socket = new DatagramSocket(9090);//2. 建立一个缓冲区并设置它的大小,根据该缓冲区建立一个包,用于接收发送过来的数据byte[] buffer = new byte[1024];//构造方法: DatagramPacket(byte buf[], int offset, int length)//参数: buf-数据包数据; offset-分组数据偏移量; length-分组数据长度;DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);//3. 接收数据包//receive(DatagramPacket p); 从此套接字接收数据报包,该方法阻塞,直到接收到数据报socket.receive(packet);//getAddress(); 返回该数据报发送或接收数据报的计算机的 IP地址System.out.println(packet.getAddress().getHostAddress()); //获取发送者的 IP地址//getData(); 返回数据缓冲区System.out.println(new String(packet.getData(), 0, packet.getLength())); //打印接收到的消息//4. 关闭资源socket.close();}}
- 运行结果:
- 同样的,我们还是需要先运行接收端:
- 此时,接收端已启动,因为使用了
DatagramPacket
类中的receive(DatagramPacket p)
方法,所以接收端会阻塞,并一直等待发送端发送数据包。这时,我们再启动发送端: - 观察发送端的运行结果:
- 发送端运行正常,没有发生异常。
- 观察此时接收端的运行结果:
- 接收端运行正常,没有发生异常,且接收端成功接收到了发送端发送的数据包,并打印了发送端的IP地址。
UDP实现循环发送消息
- 在现实生活中,我们通常并不只是发送一句消息,怎样才能实现连续的发送多条消息呢?
- 下面我们再写一个发送端和一个接收端,实现循环发送消息:
- 发送端:
UdpSenderDemo02
package com.clown.net.udp;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;public class UdpSenderDemo02 {public static void main(String[] args) throws Exception {//1. 创建 DatagramSocket对象,设置端口号DatagramSocket socket = new DatagramSocket(8888);//2. 准备数据,控制台读取:System.in//桥转换流:InputStreamReader,将字符流转换为字节流InputStreamReader isr = new InputStreamReader(System.in);//字节缓冲流:BufferedReaderBufferedReader reader = new BufferedReader(isr);//循环while (true) {String data = reader.readLine();byte[] bytes = data.getBytes();//3. 创建数据包//InetSocketAddress: 该类实现 IP套接字地址(IP地址 + 端口号),它也可以是一对(主机名 + 端口号)DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, new InetSocketAddress("localhost", 6666));//4. 发送数据包socket.send(packet);//设置终止循环的条件if (data.equals("bye")) {break;}}//5. 关闭资源socket.close();}}
- 接收端:
UdpReceiverDemo02
package com.clown.net.udp;import java.net.DatagramPacket;
import java.net.DatagramSocket;public class UdpReceiverDemo02 {public static void main(String[] args) throws Exception {//1. 创建 DatagramSocket对象,设置端口号DatagramSocket socket = new DatagramSocket(6666);//循环while (true) {//2. 准备接收数据包//创建一个缓冲区byte[] buffer = new byte[1024];//创建一个数据包,用于接收数据DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);//设置终止循环的条件byte[] bytes = packet.getData(); //读取接收到的数据包中的数据String receiveStr = new String(bytes, 0, packet.getLength()); //将数据转换成字符串形式//打印接收到的消息System.out.println(receiveStr);//3. 接收数据包socket.receive(packet); //阻塞式//当收到 "bye" 时,终止循环if (receiveStr.equals("bye")) {break;}}//4. 关闭资源socket.close();}}
- 运行结果:
- 先运行接收端:
- 再运行发送端:
- 此时,接收端等待发送端发送数据,发送端等待控制台输入数据。
- 我们往发送端的控制台中输入消息:
- 往发送端的控制台中输入完以上消息之后,查看接收端:
- 接收端成功接收到了发送端发送过来的消息。
- 最后,我们往发送端的控制台中输入
bye
,终止程序:
- 输入
bye
后,发送端停止运行。 - 查看接收端:
- 接收端在接收到发送端发来的
bye
之后,也停止了运行。
UDP实现在线聊天
- 在上面我们已经实现了连续的发送多条消息,下面我们结合之前学习的多线程的内容,编写程序实现在线聊天:
- 发送端:
TalkSend.java
package com.clown.net.udp;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;public class TalkSend implements Runnable {DatagramSocket socket = null;BufferedReader reader = null;private int ownPort; //自身发送进程的端口号private String destinationIP; //目的 IP地址private int destinationPort; //目的接收进程的端口号//构造器public TalkSend(int ownPort, String destinationIP, int destinationPort) {this.ownPort = ownPort;this.destinationIP = destinationIP;this.destinationPort = destinationPort;try {socket = new DatagramSocket(ownPort);reader = new BufferedReader(new InputStreamReader(System.in));} catch (SocketException e) {e.printStackTrace();}}@Overridepublic void run() {//循环while (true) {try {String data = reader.readLine(); //读取数据byte[] bytes = data.getBytes(); //将数据转换成字节类型//创建数据包DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, new InetSocketAddress(this.destinationIP, this.destinationPort));//发送数据包socket.send(packet);//设置终止循环的条件if (data.equals("bye")) {break;}} catch (IOException e) {e.printStackTrace();}}//关闭资源socket.close();}}
- 接收端
TalkReceive.java
package com.clown.net.udp;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class TalkReceive implements Runnable {DatagramSocket socket = null;String msgFrom = null; //谁发送的消息private int ownPort; //自身接收进程的端口号//构造器public TalkReceive(int ownPort, String msgFrom) {this.ownPort = ownPort;this.msgFrom = msgFrom;try {socket = new DatagramSocket(ownPort);} catch (SocketException e) {e.printStackTrace();}}@Overridepublic void run() {//循环while (true) {try {//准备接收数据包//创建一个缓冲区byte[] buffer = new byte[1024];//创建一个数据包,用于接收数据DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);//接收数据包socket.receive(packet); //阻塞式//设置终止循环的条件byte[] bytes = packet.getData(); //读取接收到的数据包中的数据String receiveData = new String(bytes, 0, packet.getLength()); //将数据转换成字符串形式//打印接收到的消息System.out.println(msgFrom + ": " + receiveData);//当收到 "bye" 时,终止循环if (receiveData.equals("bye")) {break;}} catch (IOException e) {e.printStackTrace();}}//关闭资源socket.close();}}
- 模拟两个用户:
老师
和学生
- 他们都能接收对方发送的消息,也都能向对方发送消息,实现聊天。 - 老师:
TalkTeacher.java
package com.clown.net.udp;public class TalkTeacher {public static void main(String[] args) {//开启两个线程(发送、接收)new Thread(new TalkSend(5555, "localhost", 8888)).start();new Thread(new TalkReceive(9999, "学生")).start();}}
- 学生:
TalkStudent.java
package com.clown.net.udp;public class TalkStudent {public static void main(String[] args) {//开启两个线程(发送、接收)new Thread(new TalkSend(7777, "localhost", 9999)).start();new Thread(new TalkReceive(8888, "老师")).start();}}
- 启动
TalkTeacher.java
和TalkStudent.java
:
- 在
TalkStudent.java
的控制台中输入一句消息,模拟学生向老师发送了一句话:
- 老师成功收到了学生发来的消息。接着,在
TalkTeacher.java
的控制台中输入一句消息,模拟老师回复了学生的消息:
- 学生也成功接收到了老师回复的消息。我们还可以继续聊天:
- 当其中双方都收到了对方发送的
bye
后,终止程序,结束聊天:
URL
- 统一资源定位器(URL)用于定位互联网上的某个资源。
- 如:
https://www.baidu.com/
- 如:
- 一个URL可以由以下五个部分组成:
协议://IP地址:端口/项目名/资源
- 注:
- 一个域名本质上就是一个IP地址,如:
www.baidu.com
使用时会由DNS(域名系统)解析为IP地址:39.156.66.18
。 - URL可以由五个以下的部分组成(比如一个URL可以不包含
/项目名/资源
这两个部分),但通常不会超过五个部分。
- 一个域名本质上就是一个IP地址,如:
URL的组成部分
- 为了更好地理解URL的组成部分,我们新建一个
URL
对象,调用URL
类中的一些常用方法来获取URL字符串中的各个组成部分:
package com.clown.net.url;import java.net.MalformedURLException;
import java.net.URL;public class URLDemo01 {public static void main(String[] args) throws MalformedURLException {URL url = new URL("http://localhost:8080/helloworld/index.jsp?username=clown&password=123");//getProtocol(); 获取此 URL的协议名System.out.println(url.getProtocol());//getHost(); 获取此 URL的主机名System.out.println(url.getHost());//getPort(); 获取此 URL的端口号System.out.println(url.getPort());//getPath(); 获取此 URL的文件路径部分System.out.println(url.getPath());//getFile(); 获取此 URL的文件名,返回的文件部分将与 getPath()相同,加上 getQuery()的返回值 (如果有)System.out.println(url.getFile());//getQuery(); 获取此 URL的查询部分System.out.println(url.getQuery());}}
- 运行结果:
URL实现下载网络资源
- 首先,我们需要准备一个网络资源。这里我使用Tomcat创建网络资源:
- 打开Tomcat所在目录下的
webapps
目录,在里面新建一个自己的文件夹(这里我新建的文件名为clown
),然后在新建的文件夹里添加文件(这里我添加了一个文本文件:ConfidentialFile.txt
):
- 给我们的文件添加一些内容:
- 注意,为了避免出现乱码,要把文件的编码方式修改为
ANSI
(ANSI
:在不同的系统中,ANSI
表示不同的编码,因为我的电脑是简体中文系统的,所以ANSI
表示的编码方式为GBK
):
- 然后打开Tomcat所在目录下的
bin
目录,双击startup.bat
启动Tomcat服务器:
- 这时,我们再打开浏览器,在上方地址栏中输入URL:
http://localhost:8080/clown/ConfidentialFile.txt
就能查看我们刚刚创建的文件了:
- 下面,我们来编写代码,实现利用URL下载我们刚刚创建的这个网络资源
ConfidentialFile.txt
:
package com.clown.net.url;import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;public class URLDownload {public static void main(String[] args) throws Exception {//1. 下载地址URL url = new URL("http://localhost:8080/clown/ConfidentialFile.txt");//2. 连接到这个资源 HTTP//openConnection(); 打开连接,返回一个 URLConnection类的实例。//URLConnection类: URLConnection 是一个抽象类,代表应用程序和 URL 之间的通信链接。它的实例可用于读取和写入此 URL 引用的资源。//HttpURLConnection类: 支持 HTTP特定功能的 URLConnection。是 Java提供的发起 HTTP请求的基础类库,提供了 HTTP请求的基本能力HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); //强制转换为 HttpURLConnection类//读取输入流//getInputStream(); 返回从此打开的连接读取的输入流。InputStream inputStream = urlConnection.getInputStream();//创建文件输出流FileOutputStream fos = new FileOutputStream("ConfidentialFile.txt");byte[] buffer = new byte[1024];int len;while ((len = inputStream.read(buffer)) != -1) {fos.write(buffer, 0, len); //写出数据}//关闭资源fos.close();inputStream.close();//disconnect(); 关闭连接urlConnection.disconnect();}}
- 运行结果:
- 程序运行正常,没有报错。
- 我们再查看我们的项目文件,看一下文件是否已经成功下载到了我们的项目文件夹里:
- 文件确实已经下载到我们的项目文件夹中了。
- 我们再去下载一个互联网上的资源试试:
- 随便在网易云音乐的网站上找一首音乐,F12,找到该音乐资源:
- 双击打开,复制URL:
- 将复制的URL粘贴到我们刚才写的程序中覆盖,再更改一下我们保存文件的文件名,运行程序:
package com.clown.net.url;import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;public class URLDownload {public static void main(String[] args) throws Exception {//1. 下载地址URL url = new URL("https://m701.music.126.net/20230818212400/a087d364aa84bdf9360cdce0d896f386/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/19668440665/bacd/3d83/588c/d0bbf5eb57a04d4b650f304bea6be713.m4a");//2. 连接到这个资源 HTTP//openConnection(); 打开连接,返回一个 URLConnection类的实例。//URLConnection类: URLConnection 是一个抽象类,代表应用程序和 URL 之间的通信链接。它的实例可用于读取和写入此 URL 引用的资源。//HttpURLConnection类: 支持 HTTP特定功能的 URLConnection。是 Java提供的发起 HTTP请求的基础类库,提供了 HTTP请求的基本能力HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); //强制转换为 HttpURLConnection类//读取输入流//getInputStream(); 返回从此打开的连接读取的输入流。InputStream inputStream = urlConnection.getInputStream();//创建文件输出流FileOutputStream fos = new FileOutputStream("ThatIsUS.m4a");byte[] buffer = new byte[1024];int len;while ((len = inputStream.read(buffer)) != -1) {fos.write(buffer, 0, len); //写出数据}//关闭资源fos.close();inputStream.close();//disconnect(); 关闭连接urlConnection.disconnect();}}
- 运行结果:
- 程序运行正常,没有报错。
- 我们再查看我们的项目文件,看一下文件是否已经成功下载到了我们的项目文件夹里:
- 最后,我们看看下载的音乐资源能否正常播放:
- 音乐能够正常播放,下载成功!