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
開關)。這些物件提供諸如修改時間、權限和其他資訊。
ls
命令作用的遠端目錄在 file_remoteDirectory
標頭中提供。
當使用遞迴選項 (-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
物件的 List
,每個物件代表一個檢索到的檔案)。
從版本 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 開始,您可以設定 SftpSimplePatternFileListFilter
和 SftpRegexPatternFileListFilter
,方法是將 alwaysAcceptDirectorties
設定為 true
,以始終傳遞目錄。這樣做允許簡單模式的遞迴,如下列範例所示
<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
屬性來提供其中一個篩選器。
使用 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>
物件(即傳輸產生的遠端檔案路徑的 List
)。
版本 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
具有 file1.txt
、subdir
和 zoo.txt
的 derivedInput
,以及 file1.txt
的 partialResults
。其 cause
是另一個 PartialSuccessException
,其 derivedInput
為 file2.txt
和 file3.txt
,而 partialResults
為 file2.txt
。