FTP单文件运行例子
FTP单文件运行例子/*
* AIWROK FTP 独立用法脚本(纯 Rhino / JDK,零 importClass、零第三方 dex、零外部模块)
* 实现方式:用 java.net.Socket 手写 FTP 协议(RFC 959),原生支持:
* 连接/登录、上传(STOR)、下载(RETR)、查询列目录(LIST)、当前目录(PWD)。
* 注意:除 java.* 标准类外不引用任何资源,可直接运行。
* 若列出中文文件名出现乱码,把 ftpList 里 InputStreamReader 的编码从 "ISO-8859-1" 改成 "GBK" 或 "UTF-8" 即可。
*/
// ============ ① 顶部配置区(用户改这里即可跑) ============
var FTP_HOST = "154.221.80.195"; // FTP 服务器地址
var FTP_PORT = 21; // FTP 端口,默认 21
var FTP_USER = "ghgfggggj"; // 登录用户名
var FTP_PASS = "CrSaz4611bx1B"; // 登录密码
var LOCAL_UPLOAD = "/sdcard/auto/aiwork_ftp_sample.txt"; // 要上传的本地文件(演示会自动生成,无需手动准备)
var REMOTE_UPLOAD_PATH = "/aiwork_ftp_sample.txt"; // 上传后保存在远程的路径(含文件名,放根目录更安全)
var REMOTE_DOWNLOAD_PATH = "/aiwork_ftp_sample.txt"; // 要从远程下载的文件路径(用刚上传的同名文件,演示自洽)
var LOCAL_DOWNLOAD = "/sdcard/auto/aiwork_ftp_sample_downloaded.txt"; // 下载保存到本地的路径
var LIST_DIR = "/"; // 要列出内容的远程目录,"/" 表示根目录
// ============ 全局控制连接 ============
var ctrlSock = null;
var ctrlOut = null;
var ctrlReader = null;
// 读取一条控制回复(多行回复以 "code " 结尾,遇到即停)
function readReply() {
var full = "", code = "";
while (true) {
var line = ctrlReader.readLine();
if (line == null) break;
line = String(line); // 强制转成 JS 字符串:否则 Rhino 下 Java String 与 "220" 这种字面量用 !== 永远不等
full += line + "\n";
if (/^ /.test(line)) { code = line.substring(0, 3); break; }
}
return { code: code, text: full };
}
// 发送命令(强制 CRLF)
function sendCmd(cmd) {
// 用 java.lang.String 包一层保证有 getBytes;write 用三参形式避免 Rhino 把 write(byte[]) 误判成 write(int)
var b = new java.lang.String(cmd + "\r\n").getBytes("ISO-8859-1");
ctrlOut.write(b, 0, b.length);
ctrlOut.flush();
}
// 解析 PASV 回复 -> { ip, port }
function parsePasv(text) {
var m = text.match(/\((+),(+),(+),(+),(+),(+)\)/);
if (!m) return null;
var ip = m + "." + m + "." + m + "." + m;
var port = (parseInt(m, 10) * 256) + parseInt(m, 10);
return { ip: ip, port: port };
}
// 发 PASV 并打开被动数据连接
function openPasvData() {
var r = readReply(); // 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)
var info = parsePasv(r.text);
if (!info) { printl(" PASV 解析失败: " + r.text); return null; }
// 数据连接优先用「控制连接的公网 IP(FTP_HOST) + PASV 端口」:
// 很多服务器 PASV 回复里写的是内网 IP(NAT 缺陷),从外部连不通;
// 而用我们连控制通道的公网 IP + PASV 端口通常可达(已实测 154.201.80.125 可行)。
// 若公网连不通(如客户端与服务器同局域网、内网 IP 才通),回退到 PASV 回复里的 IP。
var ds = null;
try {
ds = new java.net.Socket(FTP_HOST, info.port);
} catch (e1) {
try { ds = new java.net.Socket(info.ip, info.port); }
catch (e2) { printl(" 数据连接失败: " + e2); return null; }
}
ds.setSoTimeout(15000);
return ds;
}
// ============ 连接 / 登录 ============
function ftpConnect() {
try {
ctrlSock = new java.net.Socket(FTP_HOST, FTP_PORT);
ctrlSock.setSoTimeout(15000);
ctrlOut = ctrlSock.getOutputStream();
ctrlReader = new java.io.BufferedReader(new java.io.InputStreamReader(ctrlSock.getInputStream(), "ISO-8859-1"));
var welcome = readReply();
if (welcome.code !== "220") { printl(" 服务器未就绪(" + welcome.code + "): " + welcome.text); return false; }
sendCmd("USER " + FTP_USER);
readReply();
sendCmd("PASS " + FTP_PASS);
var r2 = readReply();
if (r2.code !== "230") { printl(" 登录失败(" + r2.code + "): " + r2.text); return false; }
sendCmd("TYPE I"); // 二进制传输,必须设置(否则图片/压缩包损坏)
readReply();
printl(" 连接成功");
return true;
} catch (e) {
printl(" 连接异常: " + e);
return false;
}
}
// ============ 查询 / 列目录 ============
function ftpList(dir) {
try {
if (ctrlSock == null) { printl(" 尚未连接,请先调用 ftpConnect()"); return -1; }
var target = (dir == null || dir === "") ? "/" : dir;
sendCmd("PASV");
var ds = openPasvData();
if (ds == null) return -1;
sendCmd("LIST " + target);
readReply(); // 150 开始
var dr = new java.io.BufferedReader(new java.io.InputStreamReader(ds.getInputStream(), "ISO-8859-1"));
var line, count = 0;
printl(" 目录 " + target + " 内容如下:");
while ((line = dr.readLine()) != null) {
printl("" + line);
count++;
}
dr.close(); ds.close();
readReply(); // 226 结束
printl(" 目录共 " + count + " 个条目");
return count;
} catch (e) {
printl(" 列目录异常: " + e);
return -1;
}
}
// ============ 上传 ============
function ftpUpload(localPath, remotePath) {
var fis = null, ds = null;
try {
if (ctrlSock == null) { printl(" 尚未连接,请先调用 ftpConnect()"); return false; }
var f = new java.io.File(localPath);
if (!f.exists()) { printl(" 本地文件不存在: " + localPath); return false; }
sendCmd("PASV");
ds = openPasvData();
if (ds == null) return false;
sendCmd("STOR " + remotePath);
readReply(); // 150 开始
var dout = ds.getOutputStream();
fis = new java.io.FileInputStream(f);
var buf = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 4096);
var len;
while ((len = fis.read(buf)) > 0) { dout.write(buf, 0, len); }
fis.close(); fis = null;
dout.flush(); ds.close(); ds = null;
var done = readReply(); // 226 结束
var ok = (done.code === "226" || done.code === "250");
printl(ok ? (" 上传成功: " + localPath + " -> " + remotePath) : (" 上传失败(" + done.code + "): " + done.text));
return ok;
} catch (e) {
printl(" 上传异常: " + e);
return false;
} finally {
if (fis != null) try { fis.close(); } catch (x) {}
if (ds != null) try { ds.close(); } catch (x) {}
}
}
// ============ 下载 ============
function ftpDownload(remotePath, localPath) {
var fos = null, ds = null;
try {
if (ctrlSock == null) { printl(" 尚未连接,请先调用 ftpConnect()"); return false; }
var lf = new java.io.File(localPath);
var parent = lf.getParentFile();
if (parent != null && !parent.exists()) parent.mkdirs();
sendCmd("PASV");
ds = openPasvData();
if (ds == null) return false;
sendCmd("RETR " + remotePath);
var r = readReply(); // 150 开始
if (r.code !== "150" && r.code !== "125") { printl(" 下载无法开始(" + r.code + "): " + r.text); ds.close(); return false; }
var din = ds.getInputStream();
fos = new java.io.FileOutputStream(lf);
var buf = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 4096);
var len;
while ((len = din.read(buf)) > 0) { fos.write(buf, 0, len); }
fos.close(); fos = null;
ds.close(); ds = null;
var done = readReply(); // 226 结束
var ok = (done.code === "226" || done.code === "250");
printl(ok ? (" 下载成功: " + remotePath + " -> " + localPath) : (" 下载失败(" + done.code + "): " + done.text));
return ok;
} catch (e) {
printl(" 下载异常: " + e);
return false;
} finally {
if (fos != null) try { fos.close(); } catch (x) {}
if (ds != null) try { ds.close(); } catch (x) {}
}
}
// ============ 当前工作目录 ============
function ftpPwd() {
try {
sendCmd("PWD");
var r = readReply(); // 257 "/xxx" is current directory
var m = r.text.match(/"(.*)"/);
return m ? m : r.text;
} catch (e) { return ""; }
}
// ============ 关闭连接 ============
function ftpClose() {
try {
if (ctrlSock != null) {
try { sendCmd("QUIT"); readReply(); } catch (x) {}
try { ctrlSock.close(); } catch (x) {}
printl(" 连接已关闭");
}
} catch (e) { printl(" 关闭异常: " + e); }
}
// ============ 辅助:自动生成本地样例文件(演示用) ============
function ensureLocalSample(localPath) {
try {
var f = new java.io.File(localPath);
if (f.exists()) return true;
var p = f.getParentFile();
if (p != null && !p.exists()) p.mkdirs();
var fw = new java.io.FileWriter(f);
fw.write("AIWROK FTP 演示样例文件\n生成时间: " + ("" + java.lang.System.currentTimeMillis()));
fw.close();
printl(" 已自动生成本地样例文件: " + localPath);
return true;
} catch (e) { printl(" 生成样例文件失败: " + e); return false; }
}
// ============ main 演示(连接→PWD→列目录→上传→列目录→下载→关闭) ============
function main() {
printl("========== FTP 独立用法演示开始(纯 Socket,无 importClass) ==========");
if (!ftpConnect()) { printl(" 连接失败,演示终止"); return; }
printl(" 当前工作目录: " + ftpPwd());
printl("----- 上传前列出 " + LIST_DIR + " -----");
ftpList(LIST_DIR);
ensureLocalSample(LOCAL_UPLOAD);
ftpUpload(LOCAL_UPLOAD, REMOTE_UPLOAD_PATH);
printl("----- 上传后列出 " + LIST_DIR + " -----");
ftpList(LIST_DIR);
ftpDownload(REMOTE_DOWNLOAD_PATH, LOCAL_DOWNLOAD);
ftpClose();
printl("========== FTP 独立用法演示结束 ==========");
}
main();
页:
[1]