随意心情
===========================================================
批量测试FlashFXP的站点文件
===========================================================

批量测试FlashFXP的站点文件

GzlLm@msn.com

一、起因

个人FTP站点资源太多,开始的时候整理比较简单,但是随着有些论坛的关闭,一些FTP的转型等原因,导致站点管理器里面的站点信息相对的混乱,特别是有很多密码不正确,或者ftp地址更改,端口更改等情况,如果想一一测试所有的站点,费时又费事,于是就考虑花半天的时间自己写个小program来解决这个问题。

二、计划

FlashFTP的站点文件为Sites.dat文件,所有的站点信息都记录在这个文件中,包括分组信息。sites.dat文件结构比较简单,用ultraedit直接打开的话,是看到一个文本文件转换成十六进制编辑模式就能看到一点不同了,一个站点名,包括其目录名都在一个"[]",例如目录abc下的子目录def下的站点sitename(以上信息部分摘录于互联网)。了解了sites.dat的结构,再需要考虑的是ip的转换,现在的ip地址的表现方式有几种,域名可以等同于ip地址,不过如果ip地址经过了如下方式的编码,程序在解析的时候就会出问题:

public String encodeIP(String ip) {

long ip1 = Long.parseLong(ip.split(".")[0]) * 256 * 256 * 256;

long ip2 = Long.parseLong(ip.split(".")[1]) * 256 * 256;

long ip3 = Long.parseLong(ip.split(".")[2]) * 256;

long ip4 = Long.parseLong(ip.split(".")[3]);

return Long.toString(ip1 + ip2 + ip3 + ip4);

}

这样编码的ip地址会变成全部数字的字符串,可以考虑使用:

public String decodeIP(String ip) {

long ip1 = Long.parseLong(ip) / 256 / 256 / 256;

long ip2 = (Long.parseLong(ip) - ip1 * 256 * 256 * 256) / 256 / 256;

long ip3 = (Long.parseLong(ip) - ip1 * 256 * 256 * 256 - ip2 * 256 * 256) / 256;

long ip4 = (Long.parseLong(ip) - ip1 * 256 * 256 * 256 - ip2 * 256

* 256 - ip3 * 256) % 256;

return ip1 + "." + ip2 + "." + ip3 + "." + ip4;

}

进行解析,不过有些地址在解析的时候会出现问题,例如以0开头的ip地址字符串等,根据以上情况,直接调用ping命令来获取ip地址,我觉得应该算是一个很简便的方法了,在这个问题上追求的不是速度,而是准确。

另外为了小程序维护分发的方便,不考虑使用第三方的FTP的包,而直接使用
sun.net.ftp.FtpClient;

sun.net.ftp.FtpLoginException;

sun.net.ftp.FtpProtocolException;

以上三个类

三、实现

1、备份原来的sites.dat文件,加上时间戳,避免文件备份被覆盖

File fbak = new File(Tester.SITE_FILENAME + "."

+ Calendar.getInstance().getTime().getTime() + ".bak");

2sites.dat文件的获取。遍历一边sites.dat文件,获取到站点信息包括获取到正确的ip地址,获取ip地址的方法如下:

public String getRealIp(String ip) {

String realip = ip;

Process process = null;

BufferedReader bufferedReader = null;

try {

process = Runtime.getRuntime().exec("ping " + ip);

bufferedReader = new BufferedReader(new InputStreamReader(process

.getInputStream()));

String linedata = null;

while ((linedata = bufferedReader.readLine()) != null) {

if (linedata.startsWith("Pinging")) {

realip = linedata.split(" ")[1];

break;

}

}

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

bufferedReader.close();

} catch (IOException e) {

e.printStackTrace();

}

bufferedReader = null;

process = null;

}

return realip;

}

3、站点名称有些麻烦,一个站点名,包括其目录名都在一个"[]"中例如目录abc下的子目录def下的站点sitename

String[] name=new String[]{"abc","def","sitename"}来表示

那么在sites.dat文件中应该写入的内容如下result

代码:

StringBuffer result = new StringBuffer();

result.append("[");

int len = name.length;

for (int j = 0; j < len - 1; j++) {

if (name[j] != null && !name[j].equals(""))

result.append((char) 0x7f + name[j] + (char) 0x1e + (char) 0x20);

}

result.append(name[len - 1] + "]");

还一个要注意的是站点的注释中

回车要用0x01来替换

我自己处理的时候没有在网上看到上面的信息,所以直接用了点傻的方法,直接读取全部的包括了分组信息的站点名,然后在构造站点信息数据的类中,再进一步的分解成为组名称和站点名称。

以下子为SiteDate的构造器:

public SiteData(String fullName) {

this.setFullName(fullName);

if (fullName.startsWith("[")) {// 这个site属于一个分组

int lastindex = fullName.lastIndexOf("");

String tempStr = fullName.substring(lastindex + 1);

this.setGroupName(fullName.substring(0, lastindex + 1)

+ tempStr.substring(0, tempStr.indexOf(" ") + 1));

this.setSiteName(getRealSiteName(tempStr.substring(tempStr

.indexOf(" ") + 1)));

} else {

this.setGroupName("[");

this.setSiteName(getRealSiteName(fullName.substring(fullName

.indexOf("[") + 1)));

}

}

public String getRealSiteName(String siteName) {

String siterealname = siteName;

if (siterealname.indexOf("|") >= 2

&& siterealname.indexOf("|") != siterealname.lastIndexOf("|")) {

siterealname = siteName.substring(0, siterealname.indexOf("|") - 2)

+ siteName.substring(siterealname.lastIndexOf("|") + 1);

}

return siterealname;

}

4、再就是对站点数据文件中的站点密码信息解密,采用了网友kanbol

* 经写了一个解码flashfxp密码的方法:

private static final char[] FlashFXP_Key = "yA36zA48dEhfrvghGRg57h5UlDv3"

.toCharArray();

public String decodePWD(String input) {

if (input.equals("") || input == null)

return "";

StringBuffer result = new StringBuffer();

char[] inputArr = input.toCharArray();

for (int i = 0; i < inputArr.length - 2; i = i + 2) {

String source = "" + inputArr[i + 2] + inputArr[i + 3];

String key = ""

+ Integer.toHexString((byte) (FlashFXP_Key[i / 2 % 28]));

String magic_number = "" + inputArr[i] + inputArr[i + 1];

int chr = (Integer.parseInt(source, 16) ^ Integer.parseInt(key, 16))

- Integer.parseInt(magic_number, 16);

if (chr < 0) {

chr = chr + 255;

}

result.append((char) chr);

}

return result.toString();

}

5、最后就是测试站点信息,并将反馈的结果修改原来的站点的文件名(这里需要注意,只能修改原来的站点名,不能修改组的名字,否则会将分组信息打乱)。测试的时候处理连接到服务器的各种异常是关键:

try {

fc = new FtpClient(hostname, port);

System.out.print("登录...");

fc.login(uid, pwd);

System.out.print("退出服务器...");

fc.sendServer("QUITrn");

System.out.println("n测试成功:" + sd.getFullName());

System.out.println();

} catch (FtpLoginException e) {

msg = "nFtpLoginException|" + hostname + "登录失败!请检查用户名或密码是否正确n";

System.out.println(msg);

retResult = 1;

// return false;

} catch (ConnectException e) {

msg = "nConnectException|" + hostname + "连接失败!找不到主机n";

System.out.println(msg);

retResult = 0;

} catch (SocketException e) {

msg = "nSocketException|" + hostname + "连接失败!网络连接失败n";

System.out.println(msg);

retResult = 4;

} catch (UnknownHostException e) {

msg = "nUnknownHostException|" + hostname + "解析成为IP地址失败!n";

System.out.println(msg);

retResult = 3;

// return false;

} catch (FtpProtocolException e) {

msg = "nFtpProtocolException|连接主机:" + hostname + "失败!请检查端口是否正确n";

System.out.println(msg);

retResult = 6;

// return false;

} catch (IOException e) {

e.printStackTrace();

msg = "nIOException|连接主机:" + hostname + "失败!请检查端口是否正确n";

System.out.println(msg);

retResult = 5;

// return false;

} catch (SecurityException e) {

msg = "nSecurityException|无权限与主机:" + hostname + "连接!请检查是否有访问权限n";

System.out.println(msg);

retResult = 2;

// return false;

} finally {

fc = null;

}

6、根据以上的几种异常和反馈结果,来重新命名站点文件,并写入新的站点文件中。

switch (returnint) {

case -1:

break;

case 0:

preStr = "00|ConnectFalse|";

break;

case 1:

preStr = "01|PasswordError|";

break;

case 2:

preStr = "02|NoPrivileg|";

break;

case 3:

preStr = "03|UnknownHost|";

break;

case 4:

preStr = "04|SocketError|";

break;

case 5:

preStr = "05|IOException|";

break;

case 6:

preStr = "06|FtpProtocolError|";

break;

default:

preStr = "*|UnknowError|";

break;

}

四、扩展

已经登录FTP,想获取文件啥的,就看个人的考虑了,原先曾经考虑做一个所有ftp的文件列表,存放到本地,在需要的时候可以进行本地文件查询(以前就出现过我在一个ftp上看到一个文件,当时没有想到下载,不过等我需要的时候,却怎么也找不到那个ftp,如果上天再给我一个重来一次的机会,我会download,如果非要给下载的文件大小加一个限制,我希望是10000G……),不过这样就超出我这个小程序的预期目的了,所以就不多此一举了,够用就行。


gzllm 发表于:2005.12.22 13:25 ::分类: ( 生活 ) ::阅读:(1708次) :: 评论 (1)
re: 批量测试FlashFXP的站点文件 [回复]

好东东啊
终于找到相关贴了
要是有程序下就更好了
你的BLog偶看了看 挺好的
支持一下 有时间还会来滴!

淼淼 评论于: 2006.09.17 15:30

发表评论
标题

在此添加评论
表情符号: smile laughing tongue angry crying sad wassat wink

称呼

邮箱地址(可选)

个人主页(可选)




自我介绍
切换风格
新闻聚合
博客日历
文章归档...
最新发表...
博客统计...
Blog信息
网站链接...