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);
//字节缓冲流:BufferedReader
BufferedReader 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();
}
}
@Override
public 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();
}
}
@Override
public 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();
}
}
- 运行结果:
- 程序运行正常,没有报错。
- 我们再查看我们的项目文件,看一下文件是否已经成功下载到了我们的项目文件夹里:
- 最后,我们看看下载的音乐资源能否正常播放:
- 音乐能够正常播放,下载成功!