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

2 上传下载

文件的上传可以分成多线程及单线程,在单线程情况下比较简单,而在多线程的情况下,要处理的事情要多点,同时也要小心很多。下面是net.sf.jftp.net.FtpConnection的上传handleUpload方法。已经考虑了单线程及多线程两种不同的类型。

public   int  handleUpload(String file, String realName)
    
{
        
if(Settings.getEnableMultiThreading() &&
               (
!Settings.getNoUploadMultiThreading()))
        
{
            Log.out(
"spawning new thread for this upload.");

            FtpTransfer t;

            
if(realName != null)
            
{
                t 
= new FtpTransfer(host, port, getLocalPath(), getCachedPWD(),
                                    file, username, password, Transfer.UPLOAD,
                                    handler, listeners, realName, crlf);
            }

            
else
            
{
                t 
= new FtpTransfer(host, port, getLocalPath(), getCachedPWD(),
                                    file, username, password, Transfer.UPLOAD,
                                    handler, listeners, crlf);
            }


            lastTransfer 
= t;

            
return NEW_TRANSFER_SPAWNED;
        }

        
else
        
{
            
if(Settings.getNoUploadMultiThreading())
            
{
                Log.out(
"upload multithreading is disabled.");
            }

            
else
            
{
                Log.out(
"multithreading is completely disabled.");
            }


            
return (realName == null? upload(file) : upload(file, realName);
        }

}


 

在多线程的情况下,有一个单独的类net.sf.jftp.net .FtpTransfer,当然,多线程情况下,此类肯定是一个单独的线程了。与JConnection相似,其线程的启动也是在构造方法中启动。而在它的run方法中,进行文件的读取及传输。

public   void  run()
    
{
        
if(handler.getConnections().get(file) == null)
        
{
            handler.addConnection(file, 
this);
        }

        
else if(!pause)
        
{
            Log.debug(
"Transfer already in progress: " + file);
            work 
= false;
            stat 
= 2;

            
return;
        }


        
boolean hasPaused = false;

        
while(pause)
        
{
            
try
            
{
                runner.sleep(
100);

                
if(listeners != null)
                
{
                    
for(int i = 0; i < listeners.size(); i++)
                    
{
                        ((ConnectionListener) listeners.elementAt(i)).updateProgress(file,
                                                                                     PAUSED,
                                                                                     
-1);
                    }

                }


                
if(!work)
                
{
                    
if(listeners != null)
                    
{
                        
for(int i = 0; i < listeners.size(); i++)
                        
{
                            ((ConnectionListener) listeners.elementAt(i)).updateProgress(file,
                                                                                         REMOVED,
                                                                                         
-1);
                        }

                    }

                }

            }

            
catch(Exception ex)
            
{
            }


            hasPaused 
= true;
        }


        
while((handler.getConnectionSize() >= Settings.getMaxConnections()) &&
                  (handler.getConnectionSize() 
> 0&& work)
        
{
            
try
            
{
                stat 
= 4;
                runner.sleep(
400);

                
if(!hasPaused && (listeners != null))
                
{
                    
for(int i = 0; i < listeners.size(); i++)
                    
{
                        ((ConnectionListener) listeners.elementAt(i)).updateProgress(file,
                                                                                     QUEUED,
                                                                                     
-1);
                    }

                }

                
else
                
{
                    
break;
                }

            }

            
catch(Exception ex)
            
{
                ex.printStackTrace();
            }

        }


        
if(!work)
        
{
            
if(listeners != null)
            
{
                
for(int i = 0; i < listeners.size(); i++)
                
{
                    ((ConnectionListener) listeners.elementAt(i)).updateProgress(file,
                                                                                 REMOVED,
                                                                                 
-1);
                }

            }


            handler.removeConnection(file);
            stat 
= 3;

            
return;
        }


        started 
= true;

        
try
        
{
            runner.sleep(Settings.ftpTransferThreadPause);
        }

        
catch(Exception ex)
        
{
        }


        con 
= new FtpConnection(host, port, remotePath, crlf);

        con.setConnectionHandler(handler);
        con.setConnectionListeners(listeners);

        
int status = con.login(user, pass);

        
if(status == FtpConnection.LOGIN_OK)
        
{
            File f 
= new File(localPath);
            con.setLocalPath(f.getAbsolutePath());

            
if(type.equals(UPLOAD))
            
{
                
if(newName != null)
                
{
                    transferStatus 
= con.upload(file, newName);
                }

                
else
                
{
                    transferStatus 
= con.upload(file);
                }

            }

            
else
            
{
                transferStatus 
= con.download(file,this.newName);
            }

        }


        
if(!pause)
        
{
            handler.removeConnection(file);
        }

    }



 

至于下载的过程,因为它是上传的逆过程,与上传的方法及写法大同小异,在些出于篇幅的考虑,并没有将代码列出,但其思想及思路完全一样。请读者参考源代码。

 

  进度条

 

可以想象,如果在上传或是下载的过程中,没有任何的提示,用户根本没法判断任务是否完成或是任务是否死了,常常由于上传时间或下载时间过长而误导用户。因此,进度条就显得非常的重要与实用。

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

而上传或下载的过程中(见上一节的FtpTransfer类的run方法),可以查看,con.upload(file, newName)方法,代码如下所示,

     public   int  upload(String file, String realName, InputStream in)
    
{
        hasUploaded 
= true;
        Log.out(
"ftp upload started: " + this);

        
int stat;

        
if((in == null&& new File(file).isDirectory())
        
{
            shortProgress 
= true;
            fileCount 
= 0;
            baseFile 
= file;
            dataType 
= DataConnection.PUTDIR;
            isDirUpload 
= true;

            stat 
= uploadDir(file);

            shortProgress 
= false;

            
//System.out.println(fileCount + ":" + baseFile);
            fireProgressUpdate(baseFile,
                               DataConnection.DFINISHED 
+ ":" + fileCount, -1);

            fireActionFinished(
this);
            fireDirectoryUpdate(
this);
        }

        
else
        
{
            dataType 
= DataConnection.PUT;
            stat 
= rawUpload(file, realName, in);

            
try
            
{
                Thread.sleep(
100);
            }

            
catch(Exception ex)
            
{
            }


            fireActionFinished(
this);
            fireDirectoryUpdate(
this);
        }


        
try
        
{
            Thread.sleep(
500);
        }

        
catch(Exception ex)
        
{
        }


        
return stat;
    }


 

此方法进行负责上传一定字节数量的内容,其实就是调用rawUpload方法,这里没列出,请参考源代码,而当传完此字节数据后,通过调用fireActionFinished()方法来调用主线程中的updateProgressBar()。其实代码如下:

     protected   void  updateProgressBar()  {
        
int percent = (int) (((float) lFileCompleteSize / (float) lFileSize) * 10000F);
        pbFile.setValue(percent);
        
// System.out.println("================================================="+percent);
        pbFile.setString(lFileCompleteSize / 1024L + "/" + lFileSize / 1024L
                
+ " kB");
        percent 
= (int) (((float) lTotalCompleteSize / (float) lTotalSize) * 10000F);
        pbTotal.setString(lTotalCompleteSize 
/ 1024L + "/" + lTotalSize / 1024L
                
+ " kB");
        pbTotal.setValue(percent);
        repaint();
    }

 

上面用了两个进度条,第一个进度条表示当前文件的上传或下载进度,第二个进度条表示所有文件下载或上传的进度。同时,为了产生进度条的移动或变化进度幅度比较明显,通过pbFile.setMaximum(10000)pbTotal.setMaximum(10000)将进度条的最大值设置成10000,而不是平时我们所设置的100。笔者认为这样比较好看,因为有的时候上传或下载的时候由于网络原因,可能变化比较小。若设置成100则变化不是特别明显。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值