SFTP 出站閘道器
SFTP 出站閘道器提供了一組有限的命令,允許您與遠端 SFTP 伺服器進行互動
-
ls(列出檔案) -
nlst(列出檔名) -
get(檢索檔案) -
mget(檢索多個檔案) -
rm(刪除檔案集) -
mv(移動並重命名檔案) -
put(傳送檔案) -
mput(傳送多個檔案)
使用 ls 命令
ls 列出遠端檔案並支援以下選項:
-
-1: 檢索檔名列表。預設是檢索FileInfo物件列表 -
-a: 包含所有檔案(包括以 '.' 開頭的檔案) -
-f: 不對列表進行排序 -
-dirs: 包含目錄(預設排除) -
-links: 包含符號連結(預設排除) -
-R: 遞迴列出遠端目錄
此外,檔名過濾方式與 inbound-channel-adapter 相同。
ls 操作產生的訊息負載是檔名列表或 FileInfo 物件列表(取決於您是否使用 -1 選項)。這些物件提供修改時間、許可權等資訊。
file_remoteDirectory 頭部提供了 ls 命令操作的遠端目錄。
當使用遞迴選項(-R)時,fileName 包含任何子目錄元素,並表示檔案的相對路徑(相對於遠端目錄)。如果您使用 -dirs 選項,每個遞迴目錄也會作為列表中的一個元素返回。在這種情況下,我們建議您不要使用 -1 選項,因為您將無法區分檔案和目錄,而使用 FileInfo 物件時可以做到這一點。
如果列出的遠端路徑以 / 符號開頭,SFTP 會將其視為絕對路徑;否則,視為當前使用者主目錄中的相對路徑。
使用 nlst 命令
版本 5 引入了對 nlst 命令的支援。
nlst 列出遠端檔名,並且只支援一個選項。
-
-f: 不對列表進行排序
nlst 操作產生的訊息載荷是檔名列表。
file_remoteDirectory 頭儲存了 nlst 命令作用的遠端目錄。
SFTP 協議不提供列出名稱的功能。此命令等同於帶有 -1 選項的 ls 命令,此處新增是為了方便。
使用 get 命令
get 檢索遠端檔案並支援以下選項
-
-P: 保留遠端檔案的時間戳。 -
-stream: 以流形式檢索遠端檔案。 -
-D: 成功傳輸後刪除遠端檔案。如果傳輸被忽略(因為FileExistsMode是IGNORE且本地檔案已存在),則不刪除遠端檔案。
file_remoteDirectory 頭儲存遠端目錄,file_remoteFile 頭儲存檔名。
get 操作產生的訊息負載是一個 File 物件,表示檢索到的檔案。如果您使用 -stream 選項,負載是 InputStream 而不是 File。對於文字檔案,常見用例是將此操作與 檔案拆分器 或 流轉換器 結合使用。以流形式消費遠端檔案時,您有責任在流消費後關閉 Session。為方便起見,Session 包含在 closeableResource 頭中,並且 IntegrationMessageHeaderAccessor 提供了便捷方法
Closeable closeable = new IntegrationMessageHeaderAccessor(message).getCloseableResource();
if (closeable != null) {
closeable.close();
}
以下示例顯示如何以流形式使用檔案:
<int-sftp:outbound-gateway session-factory="ftpSessionFactory"
request-channel="inboundGetStream"
command="get"
command-options="-stream"
expression="payload"
remote-directory="ftpTarget"
reply-channel="stream" />
<int-file:splitter input-channel="stream" output-channel="lines" />
如果您在自定義元件中消費輸入流,則必須關閉 Session。您可以在自定義程式碼中執行此操作,也可以將訊息的副本路由到 service-activator 並使用 SpEL,示例如下 |
<int:service-activator input-channel="closeSession"
expression="headers['closeableResource'].close()" />
使用 mget 命令
mget 根據模式檢索多個遠端檔案,並支援以下選項:
-
-P: 保留遠端檔案的時間戳。 -
-R: 遞迴檢索整個目錄樹。 -
-x: 如果沒有檔案匹配模式則丟擲異常(否則返回空列表)。 -
-D: 成功傳輸後刪除每個遠端檔案。如果傳輸被忽略,遠端檔案不會被刪除,因為FileExistsMode是IGNORE且本地檔案已存在。
mget 操作產生的訊息載荷是一個 List<File> 物件(即一個 File 物件列表,每個物件表示一個檢索到的檔案)。
從 5.0 版本開始,如果 FileExistsMode 為 IGNORE,則輸出訊息的負載不再包含由於檔案已存在而未獲取的檔案。以前,陣列包含所有檔案,包括那些已經存在的檔案。 |
您使用的表示式應生成以 * 結尾的結果,例如 myfiles/* 獲取 myfiles 下的完整樹。
從 5.0 版本開始,您可以將遞迴 MGET 與 FileExistsMode.REPLACE_IF_MODIFIED 模式結合使用,以定期在本地同步整個遠端目錄樹。無論 -P(保留時間戳)選項如何,此模式都會將本地檔案的最後修改時間戳設定為遠端檔案的時間戳。
|
使用遞迴(
-R)時的注意事項模式被忽略,假定為 如果您過濾一個子目錄,則不會對該子目錄執行額外的遍歷。 不允許使用 通常,您會在 |
持久檔案列表過濾器現在有一個布林屬性 forRecursion。將此屬性設定為 true,還會設定 alwaysAcceptDirectories,這意味著出站閘道器上的遞迴操作(ls 和 mget)現在每次都會遍歷完整的目錄樹。這是為了解決目錄樹深處的變化未被檢測到的問題。此外,forRecursion=true 會導致檔案的完整路徑用作元資料儲存鍵;這解決了如果具有相同名稱的檔案在不同目錄中多次出現時過濾器無法正常工作的問題。重要提示:這意味著在頂層目錄下的檔案中,持久元資料儲存中的現有鍵將找不到。因此,此屬性預設為 false;這可能會在未來的版本中更改。
從 5.0 版本開始,您可以透過將 alwaysAcceptDirectorties 設定為 true 來配置 SftpSimplePatternFileListFilter 和 SftpRegexPatternFileListFilter 以始終透過目錄。這樣做允許簡單模式的遞迴,示例如下
<bean id="starDotTxtFilter"
class="org.springframework.integration.sftp.filters.SftpSimplePatternFileListFilter">
<constructor-arg value="*.txt" />
<property name="alwaysAcceptDirectories" value="true" />
</bean>
<bean id="dotStarDotTxtFilter"
class="org.springframework.integration.sftp.filters.SftpRegexPatternFileListFilter">
<constructor-arg value="^.*\.txt$" />
<property name="alwaysAcceptDirectories" value="true" />
</bean>
您可以透過使用閘道器上的 filter 屬性提供其中一個過濾器。
另請參閱 出站閘道器部分成功(mget 和 mput)。
使用 put 命令
put 將檔案傳送到遠端伺服器。訊息的負載可以是 java.io.File、byte[] 或 String。remote-filename-generator(或表示式)用於命名遠端檔案。其他可用屬性包括 remote-directory、temporary-remote-directory 及其 *-expression 等效項:use-temporary-file-name 和 auto-create-directory。有關更多資訊,請參閱 模式文件。
put 操作產生的訊息負載是一個 String,其中包含傳輸後伺服器上檔案的完整路徑。
4.3 版本引入了 chmod 屬性,該屬性在上傳後更改遠端檔案許可權。您可以使用傳統的 Unix 八進位制格式,例如,600 僅允許檔案所有者讀寫。使用 Java 配置介面卡時,可以使用 setChmod(0600)。
使用 mput 命令
mput 將多個檔案傳送到伺服器並支援以下選項
-
-R: 遞迴 — 傳送目錄和子目錄中所有檔案(可能已過濾)
訊息負載必須是表示本地目錄的 java.io.File(或 String)。自 5.1 版本以來,也支援 File 或 String 的集合。
支援與 put 命令 相同的屬性。此外,您可以使用 mput-pattern、mput-regex、mput-filter 或 mput-filter-expression 之一來過濾本地目錄中的檔案。只要子目錄本身透過過濾器,該過濾器就與遞迴配合使用。未透過過濾器的子目錄不會被遞迴。
mput 操作產生的訊息負載是 List<String> 物件(即,傳輸產生的遠端檔案路徑列表)。
另請參閱 出站閘道器部分成功(mget 和 mput)。
4.3 版本引入了 chmod 屬性,該屬性允許您在上傳後更改遠端檔案許可權。您可以使用傳統的 Unix 八進位制格式,例如,600 僅允許檔案所有者讀寫。使用 Java 配置介面卡時,可以使用 setChmodOctal("600") 或 setChmod(0600)。
使用 rm 命令
rm 命令沒有選項。
如果移除操作成功,則生成的訊息負載為 Boolean.TRUE。否則,訊息負載為 Boolean.FALSE。file_remoteDirectory 頭儲存遠端目錄,file_remoteFile 頭儲存檔名。
使用 mv 命令
mv 命令沒有選項。
expression 屬性定義“源”路徑,rename-expression 屬性定義“目標”路徑。預設情況下,rename-expression 是 headers['file_renameTo']。此表示式不得評估為 null 或空 String。如有必要,將建立所需的任何遠端目錄。結果訊息的負載為 Boolean.TRUE。file_remoteDirectory 頭儲存原始遠端目錄,file_remoteFile 頭儲存檔名。file_renameTo 頭儲存新路徑。
從 5.5.6 版本開始,remoteDirectoryExpression 可以方便地用於 mv 命令。如果“源”檔案不是完整檔案路徑,則 remoteDirectoryExpression 的結果將用作遠端目錄。對於“目標”檔案也是如此,例如,如果任務只是重新命名某個目錄中的遠端檔案。
附加命令資訊
get 和 mget 命令支援 local-filename-generator-expression 屬性。它定義了一個 SpEL 表示式,用於在傳輸期間生成本地檔名。評估上下文的根物件是請求訊息。remoteFileName 變數也可用。它對於 mget 特別有用(例如:local-filename-generator-expression="#remoteFileName.toUpperCase() + headers.foo")。
get 和 mget 命令支援 local-directory-expression 屬性。它定義了一個 SpEL 表示式,用於在傳輸期間生成本地目錄名。評估上下文的根物件是請求訊息。remoteDirectory 變數也可用。它對於 mget 特別有用,例如 local-directory-expression="'/tmp/local/' + #remoteDirectory.toUpperCase() + headers.myheader"。此屬性與 local-directory 屬性互斥。
對於所有命令,閘道器的“expression”屬性儲存命令作用的路徑。對於 mget 命令,表示式可能評估為 *,表示檢索所有檔案,somedirectory/*,以及其他以 * 結尾的值。
以下示例顯示了配置為 ls 命令的閘道器:
<int-ftp:outbound-gateway id="gateway1"
session-factory="ftpSessionFactory"
request-channel="inbound1"
command="ls"
command-options="-1"
expression="payload"
reply-channel="toSplitter"/>
傳送到 toSplitter 通道的訊息負載是一個 String 物件列表,每個物件都包含一個檔名。如果您省略 command-options="-1",則負載將是 FileInfo 物件列表。您可以將選項作為空格分隔的列表提供,例如,command-options="-1 -dirs -links"。
從 4.2 版本開始,GET、MGET、PUT 和 MPUT 命令支援 FileExistsMode 屬性(使用名稱空間支援時為 mode)。這會影響本地檔案存在(GET 和 MGET)或遠端檔案存在(PUT 和 MPUT)時的行為。支援的模式有 REPLACE、APPEND、FAIL 和 IGNORE。為了向後相容,PUT 和 MPUT 操作的預設模式是 REPLACE。對於 GET 和 MGET 操作,預設模式是 FAIL。
使用 Java 配置
以下 Spring Boot 應用程式展示瞭如何使用 Java 配置出站閘道器的示例
@SpringBootApplication
public class SftpJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(SftpJavaApplication.class)
.web(false)
.run(args);
}
@Bean
@ServiceActivator(inputChannel = "sftpChannel")
public MessageHandler handler() {
return new SftpOutboundGateway(ftpSessionFactory(), "ls", "'my_remote_dir/'");
}
}
使用 Java DSL 進行配置
以下 Spring Boot 應用程式顯示瞭如何使用 Java DSL 配置出站閘道器的示例:
@SpringBootApplication
public class SftpJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(SftpJavaApplication.class)
.web(false)
.run(args);
}
@Bean
public SessionFactory<SftpClient.DirEntry> sftpSessionFactory() {
DefaultSftpSessionFactory sf = new DefaultSftpSessionFactory();
sf.setHost("localhost");
sf.setPort(port);
sf.setUsername("foo");
sf.setPassword("foo");
factory.setTestSession(true);
return new CachingSessionFactory<>(sf);
}
@Bean
public QueueChannelSpec remoteFileOutputChannel() {
return MessageChannels.queue();
}
@Bean
public IntegrationFlow sftpMGetFlow() {
return IntegrationFlow.from("sftpMgetInputChannel")
.handle(Sftp.outboundGateway(sftpSessionFactory(),
AbstractRemoteFileOutboundGateway.Command.MGET, "payload")
.options(AbstractRemoteFileOutboundGateway.Option.RECURSIVE)
.regexFileNameFilter("(subSftpSource|.*1.txt)")
.localDirectoryExpression("'myDir/' + #remoteDirectory")
.localFilenameExpression("#remoteFileName.replaceFirst('sftpSource', 'localTarget')"))
.channel("remoteFileOutputChannel")
.get();
}
}
出站閘道器部分成功(mget 和 mput)
在對多個檔案執行操作時(使用 mget 和 mput),在一個或多個檔案傳輸後可能會發生異常。在這種情況下(從 4.2 版本開始),會丟擲 PartialSuccessException。除了通常的 MessagingException 屬性(failedMessage 和 cause)外,此異常還有兩個附加屬性
-
partialResults: 成功的傳輸結果。 -
derivedInput: 從請求訊息生成的檔案列表(例如用於mput的本地待傳輸檔案)。
這些屬性讓您可以確定哪些檔案成功傳輸,哪些沒有。
在遞迴 mput 的情況下,PartialSuccessException 可能包含巢狀的 PartialSuccessException 例項。
考慮以下目錄結構:
root/
|- file1.txt
|- subdir/
| - file2.txt
| - file3.txt
|- zoo.txt
如果在 file3.txt 上發生異常,則閘道器丟擲的 PartialSuccessException 的 derivedInput 為 file1.txt、subdir 和 zoo.txt,partialResults 為 file1.txt。其 cause 是另一個 PartialSuccessException,其 derivedInput 為 file2.txt 和 file3.txt,partialResults 為 file2.txt。