我试图在此处修改@BalusC优秀教程,以发送gzip压缩文件。这是一个有效的java类:
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.zip.GZIPOutputStream; public final class NetworkService { // *** EDIT THOSE AS APROPRIATE private static final String FILENAME = "C:/Dropbox/TMP.txt"; private static final String URL = "http://192.168.1.64:8080/DataCollectionServlet/"; // *** END EDIT private static final CharSequence CRLF = "\r\n"; private static boolean isServerGzip = true; // *** private static String charsetForMultipartHeaders = "UTF-8"; public static void main(String[] args) { HttpURLConnection connection = null; OutputStream serverOutputStream = null; try { File file = new File(FILENAME); final String boundary = Long .toHexString(System.currentTimeMillis()); connection = connection(true, boundary); serverOutputStream = connection.getOutputStream(); try { flushMultiPartData(file, serverOutputStream, boundary); } catch (IOException e) {} System.out.println(connection.getResponseCode()); // 200 } catch (IOException e) { // Network unreachable : not connected // No route to host : probably on an encrypted network // Connection timed out : Server DOWN } finally { if (connection != null) connection.disconnect(); } } private static HttpURLConnection connection(boolean isMultiPart, String boundary) throws MalformedURLException, IOException { HttpURLConnection connection = (HttpURLConnection) new URL(URL) .openConnection(); connection.setDoOutput(true); // triggers POST connection.setUseCaches(false); // *** no difference connection.setRequestProperty("Connection", "Keep-Alive"); connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) " + "Gecko/20100401"); // *** tried others no difference connection.setChunkedStreamingMode(1024); // *** no difference if (isMultiPart) { if (boundary == null || "".equals(boundary.trim())) throw new IllegalArgumentException("Boundary can't be " + ((boundary == null) ? "null" : "empty")); connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); } return connection; } // ========================================================================= // Multipart // ========================================================================= private static void flushMultiPartData(File file, OutputStream serverOutputStream, String boundary) throws IOException { PrintWriter writer = null; try { // true = autoFlush, important! writer = new PrintWriter(new OutputStreamWriter(serverOutputStream, charsetForMultipartHeaders), true); appendBinary(file, boundary, writer, serverOutputStream); // End of multipart/form-data. writer.append("--" + boundary + "--").append(CRLF); } finally { if (writer != null) writer.close(); } } private static void appendBinary(File file, String boundary, PrintWriter writer, OutputStream output) throws FileNotFoundException, IOException { // Send binary file. writer.append("--" + boundary).append(CRLF); writer.append( "Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + file.getName() + "\"").append(CRLF); writer.append( "Content-Type: " // *** + ((isServerGzip) ? "application/gzip" : URLConnection .guessContentTypeFromName(file.getName()))) .append(CRLF); writer.append("Content-Transfer-Encoding: binary").append(CRLF); writer.append(CRLF).flush(); InputStream input = null; OutputStream output2 = output; if (isServerGzip) { output2 = new GZIPOutputStream(output); } try { input = new FileInputStream(file); byte[] buffer = new byte[1024]; // *** tweaked, no difference for (int length = 0; (length = input.read(buffer)) > 0;) { output2.write(buffer, 0, length); } output2.flush(); // Important! Output cannot be closed. Close of // writer will close output as well. } finally { if (input != null) try { input.close(); } catch (IOException logOrIgnore) {} } writer.append(CRLF).flush(); // CRLF is important! It indicates end of // binary boundary. } }
您必须编辑FILENAME和URL字段,并在URL中设置一个servlet-其doPost()方法是:
FILENAME
URL
doPost()
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Collection<Part> parts = req.getParts(); for (Part part : parts) { File save = new File(uploadsDirName, getFilename(part) + "_" + System.currentTimeMillis() + ".zip"); final String absolutePath = save.getAbsolutePath(); log.debug(absolutePath); part.write(absolutePath); sc.getRequestDispatcher(DATA_COLLECTION_JSP).forward(req, resp); } }
现在,当isServerGzipfield设置为true时,FILENAME会被正确压缩并发送到服务器,但是当我尝试将其提取时,它已损坏(我在Windows上使用7z,它将打开gzip文件作为存档,但是当我尝试将文件提取到 内部时 , gzip归档文件说它已损坏-尽管确实提取了(确实损坏了)文件)。尝试了各种文件-较大的文件最终在某个点被破坏,较小的文件最终提取为空- 档案中较大文件的报告大小比实际文件大得多,而较小文件为0。我标记了需要注意// ***。我可能会错过一些连接配置,或者我用gzip压缩流的方式可能是完全错误或…? 尝试调整连接属性,缓冲区,缓存等无济于事
isServerGzip
// ***
你需要打电话
((GZIPOutputStream)output2).finish();
冲洗前。在此处查看javadoc。它指出
完成压缩数据写入输出流的操作,而无需关闭基础流。将多个过滤器连续应用于同一输出流时,请使用此方法。
你在做什么 所以
for (int length = 0; (length = input.read(buffer)) > 0;) output2.write(buffer, 0, length); } ((GZIPOutputStream)output2).finish(); //Write the compressed parts // obviously make sure output2 is truly GZIPOutputStream output2.flush(); //
关于 将多个过滤器连续应用于同一输出流的主题 ,这就是我的理解方式:
您有一个OutputStream到HTTP服务器的,即套接字连接。该HttpUrlConnection写头,然后你直接写体。在这种情况下(多部分),您将边界和标头发送为未压缩的字节,已压缩的文件内容,然后再次发送边界。因此,流最终看起来像这样:
OutputStream
HttpUrlConnection
start writing with GZIPOutputStream v |---boundary---|---the part headers---|---gzip encoded file content bytes---|---boundary---| ^ ^ write directly with PrintWriter use PrintWriter again
因此,您可以看到如何用不同的过滤器依次编写不同的部分。请将PrintWriter视为未过滤的过滤器,您提供的任何内容都将直接编写。的GZIPOutputStream是一个gzip滤波器,其编码(的gzip)字节它给。
PrintWriter
GZIPOutputStream
至于源代码,看在你的Java JDK的安装,你应该有一个src.zip包含公开的源代码文件,java.lang*,java.util.*,java.io.*,javax.*,等。
src.zip
java.lang*
java.util.*
java.io.*
javax.*