对象流( ObjectInputStream和OjbectOutputSteam )
Person类:
package com.acoffee.java1;
import java.io.Serializable;
/**
* Person需要满足下列的要求才能满足序列化
* 1.需要实现接口:Serializable
* 2.当前类提供一个全局变量:serialVersionUID
* 3.除了当前Person类需要实现Serializable接口之外,
* 还必须保证其内部所有的属性也必须是可序列化的。
* (默认情况下,基本数据类型可序列化)
*
* ObjectOutputStream和ObjectInputStream
* 不能序列化static和transient修 饰的成员变量
*
* @author acoffee
* @create 2020-10-20 19:31
*/
public class Person implements Serializable {
public static final long serialVersionUID = -123131234353L;
private int age;
private String name;
private int id;
public long getSerialVersionUID() {
return serialVersionUID;
}
public Person() {
}
public Person(int age, String name, int id) {
this.age = age;
this.name = name;
this.id = id;
}
}
package com.acoffee.java1;
import org.junit.Test;
import java.io.*;
/**
* 对象流的使用
* 1.ObjectInputStream 和 ObjectOutputStream
* 2.作用:用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
* <p>
* 3.要想一个java对象是可序列化的,需要满足相应的要求。见Person.java
* <p>
* 4.序列化机制:
* 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种
* 二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。
* 当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。
*
* @author acoffee
* @create 2020-10-20 19:09
*/
public class ObjectInputOutputStream {
/*
序列化过程:将内存中的java对象保存到磁盘中或通过网络传播出去
使用ObjectOutputStream实现
*/
@Test
public void testObjectOutputStream() {
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("hello.dat"));
oos.writeObject(new String("我爱北京天安门"));
oos.flush();//刷新操作
oos.writeObject(new Person(23, "frank",0));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 反序列化:将磁盘文件的对象还原为内存中的一个java对象
* 使用ObjectInputStream来实现
* */
@Test
public void testObjectInputStream() {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("hello.dat"));
Object obj = ois.readObject();
String str = (String) obj;
Person p = (Person) ois.readObject();
System.out.println(str);
System.out.println(p);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
随机存取文件流(RandomAccessFile 类)
RandAccessFile的使用
- 1.RandomAccessFile直接继承于java.lang.Object类,实现了 DataInput和DataOutput接口
- 2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
- 3.如果RandomAccessFile作为输出流存在,谢楚道的文件如果不存在,则在执行过程中自动创建,如果写出到的文件存在时,则会对原有文件内容进行覆盖(从头开始覆盖)
- 可以通过相关操作实现插入的操作
RandomAccessFile作为输入流:
@Test
public void test1() throws IOException {
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
//1.
raf1 = new RandomAccessFile(new File("爱情与友情.jpg"), "r");
raf2 = new RandomAccessFile(new File("爱情与友情5.jpg"), "rw");
//2.
byte[] buffer = new byte[1024];
int len;
while ((len = raf1.read(buffer)) != -1) {
raf2.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (raf1 != null)
//3.
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (raf2 != null)
raf2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
作输出流时(如果有内容 会对原有文件内容进行覆盖):
@Test
public void test2() throws IOException {
RandomAccessFile raf = new RandomAccessFile(new File("hello.txt"), "rw");
raf.seek(3);//将指针调到角标3的位置(从角标3开始覆盖)
raf.write("frank".getBytes());
raf.close();
}
执行前:
执行后:
练习:RandomAccessFile实现数据的插入
/*
使用RandomAccessFile实现数据的插入效果
*/
@Test
public void test3() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
raf1.seek(3);//将指针调到角标为3的位置
//保存指针3后面的所有数据到StringBuilder中
StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
byte[] buffer = new byte[20];
int len;
while((len = raf1.read(buffer)) != -1){
builder.append(new String(buffer,0,len)) ;
}
//调回指针,写入“xyz”
raf1.seek(3);
raf1.write("xyz".getBytes());
//将StringBuilder中的数据写入到文件中
raf1.write(builder.toString().getBytes());
raf1.close();
//思考:将StringBuilder替换为ByteArrayOutputStream
}
NIO.2中Path、 Paths、Files类的使用
随着 JDK 7 的发布,Java对NIO进行了极大的扩展,增强了对 文件处理和文件系统特性的支持,以至于我们称他们为 NIO.2。 因为 NIO 提供的一些功能,NIO已经成为文件处理中越来越重要的部分。
/**
* 1. jdk 7.0 时,引入了 Path、Paths、Files三个类。
* 2.此三个类声明在:java.nio.file包下。
* 3.Path可以看做是java.io.File类的升级版本。也可以表示文件或文件目录,与平台无关
* <p>
* 4.如何实例化Path:使用Paths.
* static Path get(String first, String … more) : 用于将多个字符串串连成路径
* static Path get(URI uri): 返回指定uri对应的Path路径
*
* @author shkstart
* @create 2019 下午 2:44
*/
public class PathTest {
//如何使用Paths实例化Path
@Test
public void test1() {
Path path1 = Paths.get("d:\\nio\\hello.txt");//new File(String filepath)
Path path2 = Paths.get("d:\\", "nio\\hello.txt");//new File(String parent,String filename);
System.out.println(path1);
System.out.println(path2);
Path path3 = Paths.get("d:\\", "nio");
System.out.println(path3);
}
//Path中的常用方法
@Test
public void test2() {
Path path1 = Paths.get("d:\\", "nio\\nio1\\nio2\\hello.txt");
Path path2 = Paths.get("hello.txt");
// String toString() : 返回调用 Path 对象的字符串表示形式
System.out.println(path1);
// boolean startsWith(String path) : 判断是否以 path 路径开始
System.out.println(path1.startsWith("d:\\nio"));
// boolean endsWith(String path) : 判断是否以 path 路径结束
System.out.println(path1.endsWith("hello.txt"));
// boolean isAbsolute() : 判断是否是绝对路径
System.out.println(path1.isAbsolute() + "~");
System.out.println(path2.isAbsolute() + "~");
// Path getParent() :返回Path对象包含整个路径,不包含 Path 对象指定的文件路径
System.out.println(path1.getParent());
System.out.println(path2.getParent());
// Path getRoot() :返回调用 Path 对象的根路径
System.out.println(path1.getRoot());
System.out.println(path2.getRoot());
// Path getFileName() : 返回与调用 Path 对象关联的文件名
System.out.println(path1.getFileName() + "~");
System.out.println(path2.getFileName() + "~");
// int getNameCount() : 返回Path 根目录后面元素的数量
// Path getName(int idx) : 返回指定索引位置 idx 的路径名称
for (int i = 0; i < path1.getNameCount(); i++) {
System.out.println(path1.getName(i) + "*****");
}
// Path toAbsolutePath() : 作为绝对路径返回调用 Path 对象
System.out.println(path1.toAbsolutePath());
System.out.println(path2.toAbsolutePath());
// Path resolve(Path p) :合并两个路径,返回合并后的路径对应的Path对象
Path path3 = Paths.get("d:\\", "nio");
Path path4 = Paths.get("nioo\\hi.txt");
path3 = path3.resolve(path4);
System.out.println(path3);
// File toFile(): 将Path转化为File类的对象
File file = path1.toFile();//Path--->File的转换
Path newPath = file.toPath();//File--->Path的转换
}
}
网络编程
网络通信协议
通信要素1:IP 和 端口号
/**
* 一、网络编程中有两个主要的问题:
* 1.如何准确地定位网络上一台或多台主机;定位主机上的特定的应用
* 2.找到主机后如何可靠高效地进行数据传输
*
* 二、网络编程中的两个要素:
* 1.对应问题一:IP和端口号
* 2.对应问题二:提供网络通信协议:TCP/IP参考模型(应用层、传输层、网络层、物理+数据链路层)
*
*
* 三、通信要素一:IP和端口号
*
* 1. IP:唯一的标识 Internet 上的计算机(通信实体)
* 2. 在Java中使用InetAddress类代表IP
* 3. IP分类:IPv4 和 IPv6 ; 万维网 和 局域网
* 4. 域名: www.baidu.com www.mi.com www.sina.com www.jd.com
* www.vip.com
* 5. 本地回路地址:127.0.0.1 对应着:localhost
*
* 6. 如何实例化InetAddress:两个方法:getByName(String host) 、 getLocalHost()
* 两个常用方法:getHostName() / getHostAddress()
*
* 7. 端口号:正在计算机上运行的进程。
* 要求:不同的进程有不同的端口号
* 范围:被规定为一个 16 位的整数 0~65535。
*
* 8. 端口号与IP地址的组合得出一个网络套接字:Socket
*
* @author acoffee
* @create 2020-10-21 18:13
*/
public class InetAddressTest {
public static void main(String[] args) throws UnknownHostException {
InetAddress inet1 = InetAddress.getByName("192.168.10.14");
System.out.println(inet1);///192.168.10.14
InetAddress inet2 = InetAddress.getByName("www.sina.com");
System.out.println(inet2);//www.sina.com/101.206.202.228
InetAddress inet3 = InetAddress.getByName("127.0.0.1");
System.out.println(inet3);
//获取本地ip
InetAddress inet4 = InetAddress.getLocalHost();
System.out.println(inet4);//DESKTOP-F6H0M5U/169.254.230.191
//getHostName
System.out.println(inet2.getHostName());//www.sina.com
//getHostAddress
System.out.println(inet2.getHostAddress());//101.206.202.225
}
}
通信要素2:网络协议
TCP网络编程
1.客户端发送内容给服务端,服务端将内容打印到控制台上。
package com.acoffee.java;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author acoffee
* @create 2020-10-21 19:22
*/
public class TCPTest1 {
//客户端
@Test
public void client() {
Socket socket = null;
OutputStream os = null;
try {
//1.创建Socket对象,指明服务器端的ip和端口号
InetAddress inet = InetAddress.getByName("127.0.0.1");
socket = new Socket(inet, 8899);
//2.获取一个输出流,用于输出数据
os = socket.getOutputStream();
//3.写出数据的操作
os.write("我是Frank,你好!".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//4.资源的关闭
if (os != null)
os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//服务端
@Test
public void server(){
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
//1.创建服务器的ServerSocket,指明自己的端口号
serverSocket = new ServerSocket(8899);
//2.调用accept()表示接受来自于客户端的socket
socket = serverSocket.accept();
//3.获取输入流
is = socket.getInputStream();
//不建议下述写法:
//可能会出现乱码:传递的是中文如果我们将
//这里传递的字节数设置的太小的的话可能会将其劈成两半
//从而导致乱码
// byte[] buffer = new byte[20];
// int len;
// while ((len = is.read(buffer)) != -1){
// String str = new String(buffer, 0, len);
// System.out.println(str);
// }
//在这里我们使用ByteArrayOutputStream()其原理是将
//它会将我们输入的内容保存在一个数组当中,知道我们的
//内容写入完毕过后,它才会一次性整体读出然后整体转化为
// 字符串,从而不会导致乱码
//4.读入输入流中的数据
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[5];
int len;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
System.out.println(baos.toString());
System.out.println("收到了来自于:" + socket.getInetAddress().getHostAddress() + "的数据!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//5.关闭流
if (baos != null)
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (serverSocket != null)
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
执行结果:
2.客户端发送文件给服务端,服务端将文件保存在本地。
package com.acoffee.java;
import org.junit.Test;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author acoffee
* @create 2020-10-21 20:01
*/
public class TCPTest2 {
//这里涉及到的异常需要使用try-catch-finally来处理
@Test
public void client() throws IOException {
//1.造套接字
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090);
//2.获取输出流
OutputStream os = socket.getOutputStream();
//3.获取输入流
FileInputStream fis = new FileInputStream(new File("1.png"));
//4.操作细节
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1){
os.write(buffer,0,len);
}
fis.close();
os.close();
socket.close();
}
@Test
public void Server() throws IOException {
ServerSocket ss = new ServerSocket(9090);
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream(new File("123.png"));
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
fos.close();
is.close();
socket.close();
ss.close();
}
}
3.从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给 客户端。并关闭相应的连接。
package com.acoffee.java;
import org.junit.Test;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author acoffee
* @create 2020-10-21 20:01
*/
public class TCPTest2 {
//这里涉及到的异常需要使用try-catch-finally来处理
@Test
public void client() throws IOException {
//1.造套接字
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090);
//2.获取输出流
OutputStream os = socket.getOutputStream();
//3.获取输入流
FileInputStream fis = new FileInputStream(new File("1.png"));
//4.操作细节
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1){
os.write(buffer,0,len);
}
//这里我们在客户端传输完毕过后,我们关闭数据的输出
//如果不关闭,服务器端我知道我们到底传媒传完,就会
//一直等待
socket.shutdownOutput();
//5.接受来自于服务器的数据,并显示到控制台上
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer1 = new byte[20];
int len1;
while ((len1 = is.read(buffer1)) != -1){
baos.write(buffer1,0,len1);
}
System.out.println(baos.toString());
fis.close();
os.close();
socket.close();
baos.close();
}
@Test
public void Server() throws IOException {
ServerSocket ss = new ServerSocket(9090);
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream(new File("12.png"));
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
System.out.println("图片传输完成");
//服务器端给与客户端反馈
OutputStream os = socket.getOutputStream();
os.write("你好!I'm coco!".getBytes());
fos.close();
is.close();
socket.close();
ss.close();
os.close();
}
}
执行结果:
UDP网络编程
package com.acoffee.java;
import org.junit.Test;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* @author acoffee
* @create 2020-10-21 21:15
*/
public class UDPTest {
@Test
public void sender() throws IOException {
DatagramSocket socket = new DatagramSocket();
String str = "我是UDP方式发送的导弹";
byte[] data = str.getBytes();
InetAddress inet = InetAddress.getLocalHost();
DatagramPacket packet = new DatagramPacket(data,0,data.length,inet,9090);
socket.send(packet);
socket.close();
}
@Test
public void receiver() throws IOException {
DatagramSocket socket = new DatagramSocket(9090);
byte[] buffer = new byte[100];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);
System.out.println(new String(packet.getData(), 0, packet.getLength()));
socket.close();
}
}
URL编程
URLTest类:
package com.atguigu.java1;
import java.net.MalformedURLException;
import java.net.URL;
/**
* URL网络编程
* 1.URL:统一资源定位符,对应着互联网的某一资源地址
* 2.格式:
* http://localhost:8080/examples/beauty.jpg?username=Tom
* 协议 主机名 端口号 资源地址 参数列表
*
* @author acoffee
* @create 2020 下午 4:47
*/
public class URLTest {
public static void main(String[] args) {
try {
URL url = new URL("http://localhost:8080/examples/beauty.jpg?username=Tom");
// public String getProtocol( ) 获取该URL的协议名
System.out.println(url.getProtocol());
// public String getHost( ) 获取该URL的主机名
System.out.println(url.getHost());
// public String getPort( ) 获取该URL的端口号
System.out.println(url.getPort());
// public String getPath( ) 获取该URL的文件路径
System.out.println(url.getPath());
// public String getFile( ) 获取该URL的文件名
System.out.println(url.getFile());
// public String getQuery( ) 获取该URL的查询名
System.out.println(url.getQuery());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
URLTest1类:
package com.atguigu.java1;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* @author acoffee
* @create 2020 下午 4:54
*/
public class URLTest1 {
public static void main(String[] args) {
HttpURLConnection urlConnection = null;
InputStream is = null;
FileOutputStream fos = null;
try {
URL url = new URL("http://localhost:8080/examples/beauty.jpg");
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
is = urlConnection.getInputStream();
fos = new FileOutputStream("day10\\beauty3.jpg");
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
System.out.println("下载完成");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(urlConnection != null){
urlConnection.disconnect();
}
}
}
}
每日一练:
1. 一个IP对应着哪个类的一个对象?InetAddress
实例化这个类的两种方式是?
InetAddress.getByName(String host);
InetAddress.getLocalHost();//获取本地ip
两个常用的方法是?
getHostName();
getHostAddress();
2. 传输层的TCP协议和UDP协议的主要区别是?
TCP:可靠的数据传输(三次握手);进行大数据量的传输;效率低
UDP:不可靠;以数据报形式发送,数据报限定为64k;效率高
3. 什么是URL,你能写一个URL吗?
URL:统一资源定位符
URL url = new
URL(“http://192.168.14.100:8080/examples/hello.txt?username=Tom”);
4. 谈谈你对对象序列化机制的理解
序列化过程:允许把内存中的Java对象转换成平台无关的二进制流,从 而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传 输到另一个网络节点。
反序列化过程:当其它程序获取了这种二进制流,就可以恢复成原 来的Java对象
5. 对象要想实现序列化,需要满足哪几个条件
①. 实现接口:Serializable 标识接口
②. 对象所在的类提供常量:序列版本号
③. 要求对象的属性也必须是可序列化的。(基本数据类型、String:本身就已经是可序列化的。)