Posted on 2007-10-22 09:45
詩特林 閱讀(7925)
評論(4) 編輯 收藏 所屬分類:
Socket
用Java實現FTP批量大文件上傳下載(三)
用Java實現FTP批量大文件上傳下載(一)
五、斷點續傳
對于熟用QQ的程序員,QQ的斷點續傳功能應該是印象很深刻的。因為它很實用也很方面。因此,在我們的上傳下載過程中,很實現了斷點續傳的功能。
其實斷點續傳的原理很簡單,就在上傳的過程中,先去服務上進行查找,是否存在此文件,如果存在些文件,則比較服務器上文件的大小與本地文件的大小,如果服務器上的文件比本地的要小,則認為此文件上傳過程中應該可以進行斷點續傳。
在實現的過程中,RandomAccessFile類變得很有用。此類的實例支持對隨機存取文件的讀取和寫入。隨機存取文件的行為類似存儲在文件系統中的一個大型字節數組。存在指向該隱含數組的光標或索引,稱為文件指針;輸入操作從文件指針開始讀取字節,并隨著對字節的讀取而前移此文件指針。如果隨機存取文件以讀取/寫入模式創建,則輸出操作也可用;輸出操作從文件指針開始寫入字節,并隨著對字節的寫入而前移此文件指針。寫入隱含數組的當前末尾之后的輸出操作導致該數組擴展。該文件指針可以通過 getFilePointer 方法讀取,并通過 seek 方法進行設置。
RandomAccessFile類的skipBytes方法嘗試跳過輸入的 n 個字節以丟棄跳過的字節。如果從服務器上查得待上傳文件的大小n,則采用skipBytes方法可以跳過這n個字節,從而開始從新的地方開始進行斷點續傳。具體的方法說明可以參見JDK5的API說明。
可以在net.sf.jftp.net. DataConnection類的run方法中,可以看出上傳下載中斷點續傳的實現,代碼如下:
public void run()

{
try

{
newLine = con.getCRLF();

if(Settings.getFtpPasvMode())

{
try

{
sock = new Socket(host, port);
sock.setSoTimeout(Settings.getSocketTimeout());
}
catch(Exception ex)

{
ok = false;
debug("Can't open Socket on port " + port);
}
}
else

{
//Log.debug("trying new server socket: "+port);
try

{
ssock = new ServerSocket(port);
}
catch(Exception ex)

{
ok = false;
Log.debug("Can't open ServerSocket on port " + port);
}
}
}
catch(Exception ex)

{
debug(ex.toString());
}

isThere = true;

boolean ok = true;

RandomAccessFile fOut = null;
BufferedOutputStream bOut = null;
RandomAccessFile fIn = null;

try

{
if(!Settings.getFtpPasvMode())

{
int retry = 0;

while((retry++ < 5) && (sock == null))

{
try

{
ssock.setSoTimeout(Settings.connectionTimeout);
sock = ssock.accept();
}
catch(IOException e)

{
sock = null;
debug("Got IOException while trying to open a socket!");

if(retry == 5)

{
debug("Connection failed, tried 5 times - maybe try a higher timeout in Settings.java
");
}

finished = true;

throw e;
}
finally

{
ssock.close();
}

debug("Attempt timed out, retrying
");
}
}

if(ok)

{
byte[] buf = new byte[Settings.bufferSize];
start = System.currentTimeMillis();

int buflen = 0;

//---------------download,下載----------------------
if(type.equals(GET) || type.equals(GETDIR))

{
if(!justStream)

{
try

{
if(resume)

{
File f = new File(file);
fOut = new RandomAccessFile(file, "rw");
fOut.skipBytes((int) f.length());
buflen = (int) f.length();
}
else

{
if(localfile == null)

{
localfile = file;
}

File f2 = new File(Settings.appHomeDir);
f2.mkdirs();

File f = new File(localfile);

if(f.exists())

{
f.delete();
}

bOut = new BufferedOutputStream(new FileOutputStream(localfile),
Settings.bufferSize);
}
}
catch(Exception ex)

{
debug("Can't create outputfile: " + file);
ok = false;
ex.printStackTrace();
}
}

//---------------upload,上傳----------------------
if(type.equals(PUT) || type.equals(PUTDIR))

{
if(in == null)

{
try

{
fIn = new RandomAccessFile(file, "r");
if(resume)

{
fIn.skipBytes(skiplen);
}
//fIn = new BufferedInputStream(new FileInputStream(file));
}
catch(Exception ex)

{
debug("Can't open inputfile: " + " (" + ex + ")");
ok = false;
}
}
if(ok)

{
try

{
out = new BufferedOutputStream(sock.getOutputStream());
}
catch(Exception ex)

{
ok = false;
debug("Can't get OutputStream");
}
if(ok)

{
try

{
int len = skiplen;
char b;
while(true)

{
int read;
if(in != null)

{
read = in.read(buf);
}
else

{
read = fIn.read(buf);
}
len += read;
//System.out.println(file + " " + type+ " " + len + " " + read);
if(read == -1)

{
break;
}
if(newLine != null)

{
byte[] buf2 = modifyPut(buf, read);
out.write(buf2, 0, buf2.length);
}
else

{
out.write(buf, 0, read);
}
con.fireProgressUpdate(file, type, len);
if(time())

{
// Log.debugSize(len, false, false, file);
}
if(read == StreamTokenizer.TT_EOF)

{
break;
}
}
out.flush();
//Log.debugSize(len, false, true, file);
}
catch(IOException ex)

{
ok = false;
debug("Error: Data connection closed.");
con.fireProgressUpdate(file, FAILED, -1);
ex.printStackTrace();
}
}
}
}
}
}
catch(IOException ex)

{
Log.debug("Can't connect socket to ServerSocket");
ex.printStackTrace();
}
finally

{
try

{
if(out != null)

{
out.flush();
out.close();
}
}
catch(Exception ex)

{
ex.printStackTrace();
}
try

{
if(bOut != null)

{
bOut.flush();
bOut.close();
}
}
catch(Exception ex)

{
ex.printStackTrace();
}
try

{
if(fOut != null)

{
fOut.close();
}
}
catch(Exception ex)

{
ex.printStackTrace();
}
try

{
if(in != null && !justStream)

{
in.close();
}
if(fIn != null)

{
fIn.close();
}
}
catch(Exception ex)

{
ex.printStackTrace();
}
}
try

{
sock.close();
}
catch(Exception ex)

{
debug(ex.toString());
}
if(!Settings.getFtpPasvMode())

{
try

{
ssock.close();
}
catch(Exception ex)

{
debug(ex.toString());
}
}
finished = true;
if(ok)

{
con.fireProgressUpdate(file, FINISHED, -1);
}
else

{
con.fireProgressUpdate(file, FAILED, -1);
}
}

待續
......