先解释一下为什么Javac系列鸽了,现代语言编译系统是庞大且臃肿的,尤其是在jdk7之后将一部分验证工作交给Javac,解语法糖,编译优化,验证,将代码转换为指令,我花了大概2天,大量使用的重载,接口和隐晦的实现类让人头疼,只能断点调试才能确定最终的调用方法,其中各种lambda表达式更是让人不知所云,如果代码量不算庞大,我可能会有兴趣啃下这块硬骨头,但是至少20个以上的类,40个左右的方法,也许我以后可能会继续啃下去,但不是现在,毕竟我也就是个大三学生,花费过多的精力在这里有些得不偿失,以后上班了应该会慢慢补上吧,给各位一个忠告,千万不要使用lambda表达式来进行操作,可能会被重载的类型推导和难以理解的表达式真的会让人疯掉,基本没有可维护性,千万不要用!!!
好了,题外话说完了,我们进入正题,自己实现一个文件上传功能,我们先查看浏览器发送过来的数据格式
------WebKitFormBoundaryA6NcQGN8ZVqjg68D
Content-Disposition: form-data; name="表单的name属性"; filename="发送的文件名"
Content-Type: text/plain
文件的二进制内容
------WebKitFormBoundaryA6NcQGN8ZVqjg68D--
我将其拆分为这几部分
首先是标记位,标记每一段文件的起始和结束部分
------WebKitFormBoundaryA6NcQGN8ZVqjg68D
Content-Disposition部分,有用的信息其实就是filename,用来在后台生成一个一样的文件
Content-Disposition: form-data; name="表单的name属性"; filename="发送的文件名"
Content-Type属性属于文件特有的属性,不过基本没有用,因为文件名实际上已经包含文件信息,要注意,这里的换行不单单是\n,实际上是\r\n,也就是说这是两个字节,这个地方有点坑,要注意一下
让我们理清一下思路,根据标志位,获取每一段文件信息,去除文件信息,并获取文件名,根据文件名,生成文件,最后把文件信息写入,整个功能就完成了,想法很好,但是如何实现呢?
因为不知道文件的大小,很显然,我们不能将文件一次性全部加载,再去进行操作,因为如果文件大小过大,内存就爆了,所以我们需要分段加载,但是还有一个问题,即使是分段加载,我们依然要面对内存不足的可能,所以不单单是分段加载,我们需要将文件分段放入临时文件中
直接给出代码吧
import javax.servlet.annotation.WebServlet;
import java.io.*;
import java.util.HashMap;
import java.util.UUID;
/**
* 2019-10-17 17:55
* 贺驰宇
*/
@WebServlet("/upload")
public class Servlet extends javax.servlet.http.HttpServlet {
static final int GB=1024*1024*1024;
static final int MB=1024*1024;
static final int KB=1024;
int byteSize=4*MB;
HashMap<String,String> hm = new HashMap();
/**
* 尝试通过name获取map集合的缓存文件,并转储文件
*/
public void write(String name,String file) {
try {
byte[] bytes=new byte[4*MB];
FileInputStream fis = new FileInputStream(getFile("缓存文件/"+hm.get(name)));
FileOutputStream fos=new FileOutputStream(getFile(file));
int i=-1;
while ((i = fis.read(bytes)) != -1){
fos.write(bytes,0,i);
}
fos.flush();
fos.close();
fis.