Скопируйте удаленный файл в sftp с помощью Spring Integration

Мне нужно скопировать / продублировать удаленный файл на сервере Sftp, а также переименовать при копировании, я прочитал здесь, что копирование удаленного файла в Sftp не поддерживается, поэтому у меня был единственный доступный вариант: GET < / strong> файл в локальный, а затем снова PUT в Sftp и удаление локального файла, я успешно достиг своей цели, но проблема в том, что журнал печатается из org.springframework.core.log.LogAccessor: Я понятия не имею, откуда он приходящий.

Код, помогающий копировать удаленный файл:

 @Bean
public IntegrationFlow copyRemoteFile() {
    return IntegrationFlows.from("integration.channel.copy")
            .handle(Sftp.outboundGateway(sftpSessionFactory(),
                    AbstractRemoteFileOutboundGateway.Command.GET,
                    "headers[" + COPY_SOURCE_PATH.value + "]+'/'+" +
                            "headers[" + COPY_SOURCE_FILENAME.value + "]")
                    .autoCreateLocalDirectory(true)
                    .fileExistsMode(FileExistsMode.REPLACE)
                    .localDirectory(new File(localPath)))
            .log(LoggingHandler.Level.INFO, "SftpCopyService")
            .handle(Sftp.outboundGateway(sftpSessionFactory(),
                    AbstractRemoteFileOutboundGateway.Command.PUT,
                    "payload")
                    .remoteDirectoryExpression("headers[" + COPY_DEST_PATH.value + "]")
                    .fileNameGenerator(n -> (String)n.getHeaders().get(COPY_DEST_FILENAME.value))
                    .fileExistsMode(FileExistsMode.REPLACE))
            .log(LoggingHandler.Level.INFO, "SftpCopyService")
            .handle((p, h) -> {
                try {
                      return Files.deleteIfExists(
                            Paths.get(localPath + File.separator + h.get(COPY_SOURCE_FILENAME.value)));
                } catch (IOException e) {
                    e.printStackTrace();
                    return false;
                }
            })
            .get();

Вот журнал.

2021-02-16 18:10:22,577 WARN  [http-nio-9090-exec-1] org.springframework.core.log.LogAccessor: Failed to delete C:\Users\DELL\Desktop\GetTest\Spring Integration.txt
2021-02-16 18:10:22,784 INFO  [http-nio-9090-exec-1] org.springframework.core.log.LogAccessor: GenericMessage [payload=C:\Users\DELL\Desktop\GetTest\Spring Integration.txt, headers={file_remoteHostPort=X.X.X.X:22, replyChannel=nullChannel, sourceFileName=Spring Integration.txt, file_remoteDirectory=/uploads/, destFileName=Spring Integrat.txt, destPath=uploads/dest, id=5105bdd1-8180-1185-3661-2ed708e07ab9, sourcePath=/uploads, file_remoteFile=Spring Integration.txt, timestamp=1613479222779}]
2021-02-16 18:10:23,011 INFO  [http-nio-9090-exec-1] org.springframework.core.log.LogAccessor: GenericMessage [payload=uploads/dest/Spring Integrat.txt, headers={file_remoteHostPort=X.X.X.X:22, replyChannel=nullChannel, sourceFileName=Spring Integration.txt, file_remoteDirectory=/uploads/, destFileName=Spring Integrat.txt, destPath=uploads/dest, id=1bf83b0f-3b24-66bd-ffbf-2a9018b499fb, sourcePath=/uploads, file_remoteFile=Spring Integration.txt, timestamp=1613479223011}]

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

Также есть лучший способ скопировать удаленный файл на другой путь внутри sftp

ИЗМЕНИТЬ

Как вы и предположили, я пробовал SftpRemoteFileTemplate.execute() метод для копирования файлов в sftp, но когда вызывается метод session.write(InputStream stream,String path), элемент управления метода никогда не возвращает, он сохраняет элемент управления навсегда

Я пробовал отладку, контроль теряется, когда выполнение достигает здесь:

for(_ackcount = this.seq - startid; _ackcount > ackcount && this.checkStatus((int[])null, header); ++ackcount) {
            }

Этот код находится внутри _put метода ChannelSftp.class

Вот пример кода, который я пытаюсь

 public boolean copy() {
   return remoteFileTemplate.execute(session -> {
        if (!session.exists("uploads/Spring Integration.txt")){
            return false;
        }
        if (!session.exists("uploads/dest")){
            session.mkdir("uploads/dest");
        }
        InputStream inputStream = session.readRaw("uploads/Spring Integration.txt");
        session.write(inputStream, "uploads/dest/spring.txt");
        session.finalizeRaw();
        return true;
    });
}

Не могли бы вы указать, какую ошибку я здесь делаю?


person abdur rehman    schedule 16.02.2021    source источник


Ответы (1)


Вместо того, чтобы писать весь поток через локальную копию файла, я бы предложил изучить один активатор службы для SftpRemoteFileTemplate.execute(SessionCallback<F, T>). Предоставленный SftpSession в этом обратном вызове может использоваться для InputStream readRaw() и write(InputStream inputStream, String destination). В конце концов, вы должны позвонить finalizeRaw().

Вопрос LogAccessor не ясен. Какую версию Spring Integration вы используете? Но вы отменяете версию Spring Core?

Я думаю, мы можем улучшить это сообщение WARN и не вызывать File.delete(), если оно не exists().

Не стесняйтесь делать такой вклад!

ОБНОВЛЕНИЕ

Тест JUnit для демонстрации того, как выполнить копирование на SFTP-сервере:

@Test
public void testSftpCopy() throws Exception {
    this.template.execute(session -> {
        PipedInputStream in = new PipedInputStream();
        PipedOutputStream out = new PipedOutputStream(in);
        session.read("sftpSource/sftpSource2.txt", out);
        session.write(in, "sftpTarget/sftpTarget2.txt");
        return null;
    });

    Session<?> session = this.sessionFactory.getSession();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    FileCopyUtils.copy(session.readRaw("sftpTarget/sftpTarget2.txt"), baos);
    assertThat(session.finalizeRaw()).isTrue();
    assertThat(new String(baos.toByteArray())).isEqualTo("source2");

    baos = new ByteArrayOutputStream();
    FileCopyUtils.copy(session.readRaw("sftpSource/sftpSource2.txt"), baos);
    assertThat(session.finalizeRaw()).isTrue();
    assertThat(new String(baos.toByteArray())).isEqualTo("source2");

    session.close();
}
person Artem Bilan    schedule 17.02.2021
comment
Нет, я не отменяю версию Spring Core. Я использую Spring boot 2.4.1 - person abdur rehman; 18.02.2021
comment
Я попробовал метод SftpRemoteFileTemplate.execute(SessionCallback<F, T>) для выполнения своей задачи, но, похоже, он не работает. Я отредактировал свой вопрос, чтобы предоставить более подробную информацию. - person abdur rehman; 18.02.2021
comment
Пожалуйста, найдите ОБНОВЛЕНИЕ в моем ответе. Я думаю, ChannelSftp просто не может справиться с несколькими одновременно открытыми потоками ... - person Artem Bilan; 18.02.2021