Как скопировать / переименовать файл и вернуть его, не изменяя существующий файл?

#java #file-io

#java #file-io

Вопрос:

У меня есть generic.exe файл, который не содержит в себе никаких сведений о пользователях. У меня также есть REST API, который принимает идентификатор пользователя и возвращает файл клиенту.

Теперь, что мы хотим реализовать в нашем проекте, так это то, что когда кто-то обращается к REST API, мы хотим использовать это generic.exe и переименуйте его в manager_userId.exe и верни обратно это » .manager_userId.exe «.

Здесь следует отметить, что:

  1. The generic.exe файл вообще не должен быть изменен / удален
  2. Когда 2 пользователя (UserA и UserB) одновременно обращаются к одному и тому же API, они должны получить свою собственную копию manager_userA.exe и manager_userB.exe

Код, который я написал

 @RequestMapping(value = "/downloadExecutable", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON, produces = {MediaType.APPLICATION_OCTET_STREAM})
@ResponseBody
public Response downloadExecutable(@RequestBody DownloadExecutableRequest downloadExecutableRequest,
    HttpServletRequest request, HttpServletResponse response) {
    File file = downloadExecutable(downloadExecutableRequest, request, response,
            getUserID(request), osDetails);
    return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
            .header("Content-Disposition", "attachment;filename="   file.getName()).build();
}

public File downloadExecutable(DownloadExecutableRequest downloadExecutableRequest, HttpServletRequest request,
            HttpServletResponse response, String userId, String osDetails) {
        File file = null;
        String path = "/home/genericCopy/generic.exe";
        synchronized (this) {
            BufferedWriter fileWriter = null;
            try {
             File source = null;
             source = new File(path);
             Path destination = Paths.get("/tmp/");
             Files.copy(source, destination.toFile());
             fileWriter = new BufferedWriter(new FileWriter(destination.getFileName().toString() "_" userId));
                 file = new File(destination.getFileName().toString());
            } catch (IOException e) {
            } finally {
                if (fileWriter != null) {
                        fileWriter.close();
                }
            }
                        
        }
        return file;
    }
 

Код работает, но он создает временный файл, затем переименовывает его, а затем возвращает обратно, но он будет продолжать создавать копии файла для каждого запроса.
Есть ли какой-нибудь более разумный способ, которым я могу добиться, чтобы не создавать такие временные копии пользовательских файлов, а также обрабатывать сценарий, когда 2 пользователя одновременно обращаются к API?

Комментарии:

1. Зачем вы вообще копируете исходный файл? Просто установите расположение содержимого на имя, под которым вы хотите его загрузить, и верните файл шаблона.

2. Боковой комментарий: Вы действительно требуете, чтобы ваши пользователи загружали и выполняли динамически сгенерированный исполняемый файл? Понимаете ли вы угрозу безопасности для систем пользователей?

Ответ №1:

Имя файла, который загружается пользователем, не имеет никакого отношения к имени файла на диске.

Вы можете просто указать любое имя файла в заголовке, и пользователь увидит имя.

В частности, вы бы просто установили имя файла, которое вы хотите, чтобы пользователь видел в Content-Disposition заголовке, и всегда загружали один и тот же exe-файл с диска.

Что-то вроде этого:

 return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
        .header("Content-Disposition", "attachment;filename=executable_"   getUserID(request)   ".exe";
 

Вам не нужно выполнять какое-либо копирование в downloadExecutable функции.

Ответ №2:

Вам не нужно создавать копию generic.exe файла, чтобы вернуть его с измененным именем. Вы можете использовать правильно параметризованный Content-Disposition заголовок, чтобы он каждый раз возвращал один и тот же файл с именем файла, указанным пользователем.

Здесь вы можете найти пример:

 @RestController
public class DemoController {

    @GetMapping(value = "/file", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    @ResponseBody
    public ResponseEntity downloadExecutable(@RequestParam("userId") String userId) throws IOException {
        byte[] file = Files.readAllBytes(Paths.get("/home/genericCopy/generic.exe"));

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=generic_"   userId   ".exe")
                .contentLength(file.length)
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(file);
    }
}
 

и результат выполнения этого метода:

измененный файл_файла_файла