Java GZIPInputStream-损坏的GZIP拖车
我有一个静态助手方法,负责从Rails应用程序中获取一个压缩的JSON字符串,并在返回Java GZIPInputStream-损坏的GZIP拖车,java,stream,gzip,ioexception,gzipinputstream,Java,Stream,Gzip,Ioexception,Gzipinputstream,我有一个静态助手方法,负责从Rails应用程序中获取一个压缩的JSON字符串,并在返回字符串表示之前解压缩数据 我编写了两个JUnit测试,一个测试JSON是否正确解析,另一个更基本的测试确定是否从服务器返回长度大于零的字符串 问题:当我运行测试套件时,第一个测试方法成功,另一个测试方法失败,出现IOException和消息“Corrupt GZIP trailer”(参见下面的代码)。我已经确定失败的不是测试本身,因为当我使测试以相反的顺序运行时,“成功的”测试是反向的(换句话说,无论发生什么
字符串
表示之前解压缩数据
我编写了两个JUnit测试,一个测试JSON是否正确解析,另一个更基本的测试确定是否从服务器返回长度大于零的字符串
问题:当我运行测试套件时,第一个测试方法成功,另一个测试方法失败,出现IOException
和消息“Corrupt GZIP trailer”(参见下面的代码)。我已经确定失败的不是测试本身,因为当我使测试以相反的顺序运行时,“成功的”测试是反向的(换句话说,无论发生什么,失败的总是第二个测试,无论两个测试中的哪一个是第二个测试)
这是帮助器方法:
public static String doHTTPGet(String urlString) throws IOException{
URL weatherAPI = new URL(urlString);
HttpURLConnection apiConnection = (HttpURLConnection) weatherAPI.openConnection();
apiConnection.setRequestMethod("GET");
apiConnection.setRequestProperty("Accept-Encoding", "gzip");
apiConnection.connect();
BufferedInputStream bufferedInputStream = new BufferedInputStream(apiConnection.getInputStream());
byte[] inputByteBuffer = new byte[10 * 1024];
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(10 * 1024); // initialize the output stream with at least one buffer's worth of bytes
while(bufferedInputStream.read(inputByteBuffer) > -1){
outputStream.write(inputByteBuffer);
}
outputStream.close();
bufferedInputStream.close();
apiConnection.disconnect();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(outputStream.toByteArray());
byteArrayInputStream.close();
GZIPInputStream gis = new GZIPInputStream(byteArrayInputStream);
InputStreamReader inputStreamReader = new InputStreamReader(gis, "UTF-8");
BufferedReader reader = new BufferedReader(inputStreamReader);
String decompressedResponse = "";
String line;
// readLine() is generating the IOException on the second pass.
while((line = reader.readLine()) != null){
decompressedResponse += line;
}
reader.close();
inputStreamReader.close();
gis.close();
return decompressedResponse;
}
该错误发生在助手方法的底部,在行((line=reader.readLine())!=null).
上。具体来说,错误发生在读取器.readLine()
上
以及两种测试方法:
@Test
public void testHttpGet(){
try {
// FILTERED_API_URL_WITH_TOKEN is merely the URL with an auth token
String apiResponse = HTTPHelper.doHTTPGet(GlobalConstants.FILTERED_API_URL_WITH_TOKEN);
assertNotNull(apiResponse);
assertTrue("The size of the API response should be greater than zero. It is an empty string.", apiResponse.length() > 0);
} catch (IOException e) {
e.printStackTrace();
assertTrue("An exception occured while trying to perform the HTTP Get to the api at URL " + GlobalConstants.FILTERED_API_URL_WITH_TOKEN, false);
}
}
@Test
public void testAPIContent(){
try {
// the getAPIJson() method basically does the same as the testHttpGet
// method, but converts the string to a json
JSONObject jsonObject = XMLProducerFromAPI.getAPIJson();
System.out.println(jsonObject);
assertNotNull(jsonObject);
} catch (IOException e) {
e.printStackTrace();
assertTrue("An IOException occured. See stack trace", false);
} catch (JSONException e) {
e.printStackTrace();
assertTrue("A JSONException occured. See stack trace", false);
}
}
我已经通读了,但我不相信它是适用的,(或者可能是,我误解了,如果是这样的话,请告诉我),我尝试了他们的方法,但只收到了相同的信息
由于doHTTPGet
方法是静态的,并且创建的对象是在方法体中完成的,因此不应重用任何内容(流、连接对象等)。坦白说,我被难倒了
问题:我是否在助手代码中做错了什么,或者我是否误解了某个对象的某些用法,从而产生了“损坏的GZIP拖车”消息?简而言之,在我的场景中,是什么导致了这个错误
和往常一样,如果我在这个问题上遗漏了什么,请告诉我
编辑
这是堆栈跟踪:
java.io.IOException: Corrupt GZIP trailer
at java.util.zip.GZIPInputStream.readTrailer(GZIPInputStream.java:200)
at java.util.zip.GZIPInputStream.read(GZIPInputStream.java:92)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.readLine(BufferedReader.java:299)
at java.io.BufferedReader.readLine(BufferedReader.java:362)
at com.weathertx.xmlserver.support.HTTPHelper.doHTTPGet(HTTPHelper.java:60)
at com.weathertx.xmlserver.tests.HttpHelperTest.getAPIResponse(HttpHelperTest.java:47)
at com.weathertx.xmlserver.tests.HttpHelperTest.testHttpGet(HttpHelperTest.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
问题已经解决了。坦率地说,我不太明白为什么它最初不起作用,或者它有什么问题(除了显然过于复杂和不必要的复杂)。多亏了它,我不知何故错过了我的第一次搜索,我能够通过基本上实现他们所做的事情来解决这个问题。这是我的最终代码:
public static String doHTTPGet(String urlString) throws IOException{
URL weatherAPI = new URL(urlString);
HttpURLConnection apiConnection = (HttpURLConnection) weatherAPI.openConnection();
apiConnection.setRequestMethod("GET");
apiConnection.setRequestProperty("Accept-Encoding", "gzip");
apiConnection.connect();
InputStream gzippedResponse = apiConnection.getInputStream();
InputStream decompressedResponse = new GZIPInputStream(gzippedResponse);
Reader reader = new InputStreamReader(decompressedResponse, "UTF-8");
StringWriter writer = new StringWriter();
char[] buffer = new char[10240];
for(int length = 0; (length = reader.read(buffer)) > 0;){
writer.write(buffer, 0, length);
}
writer.close();
reader.close();
decompressedResponse.close();
gzippedResponse.close();
apiConnection.disconnect();
return writer.toString();
}
因此,最终,我不需要通过字节数组流和到处传递数据。除了我原来的方法令人费解之外,如果有人明确知道我最初的算法在该方法的第一次调用后产生“损坏的GZIP拖车”错误消息的原因,请务必让我知道。此外,遗憾的是,所讨论的API受到IP的限制,因此,不幸的是,我无法在不知道每个人的IP的情况下授予访问权限。请比较write()调用。使用读取计数,这是正确的。你的原稿没有,@EJP,所以我的原稿每次都会准确地写入10240字节,而这一个会写入它可以读取的数量,最多可达10240字节,这意味着最后一次读取的字节数可能比这少(正确吗?)。但是,在流和连接等都关闭之后,当第二次调用该方法时,新的流和连接将打开。是否有剩余的垃圾流通过,或类似的东西?您在最后一次写入时正在写入垃圾,并且您收到的消息正是这样说的。非常清楚。@EJP是的,我现在明白了。这不是我想问的;具体来说,我很好奇为什么失败只发生在对这个方法的第二次调用上。两个调用完全相同,它们指向相同的URL并接收相同的压缩数据。考虑到所有对象都是此方法的局部对象,并且流对象在方法结束之前是关闭的,我觉得这很奇怪。虽然我理解你所说的,但仍然有一个缺失的答案,可以解释为什么它第一次成功,第二次失败,而且是始终如一的。不管怎样,谢谢你的帮助。第二个电话是同一个URL吗?如果它是不同的URL,并且第一次下载是缓冲区大小的倍数,那么问题就不会发生。