IO

网络框架设计模式:

服务器网络编程 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的异常处理

// JDK7try (FileWriter writer = new FileWriter("fos.txt")) {    writer.append("hh种");    writer.flush();    } catch (IOException e) {    e.printStackTrace();}// JDK9FileWriter 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关键字修饰的变量不会被序列化

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

其他方式的序列化:

序列化一些复杂对象: