Daniel Kaplan
Daniel Kaplan

Reputation: 67300

Does IOUtils.copy block until writing is finished?

Here's my situation: I'm using IOUtils to copy a file. The next thing I do is send a JSON message to another program to say, "You can download the copy". The problem is about 25% of the time the other program gets an error saying "Received unexpected EOF downloading artifact".

Every time this error occurs, if I try again manually, the error doesn't occur. My theory is that IOUtils.copy doesn't block and the OS is still writing the file to the FS while the other program tries to download it. Is there a way to force IOUtils.copy or other functionally equivalent code to block until the OS has finished writing the file? Or is my theory incorrect? Here's the code I'm using:

private boolean archiveArtifact(String archivePath, String deployId, Artifact artifact) {
    InputStream inputStream = null;
    FileOutputStream fileOutputStream = null;
    boolean successful = true;

    try {
        File archiveDir = new File(archivePath);
        File deployDir = new File(archiveDir, deployId);

        if (!deployDir.exists()) {
            deployDir.mkdirs();
        }

        URLConnection connection = new URL(artifact.getJenkinsUrl()).openConnection();
        inputStream = connection.getInputStream();
        File output = new File(deployDir, artifact.getFileName());
        fileOutputStream = new FileOutputStream(output);
        IOUtils.copy(inputStream, fileOutputStream);
    } catch (IOException e) {
        successful = false;
        logger.error(e.getMessage(), e);
    } finally {
        try {
            if (fileOutputStream != null) {
                fileOutputStream.close();
            }
        } catch (IOException e) {
            successful = false;
            logger.error(e.getMessage(), e);
        }

        try {
            if (inputStream != null) {
                inputStream.close();
            }
        } catch (IOException e) {
            successful = false;
            logger.error(e.getMessage(), e);
        }
    }

    return successful;
}

It might be worth noting that I'm copying this to a NFS. Keep in mind I don't really know anything about NFS. This is CentOS release 5.9 (Final).

Upvotes: 4

Views: 3436

Answers (1)

samlewis
samlewis

Reputation: 4048

Your current code only ensures that the file content is passed to the operating system for writing; it does not guarantee that it is actually written to a the disk.

To be certain that the file is actually written to disk you can call sync() on the FileDescriptor:

fileOutputStream.flush();
fileOutputStream.getFD().sync();

Upvotes: 4

Related Questions