发新话题

(向老紫竹求救!O(∩_∩)O) 自己写的文件上传,但是上传大图片会失真

package upload;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;

import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;

import javax.naming.InitialContext;

import javax.servlet.*;
import javax.servlet.http.*;

import javax.sql.DataSource;

public class uploadAction extends HttpServlet {
    private static final String CONTENT_TYPE = "text/html; charset=GBK";

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    public void service(HttpServletRequest request, 
                        HttpServletResponse response) throws ServletException, IOException {response.setContentType(CONTENT_TYPE);
       
         
        byte[] image=null;
        //载取上传文件内容
        parseFileForm parse=new parseFileForm();
        image=parse.parseOneField(request);
        
        try{
            InitialContext ic=new InitialContext();
            DataSource ds=(DataSource)ic.lookup("jdbc/localDS");
            Connection conn=ds.getConnection();
            //Blob操作的第一步:插入一个空Blob字段
            PreparedStatement ps=conn.prepareStatement("insert into filetable (filename,filecnt,filetype) values (?,empty_blob(),?)");
            ps.setString(1,"test8");
            ps.setString(2,"JPEG");
            ps.executeUpdate();
            ps.close();
          //Blob操作的第二步:取出数据库表中的Blob字段。
            Statement st=conn.createStatement();
            ResultSet rs=st.executeQuery("select filecnt from filetable where filename='test8' for update");
            rs.next();
            Blob blob=rs.getBlob("filecnt");
          
            //Blob更新操作:设置输出流。
            OutputStream os=blob.setBinaryStream(0);
            //Blob更新操作:通过输出流写入内容。
            os.write(image);
            os.close(); 
            ps=conn.prepareStatement("update filetable set filecnt=? where filename='test8'");
            ps.setBlob(1,blob);
            ps.executeUpdate();
            ps.close();
           // blob.setBytes(image.length,image);
            rs.close();
            st.close();
        //重新从数据库中读出刚写入的内容,以便于测试。     
            st=conn.createStatement();
            rs=st.executeQuery("select filecnt from filetable where filename='test8'");
            rs.next();
            blob=rs.getBlob("filecnt");
            blob.getBinaryStream().read(image);
            rs.close();
            st.close();
            conn.close();
        }catch (Exception e) {
            e.printStackTrace();
        }
      //输出从数据库中Blob字段是存放的内容,以便验证结果。
      
         response.setContentType("image/jpeg");
        /*
         * Returns a ServletOutputStream suitable for writing binary data in the response.
         * The servlet container does not encode the binary data
        */
        response.getOutputStream().write(image);
        response.getOutputStream().close();
       
         
         
    }
}

package upload;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.RandomAccessFile;

import java.io.StringReader;

import javax.servlet.*;
import javax.servlet.http.*;

public class parseFileForm extends HttpServlet {
    public parseFileForm() {
    }
    public byte[] parseOneField(HttpServletRequest request) {
        try{
        ServletInputStream inStream=null;//读取客户端发送过来的二进制数据
        FileOutputStream tmpfileStream=null;//文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流
        RandomAccessFile randomFile=null;//类的实例支持对随机存储文件的读和写操作
        String tmpfileName=null;
        int streamLenth=0;
        long cntStartPoint=0,cntEndPoint=0;
        byte[] content=null;
        String sgmtDeli=null;
        //获取http输入流。
        inStream= request.getInputStream();
        streamLenth=request.getContentLength();
        //在服务器临时目录下临时文件,用于保存上传的字节流块。
        tmpfileName="d:\\temp\\"+request.getSession().getId();
        tmpfileStream=new FileOutputStream(tmpfileName);//创建一个tmpfileName的文件中写入文件流。
        
         BufferedReader in=new BufferedReader(new FileReader(tmpfileName));
            

            
            
        //获取上传内容,并将其保存在临时文件中。
        
        int bytesRead=0,totalBytes=0;
        byte[] cnt;
        while (totalBytes<streamLenth)
        {
        cnt=new byte[256];
        bytesRead=inStream.read(cnt,0,256);//将256个字节数据读入cnt数组中,0表示记录存储的位置(依次加1)
        totalBytes+=bytesRead;
        tmpfileStream.write(cnt); //将 cnt.length 个字节从指定 cnt(byte)数组写入此文件输出流中
       
       //  inStream.wait(1000);
        }
        tmpfileStream.close();
        inStream.close();
        //现已将Http协议上传的内容全部写入了临时文件。以下的代码便可在服务器上对上传的内容进行解释
        //以随机读写方式打开http临时流文件。
        randomFile=new RandomAccessFile(tmpfileName,"rw"); 
        //寻找上传内容主体的起始位置和结束位置
        sgmtDeli=randomFile.readLine();//从当前文件中读取文本的下一行。 这个方法连续地读取字节直到一个文本行的末尾。
        String line=null;
        for (int i=0;i<3;i++) {
             line=randomFile.readLine();
       }     
        //将起始位置存放在startPoint中。
        cntStartPoint=randomFile.getFilePointer();//getFilePointer获取文件的指针位置
        //定位到结束置
        boolean eofblock=false;
        while (!eofblock)
        {
        line=randomFile.readLine();
        if (line.contains(sgmtDeli))
            eofblock=true;
        }
        //将结束位置存放在endPoint中。
        cntEndPoint=randomFile.getFilePointer()-line.length();
        //将上传内容主体部分读入到字节数组中。
        int cntlen=(int)(cntEndPoint-cntStartPoint);
        content=new byte[cntlen];
        randomFile.seek(cntStartPoint);//seek()定位文件指针在文件中的位置
        randomFile.read(content,0,cntlen);
        
        randomFile.close();
        //删除临时文件
        File file=new File(tmpfileName);
        file.deleteOnExit();
        return content;
        }
        catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }
}



编辑 回复 快速回复 TOP
现在这个可以实现文件上传了,但是上传大一点的图片就会失真?上传小图片没有问题?
麻烦老紫竹提示一下,给点思路,谢谢啊!
编辑 回复 快速回复 TOP
tmpfileStream.write(cnt);

这句话明显有问题,因该用

tmpfileStream.write(cnt,0,bytesRead);

只写入读取到的长度

另外,你为何在循环里每次都 new byte[256] 太浪费了。
快乐渡过每一天,减肥坚持每一天
编辑 回复 快速回复 TOP
谢谢紫竹大哥的回答,问题已经解决
继续再问紫竹大哥一个问题(谢谢啊):
我现在文件上传没问题了,但是获得表单的值啊,我都是写死了的
现在想把filename放在input表单中,但是enctype="multipart/form-data"是二进制流
我在网上查了一下,也没有怎么看明白?
再次感谢紫竹大哥
编辑 回复 快速回复 TOP
编辑 回复 快速回复 TOP
在线等待紫竹大哥的回答啊!再次感谢啊
编辑 回复 快速回复 TOP
用上传组件获得,不要用 request,因为那里面根本没有了。

我自己也写了一个上传组件,在我的项目分类里面 http://www.java2000.net/f39
快乐渡过每一天,减肥坚持每一天
编辑 回复 快速回复 TOP
“enctype="multipart/form-data"是二进制流”,你已经说了啊,所以除了<input type="file" /> 能够上传,其它的表单项传值都是不行的,你要么就重写url的方式在地址后加上"?filename=abc"的方式让servlet能够从parameter里取到(多个文件上传就不适用了)。或者你用上传组件比如commons-fileupload就可以获得文件名什么的,当然你要想不仅仅获得文件名,还要获得其他的表单项目,那就用struts 1.x的表单就可以获得了,当然这时候上传就不要你写底层的代码了。
编辑 回复 快速回复 TOP
发新话题