使用java上载包含多部分/表单数据的zip文件时缺少字节

使用java上载包含多部分/表单数据的zip文件时缺少字节,java,file-upload,amazon-s3,multipartform-data,Java,File Upload,Amazon S3,Multipartform Data,我在将.zip文件上载到远程服务器时遇到问题,因为上载后文件中缺少一些字节。在重新下载文件时,.zip存档是不可修复的,这使我相信我需要这些字节来成功执行上载 我正在使用多部分/表单数据POST请求上载文件。下面的代码中给出了我用于执行此操作的实用工具帮助器类: import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.u

我在将.zip文件上载到远程服务器时遇到问题,因为上载后文件中缺少一些字节。在重新下载文件时,.zip存档是不可修复的,这使我相信我需要这些字节来成功执行上载

我正在使用多部分/表单数据POST请求上载文件。下面的代码中给出了我用于执行此操作的实用工具帮助器类:

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;
    }
import java.io.*;
导入java.net.HttpURLConnection;
导入java.net.URL;
导入java.net.URLConnection;
导入java.util.ArrayList;
导入java.util.LinkedHashMap;
导入java.util.List;
公共类MultipartFormDataUtil{
私有最终字符串边界;
私有静态最终字符串lineReturn=“\r\n”;
专用HttpUrl连接连接;
私有数据输出流dos;
int bytesRead、bytesAvail、bufferSize;
字节[]缓冲区;
int maxBufferSize=1*1024*1024;
列表响应;
公共MultipartFormDataUtil(字符串postrl、LinkedHashMap参数、文件文件)引发IOException{
boundary=“=-=”+System.currentTimeMillis()+”=-=”;
URL=新URL(姿势);
conn=(HttpURLConnection)url.openConnection();
conn.setDoInput(真);
连接设置输出(真);
conn.SETUSECHACHES(假);
conn.setRequestMethod(“POST”);
conn.setRequestProperty(“连接”、“保持活动”);
conn.setRequestProperty(“内容类型”、“多部分/表单数据;边界=“+boundary”);
dos=新的DataOutputStream(conn.getOutputStream());
for(字符串键:params.keySet()){
addFormPart(key,params.get(key));
}
addFilePart(文件);
完成();
}
私有void addFormPart(字符串名称、字符串值)引发IOException{
dos.writeBytes(“--”+边界+换行符);
writeBytes(“内容处置:表单数据;名称=\”“+name+\”“+lineReturn”);
dos.writeBytes(“内容类型:text/plain”+lineReturn+lineReturn);
dos.writeBytes(值+行返回);
dos.flush();
}
私有void addFilePart(文件文件)引发IOException{
FileInputStream FileInputStream=新的FileInputStream(文件);
dos.writeBytes(“--”+边界+换行符);
dos.writeBytes(“内容处理:表单数据;名称=\”文件名=\”+文件名()+“\”+行返回);
writeBytes(“内容类型:”+URLConnection.guessContentTypeFromName(file.getName())+lineReturn);
写字节(“内容传输编码:二进制”+lineReturn+lineReturn);
bytesAvail=fileInputStream.available();
bufferSize=Math.min(bytesAvail,maxBufferSize);
buffer=新字节[bufferSize];
bytesRead=fileInputStream.read(缓冲区,0,缓冲区大小);
而(字节读取>0){
写入(缓冲区,0,缓冲区大小);
bytesAvail=fileInputStream.available();
bufferSize=Math.min(bytesAvail,maxBufferSize);
bytesRead=fileInputStream.read(缓冲区,0,缓冲区大小);
}
dos.flush();
dos.writeBytes(lineReturn);
dos.flush();
fileInputStream.close();
}
私有void finish()引发IOException{
response=newarraylist();
dos.writeBytes(“--”+boundary+“--”+lineReturn);
dos.flush();
dos.close();
BufferedReader=新的BufferedReader(新的InputStreamReader(conn.getInputStream());
弦线;
而((line=reader.readLine())!=null){
响应。添加(行);
}
reader.close();
连接断开();
}
公共列表getResponse(){
返回响应;
}
若要在信用到期时给予信用,此实用程序基于和的示例。使用以下代码调用此util:

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);
    }
}
受保护的静态void postFile(字符串url、LinkedHashMap参数、文件文件)引发异常{
试一试{
MultipartFormDataUtil multipartRequest=新的MultipartFormDataUtil(url、参数、文件);
List response=multipartRequest.getResponse();
for(字符串行:响应){
系统输出打印项次(行);
}
}捕获(ioe异常ioe){
log.warn(“发布文件和表单数据时出错”,ioe);
}
}
在本例中,上载url是到Amazon S3 bucket的,后者将其传递到目标系统。正是在这个最终目标处,我可以看到应该在.zip文件上运行的进程失败了(注意:该进程由Rails应用程序运行,并给出错误“错误标识包类型:无法复制NilClass”)下载文件时,我看到文件大小为3110416字节,而不是3110466字节。我无法再提取存档文件以查看其中的内容;mac archive utility的响应为“错误2-无此类文件或目录”

我缺乏这方面的概念背景,无法了解过程中可能出现的问题。我希望有人能够告诉我,我在实用程序类中犯了错误,或者让我知道还有其他问题

感谢您提供的任何见解,如果我可以发布任何其他有帮助的内容,请告诉我

编辑:我收集的关于不同大小文件上载的一些附加信息(以字节为单位):

原创------上传------差异

10167389 uuuuuuuuuuuuu10167238 uuuuuuuuuu151

3110466 uuuuuuuuuuuuuu310416 uuuuuuuuuuuu50

156885 uuuuuuuuuuuuuuuuuuuu6885 uuuuuuuuuuu0

95639352 uuuuuuuuuuuuu95637925 uuuuuuuuuuuu1427


对于上传后丢失字节的3个文件,每个文件丢失的总数据百分比约为0.0015%(但不完全相同),但彼此不相等。

经过进一步研究,我们发现错误与此问题中所示的多部分/表单数据实用程序无关。Ins