对象序列化机制
1. 对象流
ObjectInputStream 和 ObjectOutputStream
2. 作用:
ObjectInputStream: 内存中的对象 --> 存储中的文件、通过网络传输出去
ObjectOutputStream:存储中的文件、通过网络接收过来 --> 内存中的对象
3. 对象的序列化机制
序列化:可以把内存中的 Java 对象转换成二进制流,从而实现 Java 对象的持久化存储或通过网络发送。
反序列化:从本地存储或网络中获取的二进制流恢复成 Java 对象。
4. 序列化代码实现:
ObjectOutputStream oos = null;
/**
* 测试ObjectOutputStream流,也就是对象的序列化机制
*/
@Test
public void testObjectOutputStream() {
try {
oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
// 向流中添加三组数据
oos.writeObject(new String("我爱北京天安门"));
oos.flush(); // 刷新流
oos.writeObject(new Person("香芋",21));
oos.flush();
oos.writeObject(new Person("芳旭",19,111,new Account(1000)));
oos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
5. 反序列化代码实现
ObjectInputStream ois = null; // 对象输入流
/**
* 测试 ObjectInputStream 反序列化
* 注意读的时候 readObject() 的顺序不能变
*/
@Test
public void testObjectInputStream() {
try {
ois = new ObjectInputStream(new FileInputStream("object.dat"));
String str = (String) ois.readObject();
Person p1 = (Person) ois.readObject();
Person p2 = (Person) ois.readObject();
System.out.println(str);
System.out.println(p1);
System.out.println(p2);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
6. 实现序列化的对象所属的类需要满足:
- 实现序列化接口 Serializable
- 当前类提供一个全局常量: serialVersionUID
- 除了当前类需要实现 Serializable 接口外,类中的其他属性也必须是可序列化的(基本数据类型默认可序列化)
RandomAccessFile 随机存取文件流
1. 随机存取文件流
- RandomAccessFile 直接继承于 java.lang.Object 类,实现了 DataInput 和 DataOutput 接口。
- RandomAccessFile 既可以作为一个输出流,也可以作为一个输入流(既可读又可写)。
- 如果 RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。如果写出到的文件已存在,则会对原有文件的内容进行覆盖(默认从头覆盖)。
- 可以通过相关的操作,实现 RandomAccessFile “插入”数据的效果。也就是 seek(int position) 方法。
2. 代码实现
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
/**
* 使用 RandomAccessFile 随机存取文件流实现复制一个文件重命名的效果
*/
@Test
public void test1() {
try {
raf1 = new RandomAccessFile(new File("test.jpg"),"r");
raf2 = new RandomAccessFile(new File("test1.jpg"),"rw");
byte[] buffer = new byte[1024];
int len;
while ((len = raf1.read(buffer)) != -1) {
raf2.write(buffer,0,len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (raf1 != null) {
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (raf2 != null) {
try {
raf2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
RandomAccessFile raf1 = null;
/**
* 使用 RandomAccessFile 实现数据的插入效果
*/
@Test
public void test2() {
try {
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)); // 读到的内容追加到builder后面
}
// 回调指针,写入xyz
raf1.seek(3);
raf1.write("xyz".getBytes(StandardCharsets.UTF_8));
// 将 StringBuilder 中的数据写回文件中
raf1.write(builder.toString().getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
NIO
1.是什么?
Java NIO (New IO , Non-Blocking IO 非阻塞式IO),Java1.4引入,Java1.7优化(NIO.2)。实际开发中并不常用。
Path、Paths 和 Files
1. Path
- 替换原有的 File 类
1.1. 如何实例化
- static Path get(String first, String … more) 用于将多个字符串连成路径
- static Path get(Url url) 返回指定 url 对应的 Path 路径
1.2. 常用方法:
- String toString(); 返回调用 Path 对象的字符串表示形式
- boolean startsWith(String path); 是否以 path 路径开始
- boolean endsWith(String path); 是否以 path 路径结束
- boolean isAbsolute(); 是否是绝对路径
- Path getParent(); 返回 Path 对象包含整个路径,不包含 Path 对象指定的文件路径
- Path getRoot(); 返回调用 Path 对象的根路径
- Path getFileName(); 返回调用 Path 对象关联的文件名
- int getNameCount(); 返回 Path 根目录后面元素的数量
- Path getName(int index); 返回指定索引位置 index 的路径名称
- Path toAbsolutePath(); 作为绝对路径返回调用 Path 对象
- Path resolve(Path p); 合并两个路径,返回合并后的路径对应的 Path 对象
- File toFile(); 将Path 转化为 File 类的对象
2. Files 工具类
2.1. 作用
- 操作文件或文件目录
2.2. 常用方法
- 常用方法
- Path copy (Path src, Path dest, CopyOption … how); 文件的复制
- Path createDirectory(Path path, FileAttribute<?> … attr); 创建一个目录
- Path createFile(Path path, FileAttribute<?> … arr); 创建一个文件
- void delete(Path path); 删除一个目录/文件,如果不存在,则执行报错
- void deleteIfExists(Path path); Path 对应的目录/文件如果存在,执行删除
- Path move(Path src, Path dest, CopyOption … how); 将 src 移动到 dest 的位置
- long size(Path path); 返回 Path 指定文件的大小
- 用于判断的方法
- boolean exists(Path path, LinkOption … opts); 文件是否存在
- boolean isDirectory(Path path, LinkOption … opts); 是否是目录
- boolean isRegulaFile(Path path, LinkOption … opts); 是否是文件
- boolean isHidden(Path path); 文件是否隐藏
- boolean isReadable(Path path); 文件是否可读
- boolean isWritable(Path path); 文件是否可写
- boolean notExists(Path path, LinkOption … opts); 判断文件是否不存在
- 用于操作内容的方法
- SeekableByteChannel newByteChannel(Path path, OpenOption … how); 获取与指定文件的链接,how 指定打开方式
- DirectoryStream
newDirectoryStream(Path path); 打开 Path 指定的目录 - InputStream newInputStream(Path path, OpenOption … how); 获取 InputStream 对象
- OutputStream newOutputStream(Path path, OpenOption … how); 获取 OutputStream对象
网络编程
一、实现网络通信需要解决的两个问题
-
如何准确的定位网络上一台或多台主机,定位主机上特定的应用
使用TCP/IP协议,端口号定位应用
-
找到主机后如何高效的进行数据传输
依据协议发送报文
二、网络通信的两个要素
- IP和端口号
- 提供网络通信协议:TCP/IP参考模型(应用层、传输层、网络层、物理+数据链路层)
三、通信要素一:IP和端口号
1. IP的理解
- IP是在 Internet 网络中计算机(通信实体)的唯一标识
- 在 Java 中使用 InetAddress 类代表 IP
- IP 的分类:IPv4 和 IPv6;万维网和局域网
- 域名:www.baidu.com
- 本地回环:127.0.0.1 也就是 localhost
2. InetAddress 类
此类的一个对象就代表着一个具体的IP地址
- 如何实例化 InetAddress?
- getByName(String host)
- getLocalHost()
- InetAddress 类的两个常用方法
- getHostName()
- getHostAddress()
3. 端口号
用来区分某个 IP 下不同的进程
要求:不同的进程有不同的端口号
范围:被规定为一个 16 位的整数 0 ~ 65536
端接口号和IP地址组合在一起成为一个 Socket 套接字
四、网络通信协议
1. 分层模型
2. TCP 和 UDP 的区别?
- TCP 使用前必须先采用 “三次握手”的方式建立连接否则会报错;UDP 则不需要,服务端只管发送消息,不关心客户端是否收到,客户端也无需确认消息,所以是不可靠的。
3. TCP 的三次握手和四次挥手
5536
端接口号和IP地址组合在一起成为一个 Socket 套接字
四、网络通信协议
1. 分层模型
[外链图片转存中…(img-5cNu3NcZ-1656560858437)]
2. TCP 和 UDP 的区别?
- TCP 使用前必须先采用 “三次握手”的方式建立连接否则会报错;UDP 则不需要,服务端只管发送消息,不关心客户端是否收到,客户端也无需确认消息,所以是不可靠的。
3. TCP 的三次握手和四次挥手
[外链图片转存中…(img-zSjBnhSu-1656560858438)]