2021SC@SDUSC
core文件夹分析(6)
part.java
1、总结
继承自object
实现了Disposable接口
这个抽象类表示从 http post 流解析的文件部分。根据web.xml 中的上传配置决定使用的具体类 PartOnDisk 或 PartInMemory
如果上传的数据大小超过允许的最大上传大小(也在 web.xml 中指定),则使用 RejectedPart,虽然无法从中获取数据,但会提供有关被拒绝上传的一些信息
2、主要属性
//字段标题
protected Map headers;
3、方法
public Map getHeaders()
- 返回字段标题
public abstract int getSize()
- 返回文件内容的长度
public boolean isRejected()
- 判断该部分是否为被拒绝的部分,并在不方便的地方(例如 flowscript)提供作为 RejectedPart 实例的替代方案
- 如果这部分被拒绝,则返回 true
public String getMimeType()
- 返回mime类型(如果未知,则返回 null)
public boolean disposeWithRequest()
- 当创建它的请求处理完成时,是否希望清除此部分持有的任何临时资源? 默认为true
- 如果该部件应与请求一起处理,则返回 true
public void setDisposeWithRequest(boolean dispose)
- 设置 disposeWithRequest 标志的值(默认为 true)
- 参数dispose——如果零件应在请求处理后处理,则为 true
public abstract InputStream getInputStream()
- 返回包含文件数据的输入流
public void copyToSource(ModifiableSource source) throws IOException
- 将零件复制到可修改源的便捷方法
- 参数source——要写入的可修改源
public void copyToFile(String filename) throws IOException
- 将零件复制到文件的便捷方法
- 参数filename——要写入的文件的名称
public abstract void dispose()
- 处置此部分持有的任何资源,例如文件或内存缓冲区
- 当部件被垃圾收集时,在所有情况下都会发生处置,但明确调用它可以更快地清理资源
4、其他
补充:disposable接口
- 当组件需要在销毁之前释放和处置资源时使用 Disposable 接口
- 在组件生命周期结束时调用
dispose ()
。 此方法将在Startable.stop()
方法之后调用(如果由组件实现),组件使用此方法来释放和销毁组件拥有的任何资源
PartOnDisk.java
1、总结
继承自Part
此类表示从 http post 流解析的文件部分
2、方法
public String getFileName()
- 返回文件名
public int getSize()
- 以字节为单位返回文件大小
public InputStream getInputStream() throws IOException
- 返回包含文件数据的 (ByteArray)输入流
public void dispose()
- 清理保存部分数据的字节数组内容缓冲区
public void finalize() throws Throwable
- 调用
dispose()
,确保底层文件已被删除
RejectedPart.java
1、总结
由于请求长度超过最大上传大小而被拒绝的上传部分
继承自Part
2、方法
public int getSize()
- 获取该部分的大小
public int getMaxContentLength()
- 获取允许的最大上传大小。 这并不适用于完整的请求内容长度,包括多部分边界和其他表单数据值
- 这意味着上传部分可以被拒绝,尽管它的单个大小(一比特)小于最大大小。 因此,建议使用
getContentLength()
而不是getSize()
来构建错误消息
public int getContentLength()
- 获取导致这部分被拒绝的请求的内容长度(以字节为单位)
public boolean isRejected()
- 判断该部分是否为被拒绝的部分
public void dispose()
- 处置此部分持有的任何资源,例如文件或内存缓冲区
TokenStream.java
1、总结
MultipartParser 的实用程序类,将输入分成由给定边界分隔的部分,在每个边界之后都会有一个换行符并被解析
继承自PushbackInputStream
2、组要属性
//初始状态,未设置边界
public static final int STATE_NOBOUNDARY = -1;
//完整阅读一个部分,现在在一个新部分的开始
public static final int STATE_NEXTPART = -2;
//读取最后一个边界,多部分块的结尾
public static final int STATE_ENDMULTIPART = -3;
//流结束,这不应该发生,常用作安全检查
public static final int STATE_ENDOFSTREAM = -4;
//目前正在阅读一部分
public static final int STATE_READING = -5;
3、方法
public TokenStream(PushbackInputStream in)
- 从 in 创建一个新的推回令牌流
- 参数in:输入流
public TokenStream(PushbackInputStream in, int size)
- 从 in 创建一个新的推回令牌流
- 参数size:回推缓冲区的大小(以字节为单位)
public void setBoundary(byte[] boundary) throws MultipartException
- 设置要扫描的边界
- 参数boundary:包含边界的字节数组
public void nextPart() throws MultipartException
- 开始阅读流中的下一部分,仅当 state 为 STATE_NEXTPART 时才可以调用此方法。 它会抛出一个 MultipartExceptio
private int readToBoundary(byte[] out) throws IOException
- 填充输出缓冲区,直到它已满、已到达边界或已到达输入流的末尾
- 当到达边界时,它会被完全读取,包括尾随的 \r 和 \n
- 它不会被写入输出缓冲区,每次调用后都会更新流状态
具体方法如下:
private int readToBoundary(byte[] out) throws IOException {
if (state != STATE_READING) {
return 0;}
int boundaryIndex = 0;
int written = 0;
int b = in.read();
while (true) {
while ((byte) b != boundary[0]) {
if (b == -1) {
state = STATE_ENDOFSTREAM;
return written;
}
out[written++] = (byte) b;
if (written == out.length) {
return written; }
b = in.read(); }
// 匹配第一个字节
boundaryIndex = 0;
// 检查边界
while ((boundaryIndex < boundary.length)
&& ((byte) b == boundary[boundaryIndex])) {
b = in.read();
boundaryIndex++;}
if (boundaryIndex == boundary.length) { // 匹配边界
if (b != -1) {
if (b == '\r') { // 换行,另一部分如下
state = STATE_NEXTPART;
in.read();
} else if (b == '-') { // 连字符,多部分结束
state = STATE_ENDMULTIPART;
in.read(); // 读取下一个连字符
in.read(); // 读取\r
in.read(); // 读取\n
} else { // 其他情况则报错
throw new IOException(
"Unexpected character after boundary");
}
} else { // 边界后什么也没有,不应该发生
state = STATE_ENDOFSTREAM;}
return written;
}
// 不匹配边界
// 字节跳过,写入第一个跳过的字节,推回其余的字节
if (b != -1) { // b可能为-1
in.unread(b); // 不匹配的字节
}
in.unread(boundary, 1,
boundaryIndex - 1); // 不读取跳过边界数据
out[written++] = boundary[0];
if (written == out.length) {
return written;}
b = in.read();
}
}
补充:read()
从此输入流中读取下一个数据字节。
值字节以int类型返回,范围为0-255。如果因为流的末尾已到达而没有可用的字节,则该值返回-1。
此方法直到输入数据可用、检测到流结束或抛出异常为止才会阻塞。