之前有做过一个上传图片的功能,找到的资料全部都是用框架做的,当时为了尽快完成任务,就拿过来修修改改直接放线上了。对于我这样的菜鸟,任务虽然完成了,可当前更重要的是个人的技术提升。然后我又开始乱想了。经理说平时把基础多看看,嗯,上班也有一年了,年后我也写了日记进行了深刻的反思,然后重新给自己定位。理所当然的是最开始的一层,就是买家具用的人,对于各种技术都只是研究它是做什么的,怎么使用。只能拿过来用,也只会拿过来用。能力还不足以吃透它的底层和核心。再多的技术拿过来都只是会用。虽然这是做项目必备,而我也可以合格。但从个人角度出发,这样的事情重复多了,就真的是搬砖了。我想一步一步成为做家具的人,成为植树人···
想的再多不如踏实的搞点东西,嗯,开搞。任务完结后,我开始尝试用基础的servlet,来做这个功能。上传的原理我个人认为就是将本地文件作为输入流写入服务器上的某个目录下。嗯,按照这个逻辑,我开始找reques提供的方法,HttpServletRequest没有提供相关的方法,但是ServletRequest提供了一个getInputStream()方法,该方法返回的是检索ServletInputStream的request的实体的二进制数据。嗯,有点靠谱了。查看servletInputStream的api,解释是此抽象类提供一个从客户端读取二进制数据的输入流,包含一个高效的readLine的方法,是由container实现的。好了,输入流找到了,剩下的就是把读取到的数据写到某个目录下对应的文件里。
要一个jsp,提交数据
<body>
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="upload">
<input type="submit" value="submit">
</form>
</body>
剩下的就是在后台把数据给获取,然后写入。
public class UploadAction extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
InputStream in=req.getInputStream();
OutputStream out=null;
String path="C:\Users\Administrator\Desktop\promo\sub\test.jpg";
out=new FileOutputStream(path);
int c=0;
while((c=in.read())!=-1){
out.write(c);
out.flush();
}
in.close();
out.close();
}
}
我用图片测试的,跑完以后,路径下有了test.jpg,但是打开的话提示文件已经损坏。我了个大艹,又是这个问题!使用firebug看一下,提交的数据的什么的是没有问题的。这尼玛问题又是出在哪?按流程走,获取数据,写入数据,数据可以写入,没问题,那就是获取的读取的数据有问题了。将test.jpg改成test.txt跑完以后打开一看,文件竟然有三行明文字符,第一句对应的是Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryOgnVq83gcrdVAbmq,是boundary的值,第二句是Content-Disposition: form-data; name="upload"; filename="1.jpg",包含了jsp中file的参数名,filename的值是上传文件的名字。第三行Content-Type: image/jpeg,这些都是Header Field中的内容。第四行是空白。也就是说从第四行以后才是文件的内容,也就是ServletInputStream所谓的草泥马的request的实体的二进制数据!我英文很差啊! Retrieves the body of the request as binary data using a ServletInputStream,这操蛋的the body of the quest到底是啥玩意!好吧,先不管,知道问题在哪里了,那就绕过这个坑,既然获取的内容不完全是上传的文件内容,那就需要把不是文件的内容给丢掉。我的思路是,把getInputStream()或取的内容都先生成一个临时的txt文件,然后再从这个文件里读取真正的上传文件的内容。嗯,很可行。接下来就要引入一个新成员,RandomAccessFile.我跟它不熟,也是用到才去了解,嗯,此时此刻,它是我的英雄。随机文件存取流,能够在文件的任何位置查找或者写入数据。这个特性,是无敌的破防,无敌的固定伤害!好,代码继续改
public class UploadAction extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
InputStream in=req.getInputStream();
OutputStream out=null;
OutputStream fout=null;
String path="C:\Users\Administrator\Desktop\promo\sub\test.txt";
RandomAccessFile raf=new RandomAccessFile(path,"r");
String filePath="C:\Users\Administrator\Desktop\promo\sub\test.jpg";
out=new FileOutputStream(path);
fout=new FileOutputStream(filePath);
int c=0;
while((c=in.read())!=-1){
out.write(c);
out.flush();
}
this.log(raf.readLine());
this.log(raf.readLine());
this.log(raf.readLine());
this.log(raf.readLine());
int d=0;
while((d=raf.read())!=-1){
fout.write(d);
fout.flush();
}
fout.close();
in.close();
out.close();
}
}
跑完以后图片果然是正常的出来。然后继续改进,既然上传的图片的名字可以读取到,那就让再处理一下,让名字对应上
public class UploadAction extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
InputStream in=req.getInputStream();
OutputStream out=null;
OutputStream fout=null;
String path="C:\Users\Administrator\Desktop\promo\sub\temp.txt";
String filePath="C:\Users\Administrator\Desktop\promo\sub\";
out=new FileOutputStream(path);
int c=0;
while((c=in.read())!=-1){
out.write(c);
out.flush();
}
String fileName = null;
RandomAccessFile raf=new RandomAccessFile(path,"r");
this.log(raf.readLine());
String []tempName=raf.readLine().split(";");
for(String s:tempName){
if(s.contains("filename")){
String[] ss=s.split("=");
fileName=ss[ss.length-1];
}
}
this.log(raf.readLine());
this.log(raf.readLine());
fout=new FileOutputStream(filePath+fileName.replace(""", ""));
int d=0;
while((d=raf.read())!=-1){
fout.write(d);
fout.flush();
}
fout.close();
in.close();
out.close();
raf.close();
File file=new File(filePath+"temp.txt".replace(""", ""));
if(file.exists()){
if(file.delete()){
this.log("finished");
}
}
}
}
到了这里,上传文件的功能是已经实现了,不过还有一点,就是那个temp.txt文件,最后还要把它给删掉,这样就比较圆满一点,不然总觉的多了点什么
public class UploadAction extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
InputStream in=req.getInputStream();
OutputStream out=null;
OutputStream fout=null;
String path="C:\Users\Administrator\Desktop\promo\sub\temp.txt";
String filePath="C:\Users\Administrator\Desktop\promo\sub\";
out=new FileOutputStream(path);
int c=0;
while((c=in.read())!=-1){
out.write(c);
out.flush();
}
String fileName = null;
RandomAccessFile raf=new RandomAccessFile(path,"r");
this.log(raf.readLine());
String []tempName=raf.readLine().split(";");
for(String s:tempName){
if(s.contains("filename")){
String[] ss=s.split("=");
fileName=ss[ss.length-1];
}
}
this.log(raf.readLine());
this.log(raf.readLine());
fout=new FileOutputStream(filePath+fileName.replace(""", ""));
int d=0;
while((d=raf.read())!=-1){
fout.write(d);
fout.flush();
}
fout.close();
in.close();
out.close();
raf.close();
File file=new File(filePath+"temp.txt".replace(""", ""));
if(file.exists()){
if(file.delete()){
this.log("finished");
}
}
}
}
再跑一遍,嗯,没什么问题了,不过更大的问题又出来了,我上传图片什么的小文件是可以的,我手贱的上传了一部一个多G的电影,然后风扇响了,然后cpu的使用率猛窜到95%,然后我就两眼一黑,洗洗睡了···