How to delete a file after sending it in a web app?

19,710

Solution 1

Don't use @ResponseBody. Have Spring inject the HttpServletResponse and write directly to its OutputStream.

@RequestMapping("/getFile")
public void getFile(HttpServletResponse response) {
    String address = Services.createFile();
    File file = new File(address);
    response.setContentType("application/vnd.ms-excel");
    response.setHeader("Content-disposition", "attachment; filename=" + file.getName());

    OutputStream out = response.getOutputStream();
    FileInputStream in = new FileInputStream(file);

    // copy from in to out
    IOUtils.copy(in,out);

    out.close();
    in.close();
    file.delete();
}

I haven't added any exception handling. I leave that to you.

FileSystemResource is really just is a wrapper for FileInputStream that's used by Spring.

Or, if you want to be hardcore, you could make your own FileSystemResource implementation with its own getOutputStream() method that returns your own implementation of FileOutputStream that deletes the underlying file when you call close() on it.

Solution 2

So I decided to take Sotirious's suggestion for a "hardcore" way. It is pretty simple, but has one problem. If user of that class opens input stream once to check something and closes it, it will not be able to open it again since file is deleted on close. Spring does not seem to do that, but you will need to check after every version upgrade.

public class DeleteAfterReadeFileSystemResource extends FileSystemResource {
    public DeleteAfterReadeFileSystemResource(File file) {
        super(file);
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return new DeleteOnCloseFileInputStream(super.getFile());
    }

    private static final class DeleteOnCloseFileInputStream extends FileInputStream {

        private File file;
        DeleteOnCloseFileInputStream(File file) throws FileNotFoundException    {
            super(file);
            this.file = file;
        }

        @Override
        public void close() throws IOException {
            super.close();
            file.delete();
        }
    }
}

Solution 3

A minor adaption to this answer.

Using a InputStreamResource instead of FileSystemResource makes this a little shorter.

public class CleanupInputStreamResource extends InputStreamResource {
    public CleanupInputStreamResource(File file) throws FileNotFoundException {
        super(new FileInputStream(file) {
            @Override
            public void close() throws IOException {
                super.close();
                Files.delete(file.toPath());
            }
        });
    }
}

Solution 4

You can write Mag's solution with anonymous classes like this:

new FileSystemResource(file) {
    @Override
    public InputStream getInputStream() throws IOException {
        return new FileInputStream(file) {
            @Override
            public void close() throws IOException {
                super.close();
                Files.delete(file.toPath());
            }
        };
    }
}
Share:
19,710

Related videos on Youtube

ia.solano
Author by

ia.solano

Updated on September 15, 2022

Comments

  • ia.solano
    ia.solano over 1 year

    I have a web application. I am using java and spring. The application can create a file and send it to the browser, this is working fine. The way I do it is:

    I create the file in a Services class, and the method returns the address to the controller. The controller then sends the file, and it is downloaded correctly. The code for the controller method is this.

    @RequestMapping("/getFile")
    public @ResponseBody
    FileSystemResource getFile() {
    
        String address = Services.createFile();
        response.setContentType("application/vnd.ms-excel");
        return new FileSystemResource(new File (address));
    }
    

    The problem is that the file is saved in the server, and after many requests it will have a lot of files. I have to delete them manually. The question is: How can I delete this file after sending it? or Is there a way to send the file without saving it in the server?

  • Sotirios Delimanolis
    Sotirios Delimanolis over 10 years
    Inside a while loop, you read a byte[] from in and write it to out. Look for a Java IO tutorial.
  • rec
    rec over 6 years
    Better not close the response output stream.
  • Jacobs2000
    Jacobs2000 about 3 years
    This solution is problematic when the file is very large. IOUtils.copy(in,out) throws an OutOfMemoryException.