下载为 Java 的二进制文件已损坏

Files downloaded as Binary with Java are corrupted

我写了一个下载器,可以用来下载文本文件,也可以下载图片。所以我将文件下载为二进制文件。许多下载都运行良好,但部分文本文件和许多图像文件已损坏。错误总是发生在相同的文件和相同的位置(只要我在分析文本文件时可以分辨)。我使用此代码进行下载:

    public File downloadFile(HttpURLConnection connection) {
        return writeFileDataToFile(getFileData(connection));
    }     

    //downloads the data of the file and returns the content as string
    private List<Byte> getFileData(HttpURLConnection connection) {
        List<Byte> fileData = new ArrayList<>();

        try (InputStream input = connection.getInputStream()) {
            byte[] fileChunk = new byte[8*1024];
            int bytesRead;

            do {
                bytesRead = input.read(fileChunk);
                if (bytesRead != -1) {
                    fileData.addAll(Bytes.asList(fileChunk));
                    fileChunk = new byte[8*1024];
                }
            } while (bytesRead != -1);

            return fileData;
        } catch (IOException e) {
            System.out.println("Receiving file at " + url.toString() + " failed");
            System.exit(1);
            return null; //shouldn't be reached
        }
    }

    //writes data to the file
    private File writeFileDataToFile(List<Byte> fileData) {

        if (!this.file.exists()) {
            try {
                this.file.getParentFile().mkdirs();
                this.file.createNewFile();
            } catch (IOException e) {
                System.out.println("Error while creating file at " + file.getPath());
                System.exit(1);
            }
        }

        try (OutputStream output = new FileOutputStream(file)) {
            output.write(Bytes.toArray(fileData));
            return file;
        } catch (IOException e) {
            System.out.println("Error while accessing file at " + file.getPath());
            System.exit(1);
            return null;
        }
    }

我建议您不要通过 List of Byte,因为您是从一个数组创建一个 Byte 列表,然后将其返回到一个 Byte 数组,这并不是很有效。

此外,您错误地假设了块大小(不一定是 8192 字节)。

你为什么不做一些事情:

private File writeFileDataToFile(HttpURLConnection connection) {
    if (!this.file.exists()) {
        try {
            this.file.getParentFile().mkdirs();
            //this.file.createNewFile(); // not needed, will be created at FileOutputStream
        } catch (IOException e) {
            System.out.println("Error while creating file at " + file.getPath());
            //System.exit(1);
            // instead do a throw of error or return null
            throw new YourException(message);
        }
    }
    OutputStream output = null;
    InputStream input = null;
    try {
      output = new FileOutputStream(file):
      input = connection.getInputStream();
      byte[] fileChunk = new byte[8*1024];
      int bytesRead;
      while ((bytesRead = input.read(fileChunk )) != -1) {
         output.write(fileChunk , 0, bytesRead);
      }
      return file;
    } catch (IOException e) {
      System.out.println("Receiving file at " + url.toString() + " failed");
      // System.exit(1); // you should avoid such exit
      // instead do a throw of error or return null
      throw new YourException(message);
    } finally {
      if (input != null) {
        try {
           input.close();
        } catch (Execption e2) {} // ignore
      }
      if (output != null) {
        try {
           output.close();
        } catch (Execption e2) {} // ignore
      }
    }
}

失败是将整个 fileChunk 数组添加到文件数据,即使它没有被读取操作完全填充。

修复:

//downloads the data of the file and returns the content as string
private List<Byte> getFileData(HttpURLConnection connection) {
    List<Byte> fileData = new ArrayList<>();

    try (InputStream input = connection.getInputStream()) {
        byte[] fileChunk = new byte[8*1024];
        int bytesRead;

        do {
            bytesRead = input.read(fileChunk);
            if (bytesRead != -1) {
                fileData.addAll(Bytes.asList(Arrays.copyOf(fileChunk, bytesRead)));
            }
        } while (bytesRead != -1);

        return fileData;
    } catch (IOException e) {
        System.out.println("Receiving file at " + url.toString() + " failed");
        System.exit(1);
        return null; //shouldn't be reached
    }
}

相关变化正在发生变化的地方

if (bytesRead != -1) {
    fileData.addAll(Bytes.asList(fileChunk));
    fileChunk = new byte[8*1024];
}

进入

 if (bytesRead != -1) {
    fileData.addAll(Bytes.asList(Arrays.copyOf(fileChunk, bytesRead)));
 }