YYPOST群发软件 发表于 5 天前

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]
查看完整版本: FTP单文件运行例子