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

2019-03-19 04:21发布

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?

3条回答
来,给爷笑一个
2楼-- · 2019-03-19 04:53

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();
        }
    }
}
查看更多
爷的心禁止访问
3楼-- · 2019-03-19 04:56

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());
            }
        });
    }
}
查看更多
狗以群分
4楼-- · 2019-03-19 05:08

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.

查看更多
登录 后发表回答