欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2021年10月26日 10:33:48   作者:guichao.dong  
這篇文章主要介紹了使用ServletInputStream()輸入流讀取圖片方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

問題描述

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

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

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

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

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

問題原因

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

解決方法

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

總結(jié)回顧

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

另寫代碼要多查多看api文檔

多動(dòng)手敲代碼,不然不知道所以然,這么點(diǎ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)碼,表示沒有特殊操作
        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)備寫文件
        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ù)存盤
        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)行分析,直接讀過去
        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));
        }        
        }

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 為何修改equals方法時(shí)還要重寫hashcode方法的原因分析

    為何修改equals方法時(shí)還要重寫hashcode方法的原因分析

    這篇文章主要介紹了為何修改equals方法時(shí)還要重寫hashcode方法的原因分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Sonar編譯問題對(duì)應(yīng):File [...] can''t be indexed twice.

    Sonar編譯問題對(duì)應(yīng):File [...] can''t be indexed twice.

    今天小編就為大家分享一篇關(guān)于Sonar編譯問題對(duì)應(yīng):File [...] can't be indexed twice.,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • SpringBoot獲取當(dāng)前運(yùn)行環(huán)境三種方式小結(jié)

    SpringBoot獲取當(dāng)前運(yùn)行環(huán)境三種方式小結(jié)

    在使用SpringBoot過程中,我們只需要引入相關(guān)依賴,然后在main方法中調(diào)用SpringBootApplication.run(應(yīng)用程序啟動(dòng)類.class)方法即可,那么SpringBoot是如何獲取當(dāng)前運(yùn)行環(huán)境呢,接下來由小編給大家介紹一下SpringBoot獲取當(dāng)前運(yùn)行環(huán)境三種方式,需要的朋友可以參考下
    2024-01-01
  • java中File類的使用方法

    java中File類的使用方法

    本篇文章介紹了,在java中File類的使用方法。需要的朋友參考下
    2013-04-04
  • SpringBoot項(xiàng)目使用協(xié)同過濾的實(shí)現(xiàn)

    SpringBoot項(xiàng)目使用協(xié)同過濾的實(shí)現(xiàn)

    協(xié)同過濾是一種常用的推薦系統(tǒng)算法,用于預(yù)測(cè)用戶可能喜歡的物品,本文主要介紹了SpringBoot項(xiàng)目使用協(xié)同過濾的實(shí)現(xiàn),感興趣的可以了解一下
    2023-09-09
  • feign參數(shù)過多導(dǎo)致調(diào)用失敗的解決方案

    feign參數(shù)過多導(dǎo)致調(diào)用失敗的解決方案

    這篇文章主要介紹了feign參數(shù)過多導(dǎo)致調(diào)用失敗的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • SpringBoot WebSocket實(shí)時(shí)監(jiān)控異常的詳細(xì)流程

    SpringBoot WebSocket實(shí)時(shí)監(jiān)控異常的詳細(xì)流程

    最近做了一個(gè)需求,消防的設(shè)備巡檢,如果巡檢發(fā)現(xiàn)異常,通過手機(jī)端提交,后臺(tái)的實(shí)時(shí)監(jiān)控頁面實(shí)時(shí)獲取到該設(shè)備的信息及位置,然后安排員工去處理。這篇文章主要介紹了SpringBoot WebSocket實(shí)時(shí)監(jiān)控異常的全過程,感興趣的朋友一起看看吧
    2021-10-10
  • 淺談Servlet 實(shí)現(xiàn)網(wǎng)頁重定向的方法

    淺談Servlet 實(shí)現(xiàn)網(wǎng)頁重定向的方法

    本篇文章主要介紹了Servlet 實(shí)現(xiàn)重定向幾種方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • Java基于Tcp/ip連接的多人交互聊天室

    Java基于Tcp/ip連接的多人交互聊天室

    這篇文章主要為大家詳細(xì)介紹了Java基于Tcp/ip連接的多人交互聊天室,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • Java Swing程序設(shè)計(jì)實(shí)戰(zhàn)

    Java Swing程序設(shè)計(jì)實(shí)戰(zhàn)

    今天教大家怎么用JavaSwing工具包實(shí)現(xiàn)一個(gè)程序的界面設(shè)計(jì),文中有非常詳細(xì)的代碼示例及注釋,對(duì)正在學(xué)習(xí)Java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05

最新評(píng)論