如何使用Oracle PL/SQL读取FTP或SFTP服务器上的.csv文件
如何用Oracle SQL/PLSQL读取FTP/SFTP上的CSV文件?
兄弟,你用UTL_TCP拿到那个SSH-2.0-OpenSSH_5.3的返回确实说明连接通了,但说实话,用UTL_TCP来搞FTP/SFTP实在太折腾了——这玩意儿是底层TCP工具,你得自己手动实现FTP的USER/PASS命令、SFTP的SSH握手这些协议细节,根本没必要!我给你捋捋更简单的方案:
一、处理普通FTP服务器的CSV文件
如果是普通FTP(非SFTP),直接用Oracle自带的UTL_FTP包就行,比UTL_TCP友好太多,不用自己拼协议命令。步骤大概是这样:
- 建立FTP连接
- 登录服务器
- 切换到文件所在目录
- 逐行读取或者下载文件到数据库目录
- 处理CSV内容(比如拆分字段插入表)
- 关闭连接
给你个实际可用的示例代码:
DECLARE l_conn UTL_FTP.connection; l_line VARCHAR2(4000); BEGIN -- 建立FTP连接,替换成你的服务器地址和端口 l_conn := UTL_FTP.open_connection('ftp.******.******.com', 21); -- 登录,替换成你的FTP用户名和密码 UTL_FTP.login(l_conn, 'your_ftp_username', 'your_ftp_password'); -- 切换到CSV文件所在的远程目录 UTL_FTP.cd(l_conn, '/path/to/your/csv/folder'); -- 切换到ASCII模式(适合文本类的CSV文件) UTL_FTP.ascii(l_conn); -- 逐行读取CSV文件(替换成你的文件名) LOOP BEGIN UTL_FTP.get_line(l_conn, l_line); -- 这里可以添加逻辑处理每一行,比如拆分CSV字段插入到表中 DBMS_OUTPUT.PUT_LINE('读取到行:' || l_line); EXCEPTION WHEN NO_DATA_FOUND THEN -- 没有更多行时退出循环 EXIT; END; END LOOP; -- 关闭连接 UTL_FTP.close_connection(l_conn); EXCEPTION WHEN OTHERS THEN -- 异常时确保连接关闭 IF UTL_FTP.is_open(l_conn) THEN UTL_FTP.close_connection(l_conn); END IF; RAISE; END; /
二、处理SFTP服务器的CSV文件
如果是SFTP(基于SSH的安全FTP),UTL_FTP就不管用了,因为SFTP走的是SSH协议,Oracle没有内置的SFTP包,给你两个实用方案:
方案1:用Java存储过程调用JSch库
Java有成熟的SSH/SFTP客户端库JSch,我们可以把它导入数据库,写个Java存储过程来处理SFTP下载,再用PLSQL调用:
第一步:创建Java源(需要先把JSch的jar包导入数据库)
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "SFTPReader" AS import com.jcraft.jsch.*; import java.io.*; public class SFTPReader { public static void downloadSFTPFile(String host, int port, String user, String pass, String remoteFilePath, String localFilePath) throws Exception { JSch jsch = new JSch(); // 建立SSH会话 Session session = jsch.getSession(user, host, port); session.setPassword(pass); // 关闭主机密钥检查(生产环境建议配置可信密钥) session.setConfig("StrictHostKeyChecking", "no"); session.connect(); // 打开SFTP通道 Channel channel = session.openChannel("sftp"); channel.connect(); ChannelSftp sftpChannel = (ChannelSftp) channel; // 下载远程文件到本地目录 OutputStream os = new FileOutputStream(localFilePath); sftpChannel.get(remoteFilePath, os); // 关闭资源 os.close(); sftpChannel.exit(); session.disconnect(); } } /
第二步:创建PLSQL包装器
CREATE OR REPLACE PROCEDURE SFTP_DOWNLOAD_FILE( p_host VARCHAR2, p_port NUMBER, p_user VARCHAR2, p_pass VARCHAR2, p_remote_file VARCHAR2, p_local_file VARCHAR2 ) AS LANGUAGE JAVA NAME 'SFTPReader.downloadSFTPFile(java.lang.String, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String)'; /
第三步:调用存储过程下载,再用外部表读取
BEGIN -- 替换成你的SFTP信息和文件路径 SFTP_DOWNLOAD_FILE( 'ftp.******.******.com', 22, -- SFTP默认端口是22,如果你连的是21端口,这里改成21 'your_sftp_username', 'your_sftp_password', '/path/to/your/data.csv', '/u01/oracle/local_data/data.csv' -- 数据库服务器上的本地目录,需要配置成Oracle的DIRECTORY对象 ); END; /
然后创建外部表读取本地的CSV文件:
-- 先创建目录对象(需要DBA权限) CREATE OR REPLACE DIRECTORY DATA_DIR AS '/u01/oracle/local_data'; GRANT READ, WRITE ON DIRECTORY DATA_DIR TO your_user; -- 创建外部表,字段对应你的CSV结构 CREATE TABLE csv_external_table ( column1 VARCHAR2(100), column2 NUMBER, column3 DATE, column4 VARCHAR2(200) ) ORGANIZATION EXTERNAL ( TYPE ORACLE_LOADER DEFAULT DIRECTORY DATA_DIR ACCESS PARAMETERS ( RECORDS DELIMITED BY NEWLINE FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' MISSING FIELD VALUES ARE NULL -- 如果有表头,可以加这句跳过第一行:SKIP 1 ) LOCATION ('data.csv') ) REJECT LIMIT UNLIMITED;
方案2:用OS工具结合外部表
如果数据库服务器能直接访问SFTP服务器,也可以写个shell脚本用sftp命令把文件下载到本地目录,然后用外部表读取——这种方式不用搞Java存储过程,适合批量处理场景。
三、关于你之前的UTL_TCP尝试
你连接21端口得到SSH的返回信息,这说明你连接的服务器其实是SFTP服务(可能对方把SFTP端口改成21了),因为普通FTP的返回应该是类似220 FTP Server ready的内容,而SSH的返回是SSH-2.0-OpenSSH_5.3,所以别再用UTL_TCP硬怼了,用上面的SFTP方案更靠谱。
内容的提问来源于stack exchange,提问作者Vijay
相关产品推荐
相关产品推荐

