IO

网络框架设计模式:

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

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

架构

mindmap 处理流    缓冲操作        BufferedInputStream        BufferedOutputStream        BufferedReader        BufferedWriter    基本数据类型操作        DataInputStream        DataOutputStream    对象序列化操作        ObjectInputStream        ObjectOutputStream    转化控制        InputStreamReader        OutputStreamWriter    打印控制        PrintStream        PrintWriter
mindmap    节点流        文件操作            FileInputStream            FileOutputStream            FileReader            FileWriter        管道操作            PipedInputStream            PipedOutputStream            PipedReader            PipedWriter        数组操作            ByteArrayInputStream            ByteArrayOutputStream            CharArrayReader            CharArrayWriter

大体分为几类:

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

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

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

File类

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

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

从磁盘读取文件:

屏幕截图 2020-09-28 133112

构造方法

静态成员变量

获取

判断

创建删除

目录遍历

文件过滤器

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");
---title: String 编码时序图---sequenceDiagram    participant String    participant StringCoding    participant Charset    participant StringEncoder    participant CharsetEncoder    String->>StringCoding: getBytes(charsetName)    StringCoding->>StringCoding: encode    StringCoding->>StringCoding: lookupCharset    StringCoding->>Charset: Charset.forName    Charset-->>StringCoding: 返回找到的Charset    StringCoding->>StringEncoder: 根据Charset new StringEncoder对象    StringEncoder->>CharsetEncoder: encode    CharsetEncoder->>CharsetEncoder: encode    CharsetEncoder->>CharsetEncoder: 调用encodeLoop方法    CharsetEncoder-->>StringEncoder: 返回ByteBuffer    StringEncoder-->>StringCoding: 返回ByteBuffer    StringCoding-->>String: 返回byte[]

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关键字修饰的变量不会被序列化

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

其他方式的序列化:

序列化一些复杂对象: