溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用ServletInputStream()輸入流讀取圖片方式

發(fā)布時(shí)間:2021-10-26 13:35:41 來(lái)源:億速云 閱讀:170 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要講解了“如何使用ServletInputStream()輸入流讀取圖片方式”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“如何使用ServletInputStream()輸入流讀取圖片方式”吧!

目錄
  • 問(wèn)題描述

  • 項(xiàng)目結(jié)構(gòu)

  • 問(wèn)題原因

  • 解決方法

  • 總結(jié)回顧

問(wèn)題描述

最近遇到需要用到上傳圖片到服務(wù)器上,學(xué)習(xí)了一下原生servlet中的form上傳圖片保存到指定目錄的情況

思路:前端提交–servlet獲取inputstream–輸出到本地

獲取輸入流后輸出到本地一直打不開(kāi)提示損壞/0kb.從網(wǎng)上看到有說(shuō)需要apache的兩個(gè)包io和fileupload包.我想的是不借助第三方工具包處理(tomcat也是第三方呵呵,純的應(yīng)該是利用socket吧)

項(xiàng)目結(jié)構(gòu)

如圖所示:并未使用其余組件,創(chuàng)建了一個(gè)動(dòng)態(tài)java項(xiàng)目即可

如何使用ServletInputStream()輸入流讀取圖片方式

問(wèn)題原因

網(wǎng)上查到一片文章,大概意思是,上傳文件不是單純的文件流,其與本地io不同其中多了些東西.按照本地上傳下載的方式無(wú)法解析出來(lái).包括些分隔符\和表單的一些信息,需要重新處理

解決方法

手動(dòng)解析出圖片的流,并把其中的多余東西去掉,然后將得到的純文件流輸出到指定位置

總結(jié)回顧

該問(wèn)題居然查不到當(dāng)前時(shí)間的帖子,一般都是2-3年前的讓我有點(diǎn)意外.知其然而不知其所以然早晚被人家掣肘.在框架琳瑯滿目的當(dāng)下抄抄寫(xiě)寫(xiě)確實(shí)能解決問(wèn)題而且真的是事半功倍.

另寫(xiě)代碼要多查多看api文檔

多動(dòng)手敲代碼,不然不知道所以然,這么點(diǎn)破問(wèn)題弄了個(gè)周末

package server;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
@WebServlet(name = "streams",urlPatterns = "/UploadServlet.do")
public class CsvTest extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
            this.doPost(request, response);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        final int NONE = 0; // 狀態(tài)碼,表示沒(méi)有特殊操作
        final int DATAHEADER = 1; // 表示下一行要讀到報(bào)頭信息
        final int FILEDATA = 2; // 表示下面要讀的是上傳文件和二進(jìn)制數(shù)據(jù)
        final int FIELDDATA = 3; // 表示下面要讀到表單域的文本值
        // 請(qǐng)求消息實(shí)體的總長(zhǎng)度(請(qǐng)求消息中除消息頭之外的數(shù)據(jù)長(zhǎng)度)
        int totalbytes = request.getContentLength();
        
        File f; // 上傳文件儲(chǔ)存在服務(wù)器上
        // 容納請(qǐng)求消息實(shí)體的字節(jié)數(shù)組
        byte[] dataOrigin = new byte[totalbytes];
        // 對(duì)于post多個(gè)文件的表單,b作為原始數(shù)據(jù)的副本提供提取文件數(shù)據(jù)的操作
        byte[] b = new byte[totalbytes];
        // 請(qǐng)求消息類型
        String contentType = request.getContentType();        
        String fieldname = ""; // 表單域的名稱
        String fieldvalue = ""; // 表單域的值
        String fileFormName = ""; // 上傳的文件再表單中的名稱
        String fileRealName = ""; // 上傳文件的真實(shí)名字
        String boundary = ""; // 分界符字符串
        String lastboundary = ""; // 結(jié)束分界符字符串
        
        int fileSize = 0; // 文件長(zhǎng)度        
        // 容納表單域的名稱/值的哈希表
        Map<String, String> formfieldsTable = new HashMap<String, String>();
        // 容納文件域的名稱/文件名的哈希表
        Map<String, String> filenameTable = new HashMap<String, String>();
        
        // 在消息頭類型中找到分界符的定義
        int pos = contentType.indexOf("boundary=");
        int pos2; // position2
        
        if (pos != -1) {
        pos += "boundary=".length();
        boundary = "--" + contentType.substring(pos); // 解析出分界符
        lastboundary = boundary + "--"; // 得到結(jié)束分界符
        }
        
        int state = NONE; // 起始狀態(tài)為NONE
        
        // 得到請(qǐng)求消息的數(shù)據(jù)輸入流
        DataInputStream in = new DataInputStream(request.getInputStream());
        in.readFully(dataOrigin); // 根據(jù)長(zhǎng)度,將消息實(shí)體的內(nèi)容讀入字節(jié)數(shù)組dataOrigin中
        in.close(); // 關(guān)閉數(shù)據(jù)流
        String reqcontent = new String(dataOrigin); // 從字節(jié)數(shù)組中得到表示實(shí)體的字符串
        
        // 從字符串中得到輸出緩沖流
        BufferedReader reqbuf = new BufferedReader(new StringReader(reqcontent));
        
        // 設(shè)置循環(huán)標(biāo)志
        boolean flag = true;
        // int i = 0;
        while (flag == true) {
        String s = reqbuf.readLine();
        if (s == lastboundary || s == null)
        break;
        switch (state) {
        case NONE:
        if (s.startsWith(boundary)) {
        // 如果讀到分界符,則表示下一行一個(gè)頭信息
        state = DATAHEADER;
        // i += 1;
        }
        break;
        case DATAHEADER:
        pos = s.indexOf("filename=");
        // 先判斷出這是一個(gè)文本表單域的頭信息,還是一個(gè)上傳文件的頭信息
        if (pos == -1) {
        // 如果是文本表單域的頭信息,解析出表單域的名稱
        pos = s.indexOf("name=");
        pos += "name=".length() + 1; // 1表示后面的"的占位
        s = s.substring(pos);
        int l = s.length();
        s = s.substring(0, l - 1); // 應(yīng)該是"
        fieldname = s; // 表單域的名稱放入fieldname
        out.print("fieldname=" + fieldname);
        state = FIELDDATA; // 設(shè)置狀態(tài)碼,準(zhǔn)備讀取表單域的值
        } else {
        // 如果是文件數(shù)據(jù)的頭,先存儲(chǔ)這一行,用于在字節(jié)數(shù)組中定位
        String temp = s;
        // 先解析出文件名
        pos = s.indexOf("name=");
        pos += "name=".length() + 1; // 1表示后面的"的占位
        pos2 = s.indexOf("filename=");
        String s1 = s.substring(pos, pos2 - 3); // 3表示";加上一個(gè)空格
        fileFormName = s1;
        pos2 += "filename=".length() + 1; // 1表示后面的"的占位
        s = s.substring(pos2);
        int l = s.length();
        s = s.substring(0, l - 1);
        pos2 = s.lastIndexOf("\\"); // 對(duì)于IE瀏覽器的設(shè)置
        s = s.substring(pos2 + 1);
        fileRealName = s;
        out.print("fileRealName=" + fileRealName + "<br>");
        out.print("fileRealName.length()=" + fileRealName.length() + "<br>");
        if (fileRealName.length() != 0) { // 確定有文件被上傳
        // 下面這一部分從字節(jié)數(shù)組中取出文件的數(shù)據(jù)
        b = dataOrigin; // 復(fù)制原始數(shù)據(jù)以便提取文件
        pos = byteIndexOf(b, temp, 0); // 定位行
        
        // 定位下一行,2 表示一個(gè)回車和一個(gè)換行占兩個(gè)字節(jié)
        b = subBytes(b, pos + temp.getBytes().length + 2,
        b.length);
        
        // 再讀一行信息,是這一部分?jǐn)?shù)據(jù)的Content-type
        s = reqbuf.readLine();
        
        // 設(shè)置文件輸入流,準(zhǔn)備寫(xiě)文件
        f = new File("C:" + File.separator +"Users" + File.separator +"Administrator" + File.separator +"Desktop" + File.separator +fileRealName);
        DataOutputStream fileout = new DataOutputStream(
        new FileOutputStream(f));
        
        // 字節(jié)數(shù)組再往下一行,4表示兩回車換行占4個(gè)字節(jié),本行的回車換行2個(gè)字節(jié),Content-type的下
        // 一行是回車換行表示的空行,占2個(gè)字節(jié)
        // 得到文件數(shù)據(jù)的起始位置
        b = subBytes(b, s.getBytes().length + 4, b.length);
        pos = byteIndexOf(b, boundary, 0); // 定位文件數(shù)據(jù)的結(jié)尾
        b = subBytes(b, 0, pos - 1); // 取得文件數(shù)據(jù)
        fileout.write(b, 0, b.length - 1); // 將文件數(shù)據(jù)存盤(pán)
        fileout.close();
        fileSize = b.length - 1; // 文件長(zhǎng)度存入fileSize
        out.print("fileFormName=" + fileFormName + " filename="
        + fileRealName + " fileSize=" + fileSize
        + "<br>");
        filenameTable.put(fileFormName, fileRealName);
        state = FILEDATA;
        }
        }
        break;
        case FIELDDATA:
        // 讀取表單域的值
        s = reqbuf.readLine();
        fieldvalue = s; // 存入fieldvalue
        out.print(" fieldvalue=" + fieldvalue + "<br>");
        formfieldsTable.put(fieldname, fieldvalue);
        state = NONE;
        break;
        case FILEDATA:
        // 如果是文件數(shù)據(jù)不進(jìn)行分析,直接讀過(guò)去
        while ((!s.startsWith(boundary))
        && (!s.startsWith(lastboundary))) {
        s = reqbuf.readLine();
        if (s.startsWith(boundary)) {
        state = DATAHEADER;
        } else {
        break;
        }
        }
        break;
        }        
        }
        // 指定內(nèi)容類型,并且可以顯示中文
        out.println("<HTML");
        out.println("<HEAD><TITLE>文件上傳結(jié)果</TITLE></HEAD>");
        out.println("<BODY>");
        out.println("<H1>文件上傳結(jié)果</H1><hr>");
        out.println("ID為" + formfieldsTable.get("FileID1") + "的文件"
        + filenameTable.get("FileData1") + "已經(jīng)上傳!<br>");
        out.println("ID為" + formfieldsTable.get("FileID2") + "的文件"
        + filenameTable.get("FileData2") + "已經(jīng)上傳!<br>");
        // out.println("i = " + i + "<br>");
        out.println("</BODY>");
        out.println("</HTML>");
        }        
        
        private static int byteIndexOf(byte[] b, String s, int start) {
        return byteIndexOf(b, s.getBytes(), start);
        }        
        
        private static int byteIndexOf(byte[] b, byte[] s, int start) {
        int i;
        if (s.length == 0) {
        return 0;
        }
        int max = b.length - s.length;
        if (max < 0) {
        return -1;
        }
        if (start > max) {
        return -1;
        }
        if (start < 0) {
        start = 0;
        }
        // 在b中找到s的第一個(gè)元素
        search: for (i = start; i <= max; i++) {
        if (b[i] == s[0]) {
        // 找到了s中的第一個(gè)元素后,比較剩余的部分是否相等
        int k = 1;
        while (k < s.length) {
        if (b[k + i] != s[k]) {
        continue search;
        }
        k++;
        }
        return i;
        }
        }
        return -1;
        }        
        
        private static byte[] subBytes(byte[] b, int from, int end) {
        byte[] result = new byte[end - from];
        System.arraycopy(b, from, result, 0, end - from);
        return result;
        }
        
        private static String subBytesString(byte[] b, int from, int end) {
        return new String(subBytes(b, from, end));
        }        
        }

感謝各位的閱讀,以上就是“如何使用ServletInputStream()輸入流讀取圖片方式”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)如何使用ServletInputStream()輸入流讀取圖片方式這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI