IO

批注 2020-05-27 140149

批注 2020-05-27 140937

网络IO模型:

屏幕截图 2020-09-27 192708

网络框架设计模式:

服务器网络编程 1 + N + M 模型

1个监听线程 N个IO线程 M个worker线程

架构

stateDiagram-v2
    direction LR
    处理流 --> 缓冲操作
    缓冲操作 --> BufferedInputStream
    缓冲操作 --> BufferedOutputStream
    缓冲操作 --> BufferedReader
    缓冲操作 --> BufferedWriter
    处理流 --> 基本数据类型操作
    基本数据类型操作 --> DataInputStream
    基本数据类型操作 --> DataOutputStream
    处理流 --> 对象序列化操作
    对象序列化操作 --> ObjectInputStream
    对象序列化操作 --> ObjectOutputStream
    处理流 --> 转化控制
    转化控制 --> InputStreamReader
    转化控制 --> OutputStreamWriter
    处理流 --> 打印控制
    打印控制 --> PrintStream
    打印控制 --> PrintWriter

    节点流 --> 文件操作
    文件操作 --> FileInputStream
    文件操作 --> FileOutputStream
    文件操作 --> FileReader
    文件操作 --> FileWriter
    节点流 --> 管道操作
    管道操作 --> PipedInputStream
    管道操作 --> PipedOutputStream
    管道操作 --> PipedReader
    管道操作 --> PipedWriter
    节点流 --> 数组操作
    数组操作 --> ByteArrayInputStream
    数组操作 --> ByteArrayOutputStream
    数组操作 --> CharArrayReader
    数组操作 --> CharArrayWriter

大体分为几类:

节点流可以从或向一个特定的地方(节点)读写数据,处理流则是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写,是一种装饰器

字节到字符的转换十分耗时 非常容易出现乱码问题 这是字符流的用处

InputStreamReader 与 OutputStreamWriter 是字节流与字符流之间的桥梁

File类

File并不代表一个真实存在的真实对象

FileDescriptor才是代表一个真实文件对象

从磁盘读取文件:

屏幕截图 2020-09-28 133112

构造方法

静态成员变量

批注 2019-08-03 083724

获取

判断

创建删除

目录遍历

文件过滤器

IO

顶级父类

输入流 输出流
字节流 字节输入流 InputStream 字节输出流 OutputStream
字符流 字符输入流 Reader 字符输出流 Writer

字节输出流【OutputStream】

FileOutputStream

FileOutputStream fos = new FileOutputStream("fos.txt");

for (int i =0;i<100;i++){
    fos.write(("hello"+i+"\n").getBytes());
}
fos.flush();
fos.close();
FileOutputStream fos = new FileOutputStream("fos.txt",true);

字节输入流【InputStream】

FileInputStream

构造方法

FileInputStream fis = new FileInputStream("fos.txt");
int c = -1;
while ((c = fis.read()) != -1) {
    System.out.print((char)c);
}
fis.close();

字符流

Reader

FileReader

FileReader reader = new FileReader("fos.txt");
int c = -1;
while ((c = reader.read()) != -1){
    System.out.print((char)c);
}

Writer

FileWriter

FileWriter writer = new FileWriter("fos.txt");
writer.append("hh种");
writer.flush();
writer.close();

JDK7中IO的异常处理

// JDK7
try (FileWriter writer = new FileWriter("fos.txt")) {
    writer.append("hh种");
    writer.flush();
    
} catch (IOException e) {
    e.printStackTrace();
}
// JDK9
FileWriter writer = new FileWriter("fos.txt");
try (writer) {
    writer.append("hh种");
    writer.flush();

} catch (IOException e) {
    e.printStackTrace();
}

Properties

与流相关的方法

缓冲流

编码

IO 操作中的编解码

InputStreamReader reader = new InputStreamReader(new FileInputStream("gbk.txt"),"gbk");

OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("utf8.txt"), StandardCharsets.UTF_8);
int c = -1;
while ((c= reader.read()) != -1){
    writer.write(c);
}
writer.close();

内存编解码

"蔡徐坤".getBytes("gbk");
new String(new byte[]{ -78, -52, -48, -20, -64, -92 },"gbk");

String 编码时序图:

屏幕截图 2020-09-29 112623

Web 中的编解码

屏幕截图 2020-09-29 113656

URL编解码

/页面?name=页面

这个URL被编码成%2f%e9%a1%b5%e9%9d%a2%3fname%3d%e9%a1%b5%e9%9d%a2

不同浏览器的编码可能并不一致 那么服务端是如何解析的?

tomcat中有一个配置:

<Connector URLEncoding="UTF-8"> 

这个配置就是用来对路径部分进行解码的

至于queryString 要不是body中的charset 要不就是ISO-8859-1

并且如果使用要body的charset的话 需要配置

<Connector useBodyEncodingForURI="true"/>

HTTP header 编解码

对于request.getHeader() 默认是使用的ISO-8859-1编码 且无法指定编码 不要再Header中传递非ASCII 字符

表单编解码

浏览器会根据ContentType的Charset对表单参数进行编码

服务端可以在Servlet容器中获取参数之前调用request.setCharacterEncoding()来指定服务器解码方式 如果没有调用此方法 那么会按照系统默认的编码方式解析

Body 编解码

服务端通过response.setCharacterEncoding来设置 这个方法的本质是设置响应头ContentType

浏览器端按照以下顺序进行解码:

js文件编码问题

如果外部引入的js文件与当前html不一致 需要

<script charset="utf8" src="xxx"></script>

常见编码问题

屏幕截图 2020-09-29 131724 屏幕截图 2020-09-29 131741 屏幕截图 2020-09-29 131801

序列化

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object"));
oos.writeObject(new Person("jav",15));

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object"));
Person p = (Person)ois.readObject();

序列化的类需要实现 Serializable 接口

最好手动设置 serialVersionUID 的值, 类修改时根据是否兼容来调整这个值,serialVersionUID 值不一致会抛出序列化运行时异常。

transient关键字修饰的变量不会被序列化

序列化的目的:持久化、传输

其他方式的序列化:

序列化一些复杂对象: