您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何使用ServletInputStream()輸入流讀取圖片方式”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何使用ServletInputStream()輸入流讀取圖片方式”吧!
問題描述
項目結構
問題原因
解決方法
總結回顧
最近遇到需要用到上傳圖片到服務器上,學習了一下原生servlet中的form上傳圖片保存到指定目錄的情況
思路:前端提交–servlet獲取inputstream–輸出到本地
獲取輸入流后輸出到本地一直打不開提示損壞/0kb.從網上看到有說需要apache的兩個包io和fileupload包.我想的是不借助第三方工具包處理(tomcat也是第三方呵呵,純的應該是利用socket吧)
如圖所示:并未使用其余組件,創建了一個動態java項目即可
網上查到一片文章,大概意思是,上傳文件不是單純的文件流,其與本地io不同其中多了些東西.按照本地上傳下載的方式無法解析出來.包括些分隔符\和表單的一些信息,需要重新處理
手動解析出圖片的流,并把其中的多余東西去掉,然后將得到的純文件流輸出到指定位置
該問題居然查不到當前時間的帖子,一般都是2-3年前的讓我有點意外.知其然而不知其所以然早晚被人家掣肘.在框架琳瑯滿目的當下抄抄寫寫確實能解決問題而且真的是事半功倍.
另寫代碼要多查多看api文檔
多動手敲代碼,不然不知道所以然,這么點破問題弄了個周末
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; // 狀態碼,表示沒有特殊操作 final int DATAHEADER = 1; // 表示下一行要讀到報頭信息 final int FILEDATA = 2; // 表示下面要讀的是上傳文件和二進制數據 final int FIELDDATA = 3; // 表示下面要讀到表單域的文本值 // 請求消息實體的總長度(請求消息中除消息頭之外的數據長度) int totalbytes = request.getContentLength(); File f; // 上傳文件儲存在服務器上 // 容納請求消息實體的字節數組 byte[] dataOrigin = new byte[totalbytes]; // 對于post多個文件的表單,b作為原始數據的副本提供提取文件數據的操作 byte[] b = new byte[totalbytes]; // 請求消息類型 String contentType = request.getContentType(); String fieldname = ""; // 表單域的名稱 String fieldvalue = ""; // 表單域的值 String fileFormName = ""; // 上傳的文件再表單中的名稱 String fileRealName = ""; // 上傳文件的真實名字 String boundary = ""; // 分界符字符串 String lastboundary = ""; // 結束分界符字符串 int fileSize = 0; // 文件長度 // 容納表單域的名稱/值的哈希表 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 + "--"; // 得到結束分界符 } int state = NONE; // 起始狀態為NONE // 得到請求消息的數據輸入流 DataInputStream in = new DataInputStream(request.getInputStream()); in.readFully(dataOrigin); // 根據長度,將消息實體的內容讀入字節數組dataOrigin中 in.close(); // 關閉數據流 String reqcontent = new String(dataOrigin); // 從字節數組中得到表示實體的字符串 // 從字符串中得到輸出緩沖流 BufferedReader reqbuf = new BufferedReader(new StringReader(reqcontent)); // 設置循環標志 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)) { // 如果讀到分界符,則表示下一行一個頭信息 state = DATAHEADER; // i += 1; } break; case DATAHEADER: pos = s.indexOf("filename="); // 先判斷出這是一個文本表單域的頭信息,還是一個上傳文件的頭信息 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); // 應該是" fieldname = s; // 表單域的名稱放入fieldname out.print("fieldname=" + fieldname); state = FIELDDATA; // 設置狀態碼,準備讀取表單域的值 } else { // 如果是文件數據的頭,先存儲這一行,用于在字節數組中定位 String temp = s; // 先解析出文件名 pos = s.indexOf("name="); pos += "name=".length() + 1; // 1表示后面的"的占位 pos2 = s.indexOf("filename="); String s1 = s.substring(pos, pos2 - 3); // 3表示";加上一個空格 fileFormName = s1; pos2 += "filename=".length() + 1; // 1表示后面的"的占位 s = s.substring(pos2); int l = s.length(); s = s.substring(0, l - 1); pos2 = s.lastIndexOf("\\"); // 對于IE瀏覽器的設置 s = s.substring(pos2 + 1); fileRealName = s; out.print("fileRealName=" + fileRealName + "<br>"); out.print("fileRealName.length()=" + fileRealName.length() + "<br>"); if (fileRealName.length() != 0) { // 確定有文件被上傳 // 下面這一部分從字節數組中取出文件的數據 b = dataOrigin; // 復制原始數據以便提取文件 pos = byteIndexOf(b, temp, 0); // 定位行 // 定位下一行,2 表示一個回車和一個換行占兩個字節 b = subBytes(b, pos + temp.getBytes().length + 2, b.length); // 再讀一行信息,是這一部分數據的Content-type s = reqbuf.readLine(); // 設置文件輸入流,準備寫文件 f = new File("C:" + File.separator +"Users" + File.separator +"Administrator" + File.separator +"Desktop" + File.separator +fileRealName); DataOutputStream fileout = new DataOutputStream( new FileOutputStream(f)); // 字節數組再往下一行,4表示兩回車換行占4個字節,本行的回車換行2個字節,Content-type的下 // 一行是回車換行表示的空行,占2個字節 // 得到文件數據的起始位置 b = subBytes(b, s.getBytes().length + 4, b.length); pos = byteIndexOf(b, boundary, 0); // 定位文件數據的結尾 b = subBytes(b, 0, pos - 1); // 取得文件數據 fileout.write(b, 0, b.length - 1); // 將文件數據存盤 fileout.close(); fileSize = b.length - 1; // 文件長度存入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: // 如果是文件數據不進行分析,直接讀過去 while ((!s.startsWith(boundary)) && (!s.startsWith(lastboundary))) { s = reqbuf.readLine(); if (s.startsWith(boundary)) { state = DATAHEADER; } else { break; } } break; } } // 指定內容類型,并且可以顯示中文 out.println("<HTML"); out.println("<HEAD><TITLE>文件上傳結果</TITLE></HEAD>"); out.println("<BODY>"); out.println("<H1>文件上傳結果</H1><hr>"); out.println("ID為" + formfieldsTable.get("FileID1") + "的文件" + filenameTable.get("FileData1") + "已經上傳!<br>"); out.println("ID為" + formfieldsTable.get("FileID2") + "的文件" + filenameTable.get("FileData2") + "已經上傳!<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的第一個元素 search: for (i = start; i <= max; i++) { if (b[i] == s[0]) { // 找到了s中的第一個元素后,比較剩余的部分是否相等 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()輸入流讀取圖片方式”的內容了,經過本文的學習后,相信大家對如何使用ServletInputStream()輸入流讀取圖片方式這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。