下面的代码从HTTP请求中获取一个字节数组并将其保存在bytes []中,最终数据将保存在message []中。
我通过将其转换为String []来检查它是否包含标题,如果我这样做,我会从标题中读取一些信息,然后通过将标题之后的字节保存到message []来将其剪掉。
然后我尝试使用FileOutputStream将message []输出到文件,它稍微有效,但只保存10KB的信息,while循环的一次迭代,(似乎是覆盖),如果我设置了FileOutputStream(文件,真的)附加信息,它工作...一次,然后文件刚刚添加到我下次运行它,这不是我想要的。如何在每次迭代中使用多个字节块写入同一文件,但如果再次运行程序,仍然会完整地覆盖文件?
byte bytes[] = new byte[(10*1024)];
while (dis.read(bytes) > 0)
{
//Set all the bytes to the message
byte message[] = bytes;
String string = new String(bytes, "UTF-8");
//Does bytes contain header?
if (string.contains("\r\n\r\n")){
String theByteString[] = string.split("\r\n\r\n");
String theHeader = theByteString[0];
String[] lmTemp = theHeader.split("Last-Modified: ");
String[] lm = lmTemp[1].split("\r\n");
String lastModified = lm[0];
//Cut off the header and save the rest of the data after it
message = theByteString[1].getBytes("UTF-8");
//cache
hm.put(url, lastModified);
}
//Output message[] to file.
File f = new File(hostName + path);
f.getParentFile().mkdirs();
f.createNewFile();
try (FileOutputStream fos = new FileOutputStream(f)) {
fos.write(message);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
答案 0 :(得分:5)
您在循环的每次迭代中打开一个新的FileOutputStream
。不要这样做。在外部循环中打开它,然后循环并按原样写入,然后在循环结束时关闭。 (如果您使用带有while
循环的try-with-resources语句,那就没问题了。)
这只是问题的一部分 - 你还在循环的每次迭代中也做其他一切,包括检查标题。如果您读取的字节数组包含标题集的 part ,或者标题分隔符的 part ,则这将成为一个真正的问题。
此外,正如EJP所指出的那样,除了使用它来判断你是否完成之外,你忽略了read
的返回值。你应该总是使用read
的返回值来知道有多少字节数组是实际可用的数据。
从根本上说,您需要将整个响应读入字节数组才能开始 - 这很容易做到,但在内存中可能效率低下 - 或接受您的事实处理流,并编写更复杂的代码来检测标题的结尾。
更好的是,IMO将使用一个HTTP库,已经了解所有这些标头处理,因此您不需要自己完成。除非你自己编写一个低级HTTP库,否则你不应该处理低级HTTP细节,你应该依赖一个好的库。
答案 1 :(得分:1)
在循环之前打开文件。
注意,您需要将read()
的结果存储在变量中,并将该变量作为长度传递给new String()
。否则,您将缓冲区中的垃圾转换为实际读取的垃圾。
答案 2 :(得分:0)
读取数据存在问题 - 您只读取部分响应(因为此时并非所有数据都转移给您) - 所以您很可能只编写该部分。
检查此答案,了解如何从InputStream中读取完整数据: