首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Android/Java FormFile 多部分表單檔案上傳完整實作(Socket 底層組裝)

     編輯:Java 程式設計入門

應用場景

Android 端無法依賴高層 HTTP 庫,需手工組裝 multipart/form-data 請求,透過 Socket 直接發送。

核心實體類 FormFile

public class FormFile {
    private byte[] data;
    private InputStream inStream;
    private File file;
    private String fileName, parameterName, contentType = "application/octet-stream";
    private String operType; // URL 額外查詢參數

    // 建構子、getter/setter 略...

    /** 執行上傳 */
    public boolean post(String urlStr, Map params) throws Exception {
        final String BOUNDARY = "--------------7da2137580612";
        final String END_LINE = "--" + BOUNDARY + "--\r\n";

        URL url = new URL(urlStr);
        int port = url.getPort() == -1 ? 80 : url.getPort();
        try (Socket socket = new Socket(InetAddress.getByName(url.getHost()), port);
             OutputStream out = socket.getOutputStream();
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {

            // 1. 計算實體總長度
            StringBuilder fileMeta = buildFileMeta(BOUNDARY);
            StringBuilder textMeta = buildTextMeta(BOUNDARY, params);
            int totalLen = fileMeta.length() + textMeta.length() + 
                           (inStream != null ? (int)file.length() : data.length) + END_LINE.length();

            // 2. 發送 HTTP 請求行與 Header
            sendRequestLine(out, url, operType);
            sendHeaders(out, totalLen, BOUNDARY);

            // 3. 發送表單欄位
            out.write(textMeta.toString().getBytes());

            // 4. 發送檔案內容
            out.write(fileMeta.toString().getBytes());
            if (inStream != null) {
                byte[] buf = new byte[1024];
                int len;
                while ((len = inStream.read(buf)) != -1) out.write(buf, 0, len);
            } else {
                out.write(data);
            }
            out.write("\r\n".getBytes());

            // 5. 發送結束標記
            out.write(END_LINE.getBytes());
            out.flush();

            // 6. 讀取響應判斷
            String statusLine = in.readLine();
            return statusLine != null && statusLine.contains("200");
        }
    }
    // buildFileMeta, buildTextMeta, sendRequestLine, sendHeaders 等私有方法略...
}

關鍵組裝細節

部分格式範例
請求行POST /path?action=xxx HTTP/1.1\r\n
Content-Typemultipart/form-data; boundary=----BOUNDARY\r\n
文字欄位--BOUNDARY\r\nContent-Disposition: form-data; name="key"\r\n\r\nvalue\r\n
檔案欄位--BOUNDARY\r\nContent-Disposition: form-data; name="file"; filename="a.jpg"\r\nContent-Type: image/jpeg\r\n\r\n[二進制資料]\r\n
結束--BOUNDARY--\r\n

調用範例

File f = new File("/sdcard/photo.jpg");
Map params = new HashMap<>();
params.put("userId", "123");

FormFile ff = new FormFile(f.getName(), f, "photo", "image/jpeg");
ff.setOper("action=upload");
boolean ok = ff.post("https://192.168.1.100:8080/upload", params);

現代化建議

  • OkHttp:RequestBody.create(MultipartBody.FORM, ...) 一行搞定
  • Retrofit:@Multipart @POST("upload") Call upload(@Part MultipartBody.Part file)
  • Java 11+ HttpClient:BodyPublishers.ofByteArrays(parts)

手工 Socket 組裝僅適合極度受限環境或教學理解協議細節,生產請用成熟庫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved