使用 java 使用 multipart/form-data 上传 zip 文件时缺少字节
Missing bytes when uploading zip file with multipart/form-data using java
我在将 .zip 文件上传到远程服务器时遇到问题,因为上传后文件中缺少一些字节。重新下载文件后,.zip 存档无法打开,这让我相信我需要这些字节才能成功执行上传。
我正在使用 multipart/form-data POST 请求上传文件。下面的代码给出了我用来执行此操作的实用程序助手 class:
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
public class MultipartFormDataUtil {
private final String boundary;
private static final String lineReturn = "\r\n";
private HttpURLConnection conn;
private DataOutputStream dos;
int bytesRead, bytesAvail, bufferSize;
byte[] buffer;
int maxBufferSize = 1*1024*1024;
List<String> response;
public MultipartFormDataUtil(String postUrl, LinkedHashMap<String, String> params, File file) throws IOException {
boundary = "=-=" + System.currentTimeMillis() + "=-=";
URL url = new URL(postUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
dos = new DataOutputStream(conn.getOutputStream());
for (String key : params.keySet()) {
addFormPart(key, params.get(key));
}
addFilePart(file);
finish();
}
private void addFormPart(String name, String value) throws IOException {
dos.writeBytes("--" + boundary + lineReturn);
dos.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"" + lineReturn);
dos.writeBytes("Content-Type: text/plain" + lineReturn + lineReturn);
dos.writeBytes(value + lineReturn);
dos.flush();
}
private void addFilePart(File file) throws IOException {
FileInputStream fileInputStream = new FileInputStream(file);
dos.writeBytes("--" + boundary + lineReturn);
dos.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"" + lineReturn);
dos.writeBytes("Content-Type: " + URLConnection.guessContentTypeFromName(file.getName()) + lineReturn);
dos.writeBytes("Content-Transfer-Encoding: binary" + lineReturn + lineReturn);
bytesAvail = fileInputStream.available();
bufferSize = Math.min(bytesAvail, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvail = fileInputStream.available();
bufferSize = Math.min(bytesAvail, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dos.flush();
dos.writeBytes(lineReturn);
dos.flush();
fileInputStream.close();
}
private void finish() throws IOException {
response = new ArrayList<String>();
dos.writeBytes("--" + boundary + "--" + lineReturn);
dos.flush();
dos.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
response.add(line);
}
reader.close();
conn.disconnect();
}
public List<String> getResponse() {
return response;
}
为了在信用到期时给予信用,此实用程序基于 Peter's Notes and CodeJava.net 中的示例。此实用程序使用以下代码调用:
protected static void postFile(String url, LinkedHashMap<String, String> params, File file) throws Exception {
try {
MultipartFormDataUtil multipartRequest = new MultipartFormDataUtil(url, params, file);
List<String> response = multipartRequest.getResponse();
for (String line : response) {
System.out.println(line);
}
} catch (IOException ioe) {
log.warn("There was an error posting the file and form data", ioe);
}
}
在这种情况下,上传 url 是到 Amazon S3 存储桶,然后将其传递到目标系统。正是在这个最终目的地,我可以看到应该在 .zip 文件上 运行ning 的过程失败了(注意:该过程是由 Rails 应用程序 运行并给出错误 "Error identifying package type: can't dup NilClass")。下载文件后,我看到文件大小为 3,110,416 字节,而不是 3,110,466 字节。我无法再提取存档以查看其中的内容; mac 存档实用程序以 "Error 2 - No such file or directory".
响应
我缺乏这方面的概念背景,无法了解流程中哪里出了问题。我希望有人能够告诉我我在实用程序中犯了一个错误 class,或者让我知道是其他问题。
感谢您提供的任何见解,如果我能post有任何其他帮助,请告诉我。
编辑:我收集了一些关于不同大小的文件上传(以字节为单位)的额外信息:
原创---------已上传---------差异
10,167,389______10,167,238______151
3,110,466_______3,110,416_______50
156,885_________156,885_________0
95,639,352______95,637,925______1,427
对于上传后丢失字节的 3 个文件,每个文件丢失的总数据百分比约为(但不完全)0.0015%,但彼此不相等。
经过进一步研究,我们发现该错误与此问题中显示的 multipart/form-data 实用程序没有任何关系。相反,它与我们在 here 中的文件下载客户端有关。我们没有将 FileTransfer 客户端设置为以二进制形式下载文件,这对于 .zip 文件是必需的。
为了您在 java 中的 multipart/form-data 目的,请随意使用原始问题中包含的代码 - 假设您的原始文件没有问题,它会很好用。
我在将 .zip 文件上传到远程服务器时遇到问题,因为上传后文件中缺少一些字节。重新下载文件后,.zip 存档无法打开,这让我相信我需要这些字节才能成功执行上传。
我正在使用 multipart/form-data POST 请求上传文件。下面的代码给出了我用来执行此操作的实用程序助手 class:
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
public class MultipartFormDataUtil {
private final String boundary;
private static final String lineReturn = "\r\n";
private HttpURLConnection conn;
private DataOutputStream dos;
int bytesRead, bytesAvail, bufferSize;
byte[] buffer;
int maxBufferSize = 1*1024*1024;
List<String> response;
public MultipartFormDataUtil(String postUrl, LinkedHashMap<String, String> params, File file) throws IOException {
boundary = "=-=" + System.currentTimeMillis() + "=-=";
URL url = new URL(postUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
dos = new DataOutputStream(conn.getOutputStream());
for (String key : params.keySet()) {
addFormPart(key, params.get(key));
}
addFilePart(file);
finish();
}
private void addFormPart(String name, String value) throws IOException {
dos.writeBytes("--" + boundary + lineReturn);
dos.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"" + lineReturn);
dos.writeBytes("Content-Type: text/plain" + lineReturn + lineReturn);
dos.writeBytes(value + lineReturn);
dos.flush();
}
private void addFilePart(File file) throws IOException {
FileInputStream fileInputStream = new FileInputStream(file);
dos.writeBytes("--" + boundary + lineReturn);
dos.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"" + lineReturn);
dos.writeBytes("Content-Type: " + URLConnection.guessContentTypeFromName(file.getName()) + lineReturn);
dos.writeBytes("Content-Transfer-Encoding: binary" + lineReturn + lineReturn);
bytesAvail = fileInputStream.available();
bufferSize = Math.min(bytesAvail, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvail = fileInputStream.available();
bufferSize = Math.min(bytesAvail, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dos.flush();
dos.writeBytes(lineReturn);
dos.flush();
fileInputStream.close();
}
private void finish() throws IOException {
response = new ArrayList<String>();
dos.writeBytes("--" + boundary + "--" + lineReturn);
dos.flush();
dos.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
response.add(line);
}
reader.close();
conn.disconnect();
}
public List<String> getResponse() {
return response;
}
为了在信用到期时给予信用,此实用程序基于 Peter's Notes and CodeJava.net 中的示例。此实用程序使用以下代码调用:
protected static void postFile(String url, LinkedHashMap<String, String> params, File file) throws Exception {
try {
MultipartFormDataUtil multipartRequest = new MultipartFormDataUtil(url, params, file);
List<String> response = multipartRequest.getResponse();
for (String line : response) {
System.out.println(line);
}
} catch (IOException ioe) {
log.warn("There was an error posting the file and form data", ioe);
}
}
在这种情况下,上传 url 是到 Amazon S3 存储桶,然后将其传递到目标系统。正是在这个最终目的地,我可以看到应该在 .zip 文件上 运行ning 的过程失败了(注意:该过程是由 Rails 应用程序 运行并给出错误 "Error identifying package type: can't dup NilClass")。下载文件后,我看到文件大小为 3,110,416 字节,而不是 3,110,466 字节。我无法再提取存档以查看其中的内容; mac 存档实用程序以 "Error 2 - No such file or directory".
响应我缺乏这方面的概念背景,无法了解流程中哪里出了问题。我希望有人能够告诉我我在实用程序中犯了一个错误 class,或者让我知道是其他问题。
感谢您提供的任何见解,如果我能post有任何其他帮助,请告诉我。
编辑:我收集了一些关于不同大小的文件上传(以字节为单位)的额外信息:
原创---------已上传---------差异
10,167,389______10,167,238______151
3,110,466_______3,110,416_______50
156,885_________156,885_________0
95,639,352______95,637,925______1,427
对于上传后丢失字节的 3 个文件,每个文件丢失的总数据百分比约为(但不完全)0.0015%,但彼此不相等。
经过进一步研究,我们发现该错误与此问题中显示的 multipart/form-data 实用程序没有任何关系。相反,它与我们在 here 中的文件下载客户端有关。我们没有将 FileTransfer 客户端设置为以二进制形式下载文件,这对于 .zip 文件是必需的。
为了您在 java 中的 multipart/form-data 目的,请随意使用原始问题中包含的代码 - 假设您的原始文件没有问题,它会很好用。