【问题标题】:Byte array to file in java without overwriting,字节数组到java中的文件而不覆盖,
【发布时间】:2017-02-24 09:27:45
【问题描述】:

下面的代码从HTTP请求中获取一个字节数组并保存在bytes[]中,最终的数据会保存在message[]中。

我通过将其转换为 String[] 来检查它是否包含标头,如果有,我会从标头中读取一些信息,然后通过将标头后面的字节保存到 message[] 来将其切断。

然后我尝试使用 FileOutputStream 将 message[] 输出到文件,它工作得稍微好一点,但只保存了 10KB 的信息,while 循环的一次迭代,(似乎被覆盖),如果我设置 FileOutputStream(file, true) 附加信息,它可以工作......一次,然后文件只是添加到我下次运行它时,这不是我想要的。如何在每次迭代中使用多个字节块写入同一个文件,但如果再次运行程序,仍然会完整地覆盖文件?

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();
                }

            }
        }

【问题讨论】:

    标签: java arrays fileoutputstream


    【解决方案1】:

    您将在循环的每次迭代中打开一个新的FileOutputStream。不要那样做。在循环打开它,然后按你的方式循环和写入,然后在循环结束时关闭。 (如果您在其中使用带有 while 循环的 try-with-resources 语句,那就没问题了。)

    这只是问题的一部分——您还在循环的每次迭代中执行其他所有操作,包括检查标头。如果您读取的字节数组包含标题集的part,或者实际上是标题分隔符的part,那将是一个真正的问题。

    此外,正如 EJP 所指出的,您忽略了 read 的返回值,除了使用它来判断您是否完成。您应该始终使用read 的返回值来了解字节数组中有多少是实际可用的数据。

    从根本上说,您要么需要将 整个 响应读入一个字节数组以开始 - 这很容易做到,但在内存中可能效率低下 - 或者接受你正在处理的事实一个流,并编写更复杂的代码来检测标题的结尾。

    不过,IMO 最好使用一个已经了解所有这些标头处理的 HTTP 库,这样您就不需要自己动手了。除非您自己编写一个低级 HTTP 库,否则您不应该处理低级 HTTP 细节,您应该依赖一个好的库。

    【讨论】:

    • 更新了您的建议。我只是在等待 EJP 关于如何设置字符串的回复。
    【解决方案2】:

    在循环之前打开文件。

    注意,您需要将read() 的结果存储在一个变量中,并将该变量作为长度传递给new String()。否则,您将缓冲区中的垃圾转换为超出实际读取的内容。

    【讨论】:

    • 到我的新字节串?我将如何设置字符串长度?
    • @johnstamos:你会调用字符串构造函数来接受它:new String(bytes, 0, length, StandardCharsets.UTF_8)
    • 这只是答案的一部分,不是很有用,因为每次从 inputStream 读取时处理标头也可能导致垃圾被写入文件。
    【解决方案3】:

    读取数据存在问题 - 您只读取了响应的一部分(因为当时尚未将所有数据传输给您) - 所以很明显您只写入了那部分。

    查看此答案以了解如何从 InputStream 中读取完整数据:

    Convert InputStream to byte array in Java

    【讨论】:

    • while (dis.read(bytes) > 0) 看起来它正在向我读取所有数据。它只是分几块读取它,并在每次迭代时重新打开文件以输出。
    • 但是再看一遍,我同意还有更多内容。
    • @Jon Skeet ok :) 对不起 -1,但是当你删除了你的帖子我无法撤消它,如果你写一些有用的东西,我会在下次我们在这里见面时投票 - 我'我相信你会做的:)。干杯!
    • 我删除了它以提供更全面的回应。很快就会取消删除。 (现在完成...)
    猜你喜欢
    • 2017-07-06
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 2015-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多