利用Java实现FTP大文件批量上传下载(一)

 2024-02-18 00:01:47  阅读 0

1:使用HTTP协议上传似乎更适合web编程的方便; 上传小于1M的文件比使用FTP协议上传文件稍快。 但对于批量和大文件传输它可能无能为力。 当然,它也有它的优点。 例如,与FTP不同,FTP服务必须在服务器端启动。

2:使用FTP协议上传大于1M的文件比HTTP要快。 文件越大,上传速度比HTTP上传速度快几倍。 并使用java编写程序; FTP 比 HTTP 更方便。

笔者曾经用VB写过控件来上传、下载批处理文件,功能也很强大。 但由于CAB文件或OCX没有专门的数字签名,需要进行繁琐的客户端设置,如设置安全站点、降低客户端的安全级别等,因此一些解决方案被放弃。

同时考虑到需要在客户端对文件进行数字签名和数据加密,我们决定采用该方法来实现。 。 在文件上传之前,客户端可以获取本地密钥信息并完成对上传文件的加密和签名处理。 虽然采用需要在客户端安装JRE运行环境,给客户端的管理和使用带来一些不便,但是相对于如此大量的文件和文件的安全性来说,这或许也算是一个比较小的代价。

总结一下,运行环境是:

FTP服务器:Serv-U,专业的FTP服务器程序。 网上有现成的软件下载。 当然,读者也可以编写一个服务器端FTP文件接收程序来进行说明。 如果没有特殊的需求或者功能,Serv-U应该能够满足我们一般的上传下载需求;

客户端:Java,当年让Java流行起来的技术,据说可以与微软平起平坐。 当然,现在Java已经出来了,是替代品吗?

应用环境:互联网,最终目标。

2、Java FTP客户端库的选择

让我们想象一个情况——我们想编写一个纯Java应用程序,从远程计算机上运行的FTP服务器上传和下载文件; 我们还希望获得远程下载文件的基本文件信息,例如文件名。 、数据或文件大小等。

尽管从头开始编写 FTP 协议处理程序是可能的,而且可能很有趣,但这项工作很困难、漫长,而且有潜在的危险。 因为我们不想花费时间、精力或金钱自己编写这样的处理程序,所以我们转向现有的可重用组件。 而且很多库存都在网上。

找到一个适合我们需求的优秀Java FTP客户端库并不像看起来那么简单。 相反,这是一项非常痛苦和复杂的任务。 首先,寻找FTP客户端库需要一些时间。 其次,当我们找到所有现有的库后,我们应该选择哪一个呢? 每个库都适合不同的需求。 这些库在性能方面并不等同,而且它们的设计也有根本的不同。 每个类库都有自己的特点,并使用不同的术语来描述它们。 因此,评估和比较 FTP 客户端库是一项艰巨的任务。

使用可重用组件是一种值得的方法,但在这种情况下,一开始往往会令人畏惧。 后来我可能会感到有点羞愧:选择了一个好的FTP库之后,后续的工作就会很简单,遵循简单的规则就可以了。 目前有很多公共的、免费的ftp客户端库,比如J-ftp等,其他的还有很多。 如下表所示,表中并未全部列出。 如果读者有更好的客户端FTP库,请进一步添加。

FTP客户端类库名称

评论

J-ftp

.ftp。

工作.ftp..

.ftp。

jshop.jnet。

.ftp。

文件传输协议

com.cqs.ftp.FTP

FTP

ftp.dhl.ftp

org..io.ftp。

在本文中,作者使用J-ftp。 这是一个开源且非常强大的客户端 FTP 库。 作者非常喜欢,推荐给各位读者。 算了,免费获得它的广告。

3. 基本功能

1. 登录

使用FTP进行文件传输实际上仍然在使用。 用于沟通。 下面的代码只是类中的登录方法。 当然,在下面的代码中,为了节省篇幅,也为了把一些原理解释清楚,作者去掉了一些不必要的代码,比如日志代码。 完整代码请参考J-ftp的源码或者作者的示例源码。 这同样适用于以下代码示例:

int 登录( , )

这。 = ;

这。 = ;

整数 = ;

jcon = new (主机, 端口);

如果(jcon。())

在 = jcon.();

if(() == null)//) == null)

确定=假;

= ;

如果(!()。())//))

如果(())//))

别的

确定=假;

= ;

别的

如果(消息)

Log.debug("FTP 不可用!");

确定=假;

= ;

如果(好的)

=真;

();

();

[]=新[6];

if(().("OS/2") >= 0)

=“列表”;

如果(列表。(“”))

//只获取第一个项目(它知道第一个是

//FTP列表)

= .(.);

//*** 如果未找到文件,则将其设置为

如果(==空)

列表 = ;

s = new (., 列表);

别的

列表=[0];

如果(列表==空)

列表 = ;

if(().("MVS") >= 0)

列表=“列表”;

//***

(这);

莉兹(这个);

别的

(这个,新的()。());

;

在这个登录方法中,有一个类,它负责建立套接字。 同时这个类是一个独立的线程。 这样做的好处是,为了应对界面的变化,将网络连接等工作都放在单独的线程中处理,有利于界面的友好性。 下面是该类的run方法。 当然这个线程的启动是在类的构造函数中启动的。

无效运行()

尝试

s = new(主机,端口);

= s.();

//if(时间 > 0) s.(时间);

输出=新(新(s.(),

.));

in = new (新(s.()),

.);

确定=真;

// }

抓住(前)

前任。();

Log.out(": 由于 (" + 主机 +

“:”+端口+“)”);

确定=假;

尝试

if((s != null) && !s.())

s.close();

如果(输出!=空)

关闭();

if(in != null)

附寄();

捕获(ex2)

ex2.();

Log.out(": 还有更多要关闭和");

=真;

这里解释一下,在这个run方法中,这个类实现了客户端套接字(也可以称为“套接字”),套接字是两台机器之间的通信端点。 套接字的实际工作是由该类的实例执行的。 应用程序可以通过更改创建套接字实现的套接字工厂来配置自身,以创建适合本地防火墙的套接字。 具体说明请参考JDK5的API说明,最好是中文的。 呵呵。

2.上传下载

文件上传可以分为多线程和单线程。 在单线程的情况下,比较简单,但是在多线程的情况下,需要处理的事情就更多了,需要更加小心。 下面介绍如何上传。 已经考虑了两种不同的类型:单线程和多线程。

int(文件,)

如果(.ing() &&

(!.ading()))

Log.out(" 这是新的。");

t;

如果(!=空)

t = 新(主机、端口、()、()、

文件, , , 。,

, , , crlf);

别的

t = 新(主机、端口、()、()、

文件, , , 。,

, , crlf);

=t;

;

别的

if(.ading())

Log.out("是。");

别的

Log.out("是。");

( == 空) ? (文件):(文件,);

在多线程的情况下,有一个单独的类。 当然,在多线程的情况下,这个类必须是一个单独的线程。 与 类似,它的线程也是在构造方法中启动的。 在其 run 方法中,读取并传输文件。

无效运行()

if(.().get(文件) == null)

.(文件,这个);

否则如果(!暂停)

Log.debug(" in : " + 文件);

工作=假;

统计数据 = 2;

;

= 假;

同时(暂停)

尝试

.sleep(100);

如果(!=空)

for(int i = 0; i < .size(); i++)

(() .(i)).(文件,

,

-1);

如果(!工作)

如果(!=空)

for(int i = 0; i < .size(); i++)

(() .(i)).(文件,

,

-1);

抓住(前)

=真;

while((.() >= .()) &&

(.() > 0) && 工作)

尝试

统计数据 = 4;

.sleep(400);

if(! && ( != null))

for(int i = 0; i < .size(); i++)

(() .(i)).(文件,

,

-1);

别的

休息;

抓住(前)

前任。();

如果(!工作)

如果(!=空)

for(int i = 0; i < .size(); i++)

(() .(i)).(文件,

,

-1);

。(文件);

统计数据 = 3;

;

=真;

尝试

.sleep(.se);

抓住(前)

con = new (主机, 端口, , crlf);

con.();

con.rs();

int = con.login(用户, 通行证);

如果(==。)

文件 f = 新文件();

con.(f.());

如果(类型。())

如果(!=空)

= con.(文件, );

别的

= con.(文件);

别的

= con.(文件,这个.);

如果(!暂停)

。(文件);

至于下载过程,因为是上传的逆过程,所以和上传的方法和写法很相似。 由于篇幅原因,代码就不列出来了,但是思路和思路是完全一样的。 欢迎读者参考源代码。

4.进度

可以想象,如果上传或下载过程中没有提示,用户无法判断任务是否完成或者任务是否死掉。 这往往会因上传或下载时间过长而误导用户。 因此,进度条非常重要且实用。

进度条的实现其实很简单。 就是在程序中开启两个线程。 第一个线程用于动态更改界面上进度条的值,而第二个线程在上传或下载过程中创建循环。 在这个循环中,每次读取一定量的数据,例如8192字节。 然后传递完这个数据后,调用第一个线程中的方法来更新界面进度条的值。

在上传或下载过程中(参见上一节该类的run方法),可以查看con.(file, )方法。 代码如下,

int(文件,,中)

=真;

Log.out("ftp : " + this);

统计数据;

if((in == null) && 新文件(文件).())

=真;

= 0;

= 文件;

= .;

=真;

统计=(文件);

= 假;

//.out.( + ":" + );

(,

。 +“:”+,-1);

(这);

(这);

别的

= .PUT;

stat = (文件, , 中);

尝试

.sleep(100);

抓住(前)

(这);

(这);

尝试

.sleep(500);

抓住(前)

统计;

该方法负责上传一定数量字节的内容。 其实就是一种调用方法,这里就不列出来了。 请参考源代码。 字节数据传输完毕后,通过调用()方法来调用主线程中的()方法。 方法。 实际上代码如下:

空白 () {

int = (int) (((浮点) / (浮点) ) * );

.();

// .out.("============================================== ======“+”);

.( / 1024L + “/” + / 1024L

+“kB”);

= (int) (((浮点) / (浮点) ) * );

.( / 1024L + “/” + / 1024L

+“kB”);

.();

();

上面使用了两个进度条。 第一进度条指示当前文件的上传或下载进度,第二进度条指示所有文件的下载或上传进度。 同时,为了使进度条的移动或变化更加明显,通过.(10000)和.(10000)将进度条的最大值设置为10000,而不是我们通常设置的100。 笔者觉得这样看起来比较好,因为有时候上传或者下载的时候可能会因为网络的原因变化比较小。 如果设置为100,变化不是特别明显。

标签: 上传 线程 进度

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码