Java 缓冲区长度为>;时,下载的文件已损坏;1.

Java 缓冲区长度为>;时,下载的文件已损坏;1.,java,inputstream,outputstream,Java,Inputstream,Outputstream,我正在尝试编写一个函数,在特定的URL下载一个文件。除非我将缓冲区设置为大小为1的数组(如下面的代码所示),否则该函数将生成损坏的文件 缓冲区初始化(我计划使用)上方的三元语句以及除1以外的硬编码整数值将生成一个损坏的文件 注意:最大缓冲区大小是一个常量,在我的代码中定义为8192(2^13) public static void downloadFile(String webPath, String localDir, String fileName) { try {

我正在尝试编写一个函数,在特定的URL下载一个文件。除非我将缓冲区设置为大小为1的数组(如下面的代码所示),否则该函数将生成损坏的文件

缓冲区初始化(我计划使用)上方的三元语句以及除1以外的硬编码整数值将生成一个损坏的文件

注意:最大缓冲区大小是一个常量,在我的代码中定义为8192(2^13)

public static void downloadFile(String webPath, String localDir, String fileName) {
    try {
        File localFile;
        FileOutputStream writableLocalFile;
        InputStream stream;

        url = new URL(webPath);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        int size = connection.getContentLength(); //File size in bytes
        int read = 0; //Bytes read

        localFile = new File(localDir);

        //Ensure that directory exists, otherwise create it.
        if (!localFile.exists())
            localFile.mkdirs();

        //Ensure that file exists, otherwise create it.
        //Note that if we define the file path as we do below initially and call mkdirs() it will create a folder with the file name (I.e. test.exe). There may be a better alternative, revisit later.
        localFile = new File(localDir + fileName);
        if (!localFile.exists())
            localFile.createNewFile();

        writableLocalFile = new FileOutputStream(localFile);
        stream = connection.getInputStream();

        byte[] buffer;
        int remaining;
        while (read != size) {
            remaining = size - read; //Bytes still to be read
            //remaining > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : remaining
            buffer = new byte[1]; //Adjust buffer size according to remaining data (to be read).

            read += stream.read(buffer); //Read buffer-size amount of bytes from the stream.
            writableLocalFile.write(buffer, 0, buffer.length); //Args: Bytes to read, offset, number of bytes
        }

        System.out.println("Read " + read + " bytes.");

        writableLocalFile.close();
        stream.close();
    } catch (Throwable t) {
        t.printStackTrace();
    }
}
我这样写的原因是,我可以在用户下载时为他们提供一个实时进度条。我已经从代码中删除了它以减少混乱

len = stream.read(buffer);
read += len;
writableLocalFile.write(buffer, 0, len); 
在读取字节时不能使用buffer.length,需要使用读取调用的返回值。因为它可能返回一个短读取,然后缓冲区在读取字节后包含垃圾(0字节或以前读取的数据)

除了计算剩余的和使用动态缓冲区,只需要16k或类似的值。最后一次读取将很短,这很好。

读取的字节数可能比您请求的要少。但您总是将整个缓冲区附加到文件中。您需要捕获实际的读取字节数,并仅将这些字节附加到文件中

此外:

  • 注意
    InputStream.read()
    返回-1(EOF)
  • 服务器可能返回不正确的大小。因此,检查
    read!=尺寸
    很危险。我建议不要完全依赖内容长度HTTP字段。相反,只需继续读取输入流,直到达到EOF

  • 真不敢相信我在这上面浪费了两个小时!非常感谢你的帮助!谢谢你的留言!我一定会相应地更新我的代码。