Search code examples
javahttpniojava-nio

How to check content-length match after download image in java Nio?


    static void downloadWebp(String url) {
        URL url1;
        try {
            url1 = new URL(url);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
        {
            // download webp
            ReadableByteChannel readableByteChannel;
            try {
                readableByteChannel = Channels.newChannel(url1.openStream());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            Path path = Paths.get(System.getProperty("user.home"), "image", Paths.get(url1.getPath()).getFileName().toString() + 1);
            try (FileOutputStream fileOutputStream = new FileOutputStream(path.toAbsolutePath().toString())) {
                fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            // Can I check if download file's length matches the content-length header ?
        }
    }

Call like

downloadWebp("https://cdn.discordapp.com/attachments/1098794840742961242/1100590092957003877/Jeffery_cherry_blossoms_blooming_in_the_rain_by_Yoko_Ishii_wate_8a2f060e-32dc-4567-a3df-8bfdbb56adfd.webp");

As In previous java code, I had download a image, how can I double check if downloaded file's length matches the content-length header's value ?

As I found some file not really fully downloaded after fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE); returns, I have to retry in that case.


Solution

  • Try this:

    public static void main(String[] args) throws Exception {
        downloadWebp(
            Files.createTempFile("sprites", "svg"),
            URI.create("https://cdn.sstatic.net/Img/unified/sprites.svg?v=fcc0ea44ba27"),
            null // new Proxy(Proxy.Type.HTTP, new InetSocketAddress("<proxy-host-if-used>", 8080))
        );
    }
    
    private static void downloadWebp(Path path, URI uri, Proxy proxy) throws Exception {
        HttpURLConnection connection = (HttpURLConnection) (proxy == null 
            ? uri.toURL().openConnection() : uri.toURL().openConnection(proxy));
        try {
            //connection.setConnectTimeout(30_000);
            //connection.setReadTimeout(30_000);
            connection.connect();
            try (
                ReadableByteChannel readableByteChannel = Channels.newChannel(connection.getInputStream());
                FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.WRITE)
            ) {
                int length = connection.getHeaderFieldInt("Content-Length", -1);
                System.out.println("Content-Length: " + length);
                while (length > 0) {
                    long written = fileChannel.transferFrom(readableByteChannel, 0, length /*Math.min(length, 2048)*/);
                    length -= written;
                    System.out.println("written: " + written);
                }
            }
        } finally {
            connection.disconnect();
        }
    }
    

    You will get both content-length and actually transferred bytes:

    Content-Length: 7542
    written: 7542
    

    As @user207421 mentioned in comments it's true, you need to use transferFrom in a loop.