用java实现ftp的多线程下载 请问如何用java实现ftp的多线程下载,实现原理是什么?有代码最好 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 1:字节流结构:每次发送12+1024个字节其中,前七个字节字节表示命令第七到第十二个字节表示后面1024字节中的有效字节的长度例如一帧中前12个字节的内容为"UPFILEN00012"表示要上传文件名,文件名的长度是12。那么程序就在后面的1024个字节中去12个字节,在把它转换为字符串,作为要上传的文件名。2:命令结构Server端:DISCONN:断开连接LSFILES:发送当前目录文件列表ENDFILE:上传一个文件的结束标记UPFILEN:表示要上传一个新的文件,并且此包中包含了文件名UPDATAS:表示本包是要上传的数据DNFILEN:表示要下载的文件名,服务器要执行向客户端传输文件的操作Client端:DISCONN:断开连接LSFILES:接收服务器当前目录文件列表ENDFILE:下载一个文件的结束标记DNDATAS:表示本包是要下载的数据3:文件结构FtpServer:ftp软件的服务器端,目前在端口2121监听,支持多线程,文件的上传,下载,列表。FtpClient:ftp软件的客户端,默认连接本机的服务器端,在端口2121,支持文件的上传,下载,列表。FtpClientUI:ftp软件的客户端的用户界面,完全采用Swing技术,手工编写,没有用JB自动生成。PublicFunc:提供一些公共的静态方法例如将给定的String对象分装成要发送的帧。将数字格式化成长度为五位的String类型对象。package cn.edu.bit.software.ftptrans;import java.io.*;import java.net.*;import java.util.Vector;import java.util.logging.*;public class FtpServer{ //客户端socket对象 private ServerSocket m_servSocket; //ftp服务器的端口号 private int SERVER_PORT; //ftp服务器所允许的最大连接数 private int MAX_CONN; //连入的客户端处理对象管理器 private Vector vecClient; //设定一个log日志对象 private Logger mylog; private ConsoleHandler handler; String strServHome; public FtpServer(int servPort, int maxConn) { SERVER_PORT = servPort; MAX_CONN = maxConn; strServHome = "c:\\"; vecClient = new Vector(); /*------------初始化log------------*/ try { handler = new ConsoleHandler(); handler.setLevel(Level.ALL); mylog = Logger.getLogger("FtpServer"); mylog.addHandler(handler); mylog.setLevel(Level.ALL); } catch (SecurityException e) { mylog.warning("在设置程序日志级别时出现异常"); mylog.warning(e.getMessage()); } /*--------------初始化服务器,端口2121----------------------*/ try { m_servSocket = new ServerSocket(SERVER_PORT, MAX_CONN); while (true) { mylog.finest("FtpServer开始在端口2121监听"); Socket clientSocket = m_servSocket.accept(); vecClient.add(clientSocket); mylog.info("#" + vecClient.size() + "号客户端连入"); new TransHandler(this, clientSocket, vecClient.size()).start(); } } catch (IOException e) { mylog.warning("在初始化FtpServ时出现错误"); mylog.warning(e.getMessage()); } } public void deleteClient(TransHandler handler) { try { vecClient.remove(handler); vecClient.setSize(vecClient.size() - 1); mylog.info("第#" + handler.iClientNum + "号客户端断开了与服务器的连接!"); } catch (Exception e) { mylog.warning("在删除第#" + handler.iClientNum + "号客户端时出现异常"); mylog.warning(e.getMessage()); } } public static void main(String[] args) { new FtpServer(2121, 50); }} /** * 当有客户端连入时,处理客户端请求的类 * @author findfrog * @version 1.0 */class TransHandler extends Thread{ //服务器句柄,用于最后销毁TransHandler对象时用 FtpServer main = null; //客户端的socket private Socket m_clientSocket = null; //日志对象 private Logger mylog; //要上传的文件路径 private String strUpFilePath = null; //要下载的文件路径 private String strDnFilePath = null; //本客户端在的序号 int iClientNum = -1; //缓冲字节数据的大小 private int ibufferlength; //缓冲字节数组 byte[] inputBytes; //从客户端传来的指令 String strClientOrder; //用于得到从socket端的输入信息 InputStream m_inputStream; //用于向socket输出的输出流 OutputStream m_outputStream; //用于上传文件的输出流 FileOutputStream m_fileOutputStream; //用于下载文件的输入流 FileInputStream m_fileInputStream; //构造函数 public TransHandler(FtpServer fserver, Socket s, int iNum) { try { main = fserver; //将客户端socket句柄付给本地对象 m_clientSocket = s; //初始化log对象 mylog = Logger.getLogger("TransHandler"); //初始化本客户端序号 iClientNum = iNum; //用于得到从socket端的输入信息 m_inputStream = m_clientSocket.getInputStream(); m_outputStream = m_clientSocket.getOutputStream(); ibufferlength = 1024; inputBytes = new byte[ibufferlength + 12]; } catch (Exception e) { mylog.warning("在初始化TransHandler时发生异常!"); mylog.warning(e.getMessage()); } } public void run() { try { int ilength; while ( (ilength = m_inputStream.read(inputBytes, 0, 12 + ibufferlength)) != -1) { strClientOrder = new String(inputBytes, 0, 7); if (strClientOrder.equals("DISCONN")) { //断开连接 mylog.info("得到了DISCONN"); exit(); } else if (strClientOrder.equals("LSFILES")) { //发送当前目录文件列表 mylog.info("服务器端接收到了LSFILES命令"); File flHome = new File(main.strServHome); String[] strFileNames = flHome.list(); strFileNames = AdjustStrings(strFileNames); for (int i = 0; i < strFileNames.length; i++) { String strFileNameLength = PublicFunc.formatLength(strFileNames[i]. getBytes().length); byte[] fileNameBytes = strFileNames[i].getBytes(); byte[] outBytes = PublicFunc.makepackage("LSFILES", strFileNameLength, fileNameBytes); m_outputStream.write(outBytes, 0, outBytes.length); m_outputStream.flush(); } } else if (strClientOrder.equals("ENDFILE")) { //上传一个文件的结束标记 mylog.info("收到文件结束标志符号"); m_fileOutputStream.close(); } else if (strClientOrder.equals("UPFILEN")) { //表示要上传一个新的文件,并且此包中包含了文件名 int iFileNameLength = Integer.parseInt(new String(inputBytes, 7, 5)); mylog.info("要上传的文件名的长度为" + iFileNameLength); String strFileName = new String(inputBytes, 12, iFileNameLength); mylog.info("要上传的文件名是:" + strFileName); //初始化上传文件路径 strUpFilePath = main.strServHome + strFileName; File upFile = new File(strUpFilePath); m_fileOutputStream = new FileOutputStream(upFile); } else if (strClientOrder.equals("UPDATAS")) { //表示本包是要上传的数据 //本次数据包的长度 mylog.info("正在接收文件..."); int iDataLength = Integer.parseInt(new String(inputBytes, 7, 5)); m_fileOutputStream.write(inputBytes, 12, iDataLength); m_fileOutputStream.flush(); } else if (strClientOrder.equals("DNFILEN")) { //表示要下载的文件名,服务器要执行向客户端传输文件的操作 int iFileNameLength = Integer.parseInt(new String(inputBytes, 7, 5)); mylog.info("要下载的文件名的长度为" + iFileNameLength); String strFileName = new String(inputBytes, 12, iFileNameLength); mylog.info("要下载的文件名是:" + strFileName); //初始化上传文件路径 strDnFilePath = main.strServHome + strFileName; File dnFile = new File(strDnFilePath); //初始化了文件输出流 m_fileInputStream = new FileInputStream(dnFile); //开始向客户端传输文件 mylog.info("开始向客户端传输文件" + strFileName + "..."); int iInputLength = 0; String strInputLength; byte[] readBytes = new byte[ibufferlength]; while ( (iInputLength = m_fileInputStream.read(readBytes, 0, ibufferlength)) != -1) { strInputLength = PublicFunc.formatLength(iInputLength); byte[] outBytes = PublicFunc.makepackage("DNDATAS", strInputLength, readBytes); m_outputStream.write(outBytes, 0, outBytes.length); m_outputStream.flush(); } //最后发送一个文件结束标记 m_outputStream.write(PublicFunc.makepackage("ENDFILE", "00001", new byte[1])); m_outputStream.flush(); } } } catch (Exception e) { mylog.warning(e.getMessage()); } } public void exit() { try { m_outputStream.write(PublicFunc.makepackage("DISCONN", "00001", new byte[1])); m_inputStream.close(); m_outputStream.close(); main.deleteClient(this); main = null; } catch (Exception e) { mylog.warning("在断开客户端#" + this.iClientNum + "连接时出现异常!"); mylog.warning(e.getMessage()); } } public String[] AdjustStrings(String[] strFileNames) { String[] strItemNames = new String[strFileNames.length + 1]; strItemNames[0] = "返回上一级"; int j = 1; for (int i = 0; i < strFileNames.length; i++) { File upFile = new File(main.strServHome + strFileNames[i]); if (!upFile.isFile()) { strItemNames[j++] = "[文件夹]" + strFileNames[i]; } } for (int i = 0; i < strFileNames.length; i++) { File upFile = new File(main.strServHome + strFileNames[i]); if (upFile.isFile()) { strItemNames[j++] = strFileNames[i]; } } return strItemNames; }} package cn.edu.bit.software.ftptrans;import java.io.*;import java.net.*;import java.util.logging.*;import java.util.Vector;public class FtpClient extends Thread{ Logger mylog = Logger.getLogger("FtpClient"); Socket m_clientSocket; //缓冲字节数据的大小 private int ibufferlength; //缓冲字节数组 byte[] inputBytes; Vector vecServFiles; //用于得到从socket端的输入信息 InputStream m_inputStream; //用于向socket输出的输出流 OutputStream m_outputStream; //向本地写文件的文件输出流 FileOutputStream m_fileOutputStream; //从本地读文件的文件输入流 FileInputStream m_fileInputStream; //从服务器端传来的指令 String strServerOrder; //主机的ip地址 String strServerIP; //服务器的端口号 int iServerPort; public FtpClient(String strServIP, int iServPort) { strServerIP = strServIP; iServerPort = iServPort; } public void run() { try { //建立连接 m_clientSocket = new Socket(strServerIP, iServerPort); mylog.info("已经连到了主机" + strServerIP + "在端口" + iServerPort); m_inputStream = m_clientSocket.getInputStream(); m_outputStream = m_clientSocket.getOutputStream(); mylog.fine("客户端得到了socket的输入输出流!"); ibufferlength = 1024; inputBytes = new byte[ibufferlength + 12]; vecServFiles = new Vector(); doBusiness(); } catch (UnknownHostException e) { mylog.warning("服务器地址未知"); mylog.warning(e.getMessage()); } catch (IOException e) { mylog.warning(e.getMessage()); } catch (Exception e) { mylog.warning(e.getMessage()); } } public void doBusiness() { try { int iLength = 0; while ( (iLength = m_inputStream.read(inputBytes, 0, ibufferlength + 12)) != -1) { strServerOrder = new String(inputBytes, 0, 7); if (strServerOrder.equals("DISCONN")) { //断开连接 mylog.info("在client端得到了DISCONN"); int length = Integer.parseInt(new String(inputBytes, 7, 5)); mylog.info("长度是" + length); } else if (strServerOrder.equals("LSFILES")) { //接收服务器当前目录文件列表 int iDataLength = Integer.parseInt(new String(inputBytes, 7, 5)); mylog.info("在客户端这个文件名的长度是:" + iDataLength); String strFileName = new String(inputBytes, 12, iDataLength); mylog.info("客户端正在获取服务器目录信息....." + strFileName); vecServFiles.add(strFileName); } else if (strServerOrder.equals("ENDFILE")) { //下载一个文件的结束标记 mylog.info("收到下载文件结束标志符号"); m_fileOutputStream.close(); } else if (strServerOrder.equals("DNDATAS")) { //表示本包是要下载的数据 int iDataLength = Integer.parseInt(new String(inputBytes, 7, 5)); m_fileOutputStream.write(inputBytes, 12, iDataLength); m_fileOutputStream.flush(); } } } catch (Exception e) { } } /** * 客户端上传文件名 * @param strFileName 要上传文件的文件名 */ public void upFileName(String strFileName) { try { String strLength = PublicFunc.formatLength(strFileName.getBytes().length); byte[] outBytes = PublicFunc.makepackage("UPFILEN", strLength, strFileName.getBytes()); m_outputStream.write(outBytes, 0, outBytes.length); m_outputStream.flush(); } catch (Exception e) { mylog.warning("在客户端在向服务器写要上传的文件名时发生异常"); mylog.warning(e.getMessage()); } } /** * 讲本地文件strFilePath上传到服务器 * @param strFilePath 本地文件路径 */ public void upFileData(String strFilePath) { try { File file = new File(strFilePath); m_fileInputStream = new FileInputStream(file); int iInputLength = 0; String strInputLength; byte[] readBytes = new byte[ibufferlength]; while ( (iInputLength = m_fileInputStream.read(readBytes, 0, ibufferlength)) != -1) { strInputLength = PublicFunc.formatLength(iInputLength); byte[] outBytes = PublicFunc.makepackage("UPDATAS", strInputLength, readBytes); m_outputStream.write(outBytes, 0, outBytes.length); m_outputStream.flush(); } //最后发送一个文件结束标记 m_outputStream.write(PublicFunc.makepackage("ENDFILE", "00001", new byte[1])); m_outputStream.flush(); } catch (Exception e) { mylog.warning("从客户端向服务器传输文件内容是发生异常"); mylog.warning(e.getMessage()); } } 非常感谢 OnlyFor_love 但是我需要的是 从已有的 ftp服务器 来实现 多线程下载并不是自己写一个服务器端程序请问有什么思路吗?谢谢 用Java实现HTTP断点续传(一)断点续传的原理 其实断点续传的原理很简单,就是在Http的请求上和一般的下载有所不同而已。打个比方,浏览器请求服务器上的一个文时,所发出的请求如下: 假设服务器域名为wwww.sjtu.edu.cn,文件名为down.zip。GET /down.zip HTTP/1.1Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, application/vnd.ms-powerpoint, */*Accept-Language: zh-cnAccept-Encoding: gzip, deflateUser-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)Connection: Keep-Alive 服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:200Content-Length=106786028Accept-Ranges=bytesDate=Mon, 30 Apr 2001 12:56:11 GMTETag=W/"02ca57e173c11:95b"Content-Type=application/octet-streamServer=Microsoft-IIS/5.0Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT 所谓断点续传,也就是要从文件已经下载的地方开始继续下载。所以在客户端浏览器传给Web服务器的时候要多加一条信息--从哪里开始。 下面是用自己编的一个"浏览器"来传递请求信息给Web服务器,要求从2000070字节开始。GET /down.zip HTTP/1.0User-Agent: NetFoxRANGE: bytes=2000070-Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 仔细看一下就会发现多了一行RANGE: bytes=2000070-;这一行的意思就是告诉服务器down.zip这个文件从2000070字节开始传,前面的字节不用传了。 服务器收到这个请求以后,返回的信息如下:206Content-Length=106786028Content-Range=bytes 2000070-106786027/106786028Date=Mon, 30 Apr 2001 12:55:20 GMTETag=W/"02ca57e173c11:95b"Content-Type=application/octet-streamServer=Microsoft-IIS/5.0Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT 和前面服务器返回的信息比较一下,就会发现增加了一行:Content-Range=bytes 2000070-106786027/106786028返回的代码也改为206了,而不再是200了。 知道了以上原理,就可以进行断点续传的编程了。(二)Java实现断点续传的关键几点 (1)用什么方法实现提交RANGE: bytes=2000070-。当然用最原始的Socket是肯定能完成的,不过那样太费事了,其实Java的net包中提供了这种功能。代码如下:URL url = new URL(" http://www.sjtu.edu.cn/down.zip";;);HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();//设置User-AgenthttpConnection.setRequestProperty("User-Agent","NetFox");//设置断点续传的开始位置httpConnection.setRequestProperty("RANGE","bytes=2000070");//获得输入流InputStream input = httpConnection.getInputStream(); 从输入流中取出的字节流就是down.zip文件从2000070开始的字节流。大家看,其实断点续传用Java实现起来还是很简单的吧。接下来要做的事就是怎么保存获得的流到文件中去了。 保存文件采用的方法 我采用的是IO包中的RandAccessFile类。 操作相当简单,假设从2000070处开始保存文件,代码如下:RandomAccess oSavedFile = new RandomAccessFile("down.zip","rw");long nPos = 2000070;//定位文件指针到nPos位置oSavedFile.seek(nPos);byte[] b = new byte[1024];int nRead;//从输入流中读入字节流,然后写到文件中while((nRead=input.read(b,0,1024)) > 0){ oSavedFile.write(b,0,nRead);} 接下来要做的就是整合成一个完整的程序了。包括一系列的线程控制等等。 (三)断点续传内核的实现 主要用了6个类,包括一个测试类: SiteFileFetch.java负责整个文件的抓取,控制内部线程(FileSplitterFetch类)。 FileSplitterFetch.java负责部分文件的抓取。 FileAccess.java负责文件的存储。 SiteInfoBean.java要抓取的文件的信息,如文件保存的目录,名字,抓取文件的URL等。 Utility.java工具类,放一些简单的方法。 TestMethod.java测试类。下面是源程序:***SiteFileFetch.java*/package NetFox;import java.io.*;import java.net.*;public class SiteFileFetch extends Thread {SiteInfoBean siteInfoBean = null; //文件信息Beanlong[] nStartPos; //开始位置long[] nEndPos; //结束位置FileSplitterFetch[] fileSplitterFetch; //子线程对象long nFileLength; //文件长度boolean bFirst = true; //是否第一次取文件boolean bStop = false; //停止标志File tmpFile; //文件下载的临时信息DataOutputStream output; //输出到文件的输出流public SiteFileFetch(SiteInfoBean bean) throws IOException{ siteInfoBean = bean; //tmpFile = File.createTempFile ("zhong","1111",new File(bean.getSFilePath())); tmpFile = new File(bean.getSFilePath()+File.separator + bean.getSFileName()+".info"); if(tmpFile.exists ()) { bFirst = false; read_nPos(); } else { nStartPos = new long[bean.getNSplitter()]; nEndPos = new long[bean.getNSplitter()]; }}public void run(){ //获得文件长度 //分割文件 //实例FileSplitterFetch //启动FileSplitterFetch线程 //等待子线程返回 try{ if(bFirst) { nFileLength = getFileSize(); if(nFileLength == -1) { System.err.println("File Length is not known!"); } else if(nFileLength == -2) { System.err.println("File is not access!"); } else { for(int i=0;i<nStartPos.length;i++) { nStartPos[i] = (long)(i*(nFileLength/nStartPos.length)); } for(int i=0;i<nEndPos.length-1;i++) { nEndPos[i] = nStartPos[i+1]; } nEndPos[nEndPos.length-1] = nFileLength; } } //启动子线程 fileSplitterFetch = new FileSplitterFetch[nStartPos.length]; for(int i=0;i<nStartPos.length;i++) { fileSplitterFetch[i] = new FileSplitterFetch(siteInfoBean.getSSiteURL(), siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(), nStartPos[i],nEndPos[i],i); Utility.log("Thread " + i + " , nStartPos = " + nStartPos[i] + ", nEndPos = " + nEndPos[i]); fileSplitterFetch[i].start(); } // fileSplitterFetch[nPos.length-1] = new FileSplitterFetch(siteInfoBean.getSSiteURL(), siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),nPos[nPos.length-1],nFileLength,nPos.length-1); // Utility.log("Thread " + (nPos.length-1) + " , nStartPos = " + nPos[nPos.length-1] + ", nEndPos = " + nFileLength); // fileSplitterFetch[nPos.length-1].start(); //等待子线程结束 //int count = 0; //是否结束while循环 boolean breakWhile = false; while(!bStop) { write_nPos(); Utility.sleep(500); breakWhile = true; for(int i=0;i<nStartPos.length;i++) { if(!fileSplitterFetch[i].bDownOver) { breakWhile = false; break; } } if(breakWhile) break; //count++; //if(count>4) // siteStop(); } System.err.println("文件下载结束!");}catch(Exception e){e.printStackTrace ();}}//获得文件长度public long getFileSize(){ int nFileLength = -1; try{ URL url = new URL(siteInfoBean.getSSiteURL()); HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection (); httpConnection.setRequestProperty("User-Agent","NetFox"); int responseCode=httpConnection.getResponseCode(); if(responseCode>=400) { processErrorCode(responseCode); return -2; //-2 represent access is error } String sHeader; for(int i=1;;i++) { //DataInputStream in = new DataInputStream(httpConnection.getInputStream ()); //Utility.log(in.readLine()); sHeader=httpConnection.getHeaderFieldKey(i); if(sHeader!=null) { if(sHeader.equals("Content-Length")) { nFileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader)); break; } } else break; } } catch(IOException e){e.printStackTrace ();} catch(Exception e){e.printStackTrace ();} Utility.log(nFileLength); return nFileLength;}//保存下载信息(文件指针位置)private void write_nPos(){ try{ output = new DataOutputStream(new FileOutputStream(tmpFile)); output.writeInt(nStartPos.length); for(int i=0;i<nStartPos.length;i++) { // output.writeLong(nPos[i]); output.writeLong(fileSplitterFetch[i].nStartPos); output.writeLong(fileSplitterFetch[i].nEndPos); } output.close(); } catch(IOException e){e.printStackTrace ();} catch(Exception e){e.printStackTrace ();}}//读取保存的下载信息(文件指针位置)private void read_nPos(){ try{ DataInputStream input = new DataInputStream(new FileInputStream(tmpFile)); int nCount = input.readInt(); nStartPos = new long[nCount]; nEndPos = new long[nCount]; for(int i=0;i<nStartPos.length;i++) { nStartPos[i] = input.readLong(); nEndPos[i] = input.readLong(); } input.close(); } catch(IOException e){e.printStackTrace ();} catch(Exception e){e.printStackTrace ();}}private void processErrorCode(int nErrorCode){ System.err.println("Error Code : " + nErrorCode);}//停止文件下载public void siteStop(){ bStop = true; for(int i=0;i<nStartPos.length;i++) fileSplitterFetch[i].splitterStop();}}/***FileSplitterFetch.java*/package NetFox;import java.io.*;import java.net.*; public class FileSplitterFetch extends Thread { String sURL; //File URL long nStartPos; //File Snippet Start Position long nEndPos; //File Snippet End Position int nThreadID; //Thread's ID boolean bDownOver = false; //Downing is over boolean bStop = false; //Stop identical FileAccessI fileAccessI = null; //File Access interface public FileSplitterFetch(String sURL,String sName,long nStart,long nEnd,int id) throws IOException { this.sURL = sURL; this.nStartPos = nStart; this.nEndPos = nEnd; nThreadID = id; fileAccessI = new FileAccessI(sName,nStartPos); }public void run(){ while(nStartPos < nEndPos && !bStop) { try{ URL url = new URL(sURL); HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection (); httpConnection.setRequestProperty("User-Agent","NetFox"); String sProperty = "bytes="+nStartPos+"-"; httpConnection.setRequestProperty("RANGE",sProperty); Utility.log(sProperty); InputStream input = httpConnection.getInputStream(); //logResponseHead(httpConnection); byte[] b = new byte[1024]; int nRead; while((nRead=input.read(b,0,1024)) > 0 && nStartPos < nEndPos && !bStop) { nStartPos += fileAccessI.write(b,0,nRead); //if(nThreadID == 1) // Utility.log("nStartPos = " + nStartPos + ", nEndPos = " + nEndPos); } Utility.log("Thread " + nThreadID + " is over!"); bDownOver = true; //nPos = fileAccessI.write (b,0,nRead); } catch(Exception e){e.printStackTrace ();} }}//打印回应的头信息public void logResponseHead(HttpURLConnection con){ for(int i=1;;i++) { String header=con.getHeaderFieldKey(i); if(header!=null) //responseHeaders.put(header,httpConnection.getHeaderField(header)); Utility.log(header+" : "+con.getHeaderField(header)); else break; }}public void splitterStop(){ bStop = true;}}/***FileAccess.java*/package NetFox;import java.io.*;public class FileAccessI implements Serializable{ RandomAccessFile oSavedFile; long nPos; public FileAccessI() throws IOException { this("",0); } public FileAccessI(String sName,long nPos) throws IOException { oSavedFile = new RandomAccessFile(sName,"rw"); this.nPos = nPos; oSavedFile.seek(nPos); } public synchronized int write(byte[] b,int nStart,int nLen) { int n = -1; try{ oSavedFile.write(b,nStart,nLen); n = nLen; } catch(IOException e) { e.printStackTrace (); } return n; }}/***SiteInfoBean.java*/package NetFox;public class SiteInfoBean { private String sSiteURL; //Site's URL private String sFilePath; //Saved File's Path private String sFileName; //Saved File's Name private int nSplitter; //Count of Splited Downloading File public SiteInfoBean() { //default value of nSplitter is 5 this("","","",5); } public SiteInfoBean(String sURL,String sPath,String sName,int nSpiltter) { sSiteURL= sURL; sFilePath = sPath; sFileName = sName; this.nSplitter = nSpiltter; } public String getSSiteURL() { return sSiteURL; } public void setSSiteURL(String value) { sSiteURL = value; } public String getSFilePath() { return sFilePath; } public void setSFilePath(String value) { sFilePath = value; } public String getSFileName() { return sFileName; } public void setSFileName(String value) { sFileName = value; } public int getNSplitter() { return nSplitter; } public void setNSplitter(int nCount) { nSplitter = nCount; }}/***Utility.java*/package NetFox;public class Utility { public Utility() { } public static void sleep(int nSecond) { try{ Thread.sleep(nSecond); } catch(Exception e) { e.printStackTrace (); } }public static void log(String sMsg){ System.err.println(sMsg);}public static void log(int sMsg){ System.err.println(sMsg);}}/***TestMethod.java*/package NetFox;public class TestMethod { public TestMethod() { ///xx/weblogic60b2_win.exe try{SiteInfoBean bean = new SiteInfoBean("http://localhost/xx/weblogic60b2_win.exe";;,"L:\temp","weblogic60b2_win.exe",5); //SiteInfoBean bean = new SiteInfoBean(" http://localhost:8080/down.zip";;,"L:\temp","weblogic60b2_win.exe",5); SiteFileFetch fileFetch = new SiteFileFetch(bean); fileFetch.start(); } catch(Exception e){e.printStackTrace ();} } public static void main(String[] args) { new TestMethod(); }} jnode怎么用啊,比如创建一个文件的命令 Java哪个好点 年底散分200!!!!!!!!!!!!!!!!!!!!!!!!!!! 关于读取数据库数据的问题! 怎样设计并调用两个不同的paint()方法? 喜欢java的朋友请进~ 问一个关于位运算的问题 Rational Rose怎么导入java类库 告退,散分。 再次有劳各位JJ,GG,MM,DD,给看看一个小程序!先谢过各位! 请教数据库连接方面的内容 鼠标监听
每次发送12+1024个字节
其中,前七个字节字节表示命令
第七到第十二个字节表示后面1024字节中的有效字节的长度
例如一帧中前12个字节的内容为"UPFILEN00012"表示要上传文件名,文件名的长度是12。那么程序就在后面的1024个字节中去12个字节,在把它转换为字符串,作为要上传的文件名。2:命令结构
Server端:
DISCONN:断开连接
LSFILES:发送当前目录文件列表
ENDFILE:上传一个文件的结束标记
UPFILEN:表示要上传一个新的文件,并且此包中包含了文件名
UPDATAS:表示本包是要上传的数据
DNFILEN:表示要下载的文件名,服务器要执行向客户端传输文件的操作
Client端:
DISCONN:断开连接
LSFILES:接收服务器当前目录文件列表
ENDFILE:下载一个文件的结束标记
DNDATAS:表示本包是要下载的数据3:文件结构
FtpServer:ftp软件的服务器端,目前在端口2121监听,支持多线程,文件的上传,下载,列表。
FtpClient:ftp软件的客户端,默认连接本机的服务器端,在端口2121,支持文件的上传,下载,列表。
FtpClientUI:ftp软件的客户端的用户界面,完全采用Swing技术,手工编写,没有用JB自动生成。
PublicFunc:提供一些公共的静态方法例如将给定的String对象分装成要发送的帧。将数字格式化成长度为五位的String类型对象。
package cn.edu.bit.software.ftptrans;import java.io.*;
import java.net.*;
import java.util.Vector;
import java.util.logging.*;public class FtpServer
{
//客户端socket对象
private ServerSocket m_servSocket; //ftp服务器的端口号
private int SERVER_PORT; //ftp服务器所允许的最大连接数
private int MAX_CONN; //连入的客户端处理对象管理器
private Vector vecClient; //设定一个log日志对象
private Logger mylog; private ConsoleHandler handler; String strServHome; public FtpServer(int servPort, int maxConn)
{
SERVER_PORT = servPort;
MAX_CONN = maxConn;
strServHome = "c:\\";
vecClient = new Vector();
/*------------初始化log------------*/
try
{
handler = new ConsoleHandler();
handler.setLevel(Level.ALL);
mylog = Logger.getLogger("FtpServer");
mylog.addHandler(handler);
mylog.setLevel(Level.ALL);
}
catch (SecurityException e)
{
mylog.warning("在设置程序日志级别时出现异常");
mylog.warning(e.getMessage());
} /*--------------初始化服务器,端口2121----------------------*/
try
{
m_servSocket = new ServerSocket(SERVER_PORT, MAX_CONN);
while (true)
{
mylog.finest("FtpServer开始在端口2121监听");
Socket clientSocket = m_servSocket.accept();
vecClient.add(clientSocket);
mylog.info("#" + vecClient.size() + "号客户端连入");
new TransHandler(this, clientSocket, vecClient.size()).start();
}
}
catch (IOException e)
{
mylog.warning("在初始化FtpServ时出现错误");
mylog.warning(e.getMessage());
}
} public void deleteClient(TransHandler handler)
{
try
{
vecClient.remove(handler);
vecClient.setSize(vecClient.size() - 1);
mylog.info("第#" + handler.iClientNum + "号客户端断开了与服务器的连接!");
}
catch (Exception e)
{
mylog.warning("在删除第#" + handler.iClientNum + "号客户端时出现异常");
mylog.warning(e.getMessage());
}
} public static void main(String[] args)
{
new FtpServer(2121, 50);
}
}
* 当有客户端连入时,处理客户端请求的类
* @author findfrog
* @version 1.0
*/
class TransHandler extends Thread
{
//服务器句柄,用于最后销毁TransHandler对象时用
FtpServer main = null;
//客户端的socket
private Socket m_clientSocket = null; //日志对象
private Logger mylog; //要上传的文件路径
private String strUpFilePath = null; //要下载的文件路径
private String strDnFilePath = null; //本客户端在的序号
int iClientNum = -1; //缓冲字节数据的大小
private int ibufferlength; //缓冲字节数组
byte[] inputBytes; //从客户端传来的指令
String strClientOrder;
//用于得到从socket端的输入信息
InputStream m_inputStream;
//用于向socket输出的输出流
OutputStream m_outputStream;
//用于上传文件的输出流
FileOutputStream m_fileOutputStream;
//用于下载文件的输入流
FileInputStream m_fileInputStream; //构造函数
public TransHandler(FtpServer fserver, Socket s, int iNum)
{
try
{
main = fserver;
//将客户端socket句柄付给本地对象
m_clientSocket = s;
//初始化log对象
mylog = Logger.getLogger("TransHandler");
//初始化本客户端序号
iClientNum = iNum;
//用于得到从socket端的输入信息
m_inputStream = m_clientSocket.getInputStream();
m_outputStream = m_clientSocket.getOutputStream();
ibufferlength = 1024;
inputBytes = new byte[ibufferlength + 12]; }
catch (Exception e)
{
mylog.warning("在初始化TransHandler时发生异常!");
mylog.warning(e.getMessage());
}
} public void run()
{
try
{
int ilength;
while ( (ilength = m_inputStream.read(inputBytes, 0, 12 + ibufferlength)) !=
-1)
{
strClientOrder = new String(inputBytes, 0, 7);
if (strClientOrder.equals("DISCONN"))
{ //断开连接
mylog.info("得到了DISCONN");
exit();
}
else if (strClientOrder.equals("LSFILES"))
{ //发送当前目录文件列表
mylog.info("服务器端接收到了LSFILES命令");
File flHome = new File(main.strServHome);
String[] strFileNames = flHome.list();
strFileNames = AdjustStrings(strFileNames);
for (int i = 0; i < strFileNames.length; i++)
{
String strFileNameLength = PublicFunc.formatLength(strFileNames[i].
getBytes().length);
byte[] fileNameBytes = strFileNames[i].getBytes();
byte[] outBytes = PublicFunc.makepackage("LSFILES",
strFileNameLength, fileNameBytes);
m_outputStream.write(outBytes, 0, outBytes.length);
m_outputStream.flush();
}
}
else if (strClientOrder.equals("ENDFILE"))
{ //上传一个文件的结束标记
mylog.info("收到文件结束标志符号");
m_fileOutputStream.close();
}
else if (strClientOrder.equals("UPFILEN"))
{ //表示要上传一个新的文件,并且此包中包含了文件名
int iFileNameLength = Integer.parseInt(new String(inputBytes, 7, 5));
mylog.info("要上传的文件名的长度为" + iFileNameLength);
String strFileName = new String(inputBytes, 12, iFileNameLength);
mylog.info("要上传的文件名是:" + strFileName);
//初始化上传文件路径
strUpFilePath = main.strServHome + strFileName;
File upFile = new File(strUpFilePath);
m_fileOutputStream = new FileOutputStream(upFile);
}
else if (strClientOrder.equals("UPDATAS"))
{ //表示本包是要上传的数据
//本次数据包的长度
mylog.info("正在接收文件...");
int iDataLength = Integer.parseInt(new String(inputBytes, 7, 5));
m_fileOutputStream.write(inputBytes, 12, iDataLength);
m_fileOutputStream.flush();
}
else if (strClientOrder.equals("DNFILEN"))
{ //表示要下载的文件名,服务器要执行向客户端传输文件的操作
int iFileNameLength = Integer.parseInt(new String(inputBytes, 7, 5));
mylog.info("要下载的文件名的长度为" + iFileNameLength);
String strFileName = new String(inputBytes, 12, iFileNameLength);
mylog.info("要下载的文件名是:" + strFileName);
//初始化上传文件路径
strDnFilePath = main.strServHome + strFileName;
File dnFile = new File(strDnFilePath);
//初始化了文件输出流
m_fileInputStream = new FileInputStream(dnFile); //开始向客户端传输文件
mylog.info("开始向客户端传输文件" + strFileName + "...");
int iInputLength = 0;
String strInputLength;
byte[] readBytes = new byte[ibufferlength];
while ( (iInputLength = m_fileInputStream.read(readBytes, 0,
ibufferlength)) !=
-1)
{
strInputLength = PublicFunc.formatLength(iInputLength);
byte[] outBytes = PublicFunc.makepackage("DNDATAS", strInputLength,
readBytes);
m_outputStream.write(outBytes, 0, outBytes.length);
m_outputStream.flush();
} //最后发送一个文件结束标记
m_outputStream.write(PublicFunc.makepackage("ENDFILE", "00001",
new byte[1]));
m_outputStream.flush();
}
}
}
catch (Exception e)
{
mylog.warning(e.getMessage());
}
} public void exit()
{
try
{
m_outputStream.write(PublicFunc.makepackage("DISCONN", "00001",
new byte[1]));
m_inputStream.close();
m_outputStream.close();
main.deleteClient(this);
main = null;
}
catch (Exception e)
{
mylog.warning("在断开客户端#" + this.iClientNum + "连接时出现异常!");
mylog.warning(e.getMessage());
}
} public String[] AdjustStrings(String[] strFileNames)
{
String[] strItemNames = new String[strFileNames.length + 1];
strItemNames[0] = "返回上一级";
int j = 1;
for (int i = 0; i < strFileNames.length; i++)
{
File upFile = new File(main.strServHome + strFileNames[i]);
if (!upFile.isFile())
{
strItemNames[j++] = "[文件夹]" + strFileNames[i];
}
}
for (int i = 0; i < strFileNames.length; i++)
{
File upFile = new File(main.strServHome + strFileNames[i]);
if (upFile.isFile())
{
strItemNames[j++] = strFileNames[i];
}
} return strItemNames;
}}
import java.net.*;
import java.util.logging.*;
import java.util.Vector;public class FtpClient extends Thread
{
Logger mylog = Logger.getLogger("FtpClient");
Socket m_clientSocket;
//缓冲字节数据的大小
private int ibufferlength; //缓冲字节数组
byte[] inputBytes; Vector vecServFiles; //用于得到从socket端的输入信息
InputStream m_inputStream;
//用于向socket输出的输出流
OutputStream m_outputStream;
//向本地写文件的文件输出流
FileOutputStream m_fileOutputStream;
//从本地读文件的文件输入流
FileInputStream m_fileInputStream;
//从服务器端传来的指令
String strServerOrder;
//主机的ip地址
String strServerIP;
//服务器的端口号
int iServerPort; public FtpClient(String strServIP, int iServPort)
{
strServerIP = strServIP;
iServerPort = iServPort;
} public void run()
{
try
{
//建立连接
m_clientSocket = new Socket(strServerIP, iServerPort);
mylog.info("已经连到了主机" + strServerIP + "在端口" + iServerPort);
m_inputStream = m_clientSocket.getInputStream();
m_outputStream = m_clientSocket.getOutputStream();
mylog.fine("客户端得到了socket的输入输出流!");
ibufferlength = 1024;
inputBytes = new byte[ibufferlength + 12];
vecServFiles = new Vector();
doBusiness();
}
catch (UnknownHostException e)
{
mylog.warning("服务器地址未知");
mylog.warning(e.getMessage());
}
catch (IOException e)
{
mylog.warning(e.getMessage());
}
catch (Exception e)
{
mylog.warning(e.getMessage());
}
} public void doBusiness()
{
try
{
int iLength = 0;
while ( (iLength = m_inputStream.read(inputBytes, 0, ibufferlength + 12)) !=
-1)
{
strServerOrder = new String(inputBytes, 0, 7);
if (strServerOrder.equals("DISCONN"))
{ //断开连接
mylog.info("在client端得到了DISCONN");
int length = Integer.parseInt(new String(inputBytes, 7, 5));
mylog.info("长度是" + length);
}
else if (strServerOrder.equals("LSFILES"))
{ //接收服务器当前目录文件列表 int iDataLength = Integer.parseInt(new String(inputBytes, 7, 5));
mylog.info("在客户端这个文件名的长度是:" + iDataLength);
String strFileName = new String(inputBytes, 12, iDataLength);
mylog.info("客户端正在获取服务器目录信息....." + strFileName);
vecServFiles.add(strFileName);
}
else if (strServerOrder.equals("ENDFILE"))
{ //下载一个文件的结束标记
mylog.info("收到下载文件结束标志符号");
m_fileOutputStream.close();
}
else if (strServerOrder.equals("DNDATAS"))
{ //表示本包是要下载的数据
int iDataLength = Integer.parseInt(new String(inputBytes, 7, 5));
m_fileOutputStream.write(inputBytes, 12, iDataLength);
m_fileOutputStream.flush();
}
}
}
catch (Exception e)
{ }
} /**
* 客户端上传文件名
* @param strFileName 要上传文件的文件名
*/
public void upFileName(String strFileName)
{
try
{
String strLength = PublicFunc.formatLength(strFileName.getBytes().length);
byte[] outBytes = PublicFunc.makepackage("UPFILEN", strLength,
strFileName.getBytes());
m_outputStream.write(outBytes, 0, outBytes.length);
m_outputStream.flush();
}
catch (Exception e)
{
mylog.warning("在客户端在向服务器写要上传的文件名时发生异常");
mylog.warning(e.getMessage());
}
} /**
* 讲本地文件strFilePath上传到服务器
* @param strFilePath 本地文件路径
*/
public void upFileData(String strFilePath)
{
try
{
File file = new File(strFilePath);
m_fileInputStream = new FileInputStream(file); int iInputLength = 0;
String strInputLength;
byte[] readBytes = new byte[ibufferlength];
while ( (iInputLength = m_fileInputStream.read(readBytes, 0,
ibufferlength)) !=
-1)
{
strInputLength = PublicFunc.formatLength(iInputLength);
byte[] outBytes = PublicFunc.makepackage("UPDATAS", strInputLength,
readBytes);
m_outputStream.write(outBytes, 0, outBytes.length);
m_outputStream.flush();
}
//最后发送一个文件结束标记
m_outputStream.write(PublicFunc.makepackage("ENDFILE", "00001",
new byte[1]));
m_outputStream.flush();
}
catch (Exception e)
{
mylog.warning("从客户端向服务器传输文件内容是发生异常");
mylog.warning(e.getMessage());
}
}
但是我需要的是 从已有的 ftp服务器 来实现 多线程下载
并不是自己写一个服务器端程序请问有什么思路吗?
谢谢
(一)断点续传的原理 其实断点续传的原理很简单,就是在Http的请求上和一般的下载有所不同而已。打个比方,浏览器请求服务器上的一个文时,所发出的请求如下: 假设服务器域名为wwww.sjtu.edu.cn,文件名为down.zip。
GET /down.zip HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
excel, application/msword, application/vnd.ms-powerpoint, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Connection: Keep-Alive
服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:
200
Content-Length=106786028
Accept-Ranges=bytes
Date=Mon, 30 Apr 2001 12:56:11 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT
所谓断点续传,也就是要从文件已经下载的地方开始继续下载。所以在客户端浏览器传给
Web服务器的时候要多加一条信息--从哪里开始。
下面是用自己编的一个"浏览器"来传递请求信息给Web服务器,要求从2000070字节开始。
GET /down.zip HTTP/1.0
User-Agent: NetFox
RANGE: bytes=2000070-
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
仔细看一下就会发现多了一行RANGE: bytes=2000070-;这一行的意思就是告诉服务器down.zip这个文件从2000070字节开始传,前面的字节不用传了。
服务器收到这个请求以后,返回的信息如下:
206
Content-Length=106786028
Content-Range=bytes 2000070-106786027/106786028
Date=Mon, 30 Apr 2001 12:55:20 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT 和前面服务器返回的信息比较一下,就会发现增加了一行:
Content-Range=bytes 2000070-106786027/106786028
返回的代码也改为206了,而不再是200了。
知道了以上原理,就可以进行断点续传的编程了。
(二)Java实现断点续传的关键几点 (1)用什么方法实现提交RANGE: bytes=2000070-。
当然用最原始的Socket是肯定能完成的,不过那样太费事了,其实Java的net包中提供了这种功能。代码如下:
URL url = new URL(" http://www.sjtu.edu.cn/down.zip";;);
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
//设置User-Agent
httpConnection.setRequestProperty("User-Agent","NetFox");
//设置断点续传的开始位置
httpConnection.setRequestProperty("RANGE","bytes=2000070");
//获得输入流
InputStream input = httpConnection.getInputStream();
从输入流中取出的字节流就是down.zip文件从2000070开始的字节流。大家看,其实断点续传用Java实现起来还是很简单的吧。接下来要做的事就是怎么保存获得的流到文件中去了。
保存文件采用的方法
我采用的是IO包中的RandAccessFile类。
操作相当简单,假设从2000070处开始保存文件,代码如下:
RandomAccess oSavedFile = new RandomAccessFile("down.zip","rw");
long nPos = 2000070;
//定位文件指针到nPos位置
oSavedFile.seek(nPos);
byte[] b = new byte[1024];
int nRead;
//从输入流中读入字节流,然后写到文件中
while((nRead=input.read(b,0,1024)) > 0)
{
oSavedFile.write(b,0,nRead);
}
接下来要做的就是整合成一个完整的程序了。包括一系列的线程控制等等。
SiteFileFetch.java负责整个文件的抓取,控制内部线程(FileSplitterFetch类)。
FileSplitterFetch.java负责部分文件的抓取。 FileAccess.java负责文件的存储。
SiteInfoBean.java要抓取的文件的信息,如文件保存的目录,名字,抓取文件的URL等。
Utility.java工具类,放一些简单的方法。
TestMethod.java测试类。
下面是源程序:
*
**SiteFileFetch.java
*/
package NetFox;
import java.io.*;
import java.net.*;public class SiteFileFetch extends Thread {SiteInfoBean siteInfoBean = null; //文件信息Bean
long[] nStartPos; //开始位置
long[] nEndPos; //结束位置
FileSplitterFetch[] fileSplitterFetch; //子线程对象
long nFileLength; //文件长度
boolean bFirst = true; //是否第一次取文件
boolean bStop = false; //停止标志
File tmpFile; //文件下载的临时信息
DataOutputStream output; //输出到文件的输出流public SiteFileFetch(SiteInfoBean bean) throws IOException
{
siteInfoBean = bean;
//tmpFile = File.createTempFile ("zhong","1111",new File(bean.getSFilePath()));
tmpFile = new File(bean.getSFilePath()+File.separator + bean.getSFileName()+".info");
if(tmpFile.exists ())
{
bFirst = false;
read_nPos();
}
else
{
nStartPos = new long[bean.getNSplitter()];
nEndPos = new long[bean.getNSplitter()];
}
}public void run()
{
//获得文件长度
//分割文件
//实例FileSplitterFetch
//启动FileSplitterFetch线程
//等待子线程返回
try{
if(bFirst)
{
nFileLength = getFileSize();
if(nFileLength == -1)
{
System.err.println("File Length is not known!");
}
else if(nFileLength == -2)
{
System.err.println("File is not access!");
}
else
{
for(int i=0;i<nStartPos.length;i++)
{
nStartPos[i] = (long)(i*(nFileLength/nStartPos.length));
}
for(int i=0;i<nEndPos.length-1;i++)
{
nEndPos[i] = nStartPos[i+1];
}
nEndPos[nEndPos.length-1] = nFileLength;
}
} //启动子线程
fileSplitterFetch = new FileSplitterFetch[nStartPos.length];
for(int i=0;i<nStartPos.length;i++)
{
fileSplitterFetch[i] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),
siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(), nStartPos[i],nEndPos[i],i);
Utility.log("Thread " + i + " , nStartPos = " + nStartPos[i] + ", nEndPos = " + nEndPos[i]);
fileSplitterFetch[i].start();
}
// fileSplitterFetch[nPos.length-1] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),
siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),nPos[nPos.length-1],nFileLength,nPos.length-1);
// Utility.log("Thread " + (nPos.length-1) + " , nStartPos = " + nPos[nPos.length-1] + ", nEndPos = " + nFileLength);
// fileSplitterFetch[nPos.length-1].start(); //等待子线程结束
//int count = 0;
//是否结束while循环
boolean breakWhile = false; while(!bStop)
{
write_nPos();
Utility.sleep(500);
breakWhile = true; for(int i=0;i<nStartPos.length;i++)
{
if(!fileSplitterFetch[i].bDownOver)
{
breakWhile = false;
break;
}
}
if(breakWhile)
break; //count++;
//if(count>4)
// siteStop();
} System.err.println("文件下载结束!");
}
catch(Exception e){e.printStackTrace ();}
}//获得文件长度
public long getFileSize()
{
int nFileLength = -1;
try{
URL url = new URL(siteInfoBean.getSSiteURL());
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();
httpConnection.setRequestProperty("User-Agent","NetFox"); int responseCode=httpConnection.getResponseCode();
if(responseCode>=400)
{
processErrorCode(responseCode);
return -2; //-2 represent access is error
} String sHeader; for(int i=1;;i++)
{
//DataInputStream in = new DataInputStream(httpConnection.getInputStream ());
//Utility.log(in.readLine());
sHeader=httpConnection.getHeaderFieldKey(i);
if(sHeader!=null)
{
if(sHeader.equals("Content-Length"))
{
nFileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader));
break;
}
}
else
break;
}
}
catch(IOException e){e.printStackTrace ();}
catch(Exception e){e.printStackTrace ();} Utility.log(nFileLength);
return nFileLength;
}//保存下载信息(文件指针位置)
private void write_nPos()
{
try{
output = new DataOutputStream(new FileOutputStream(tmpFile));
output.writeInt(nStartPos.length);
for(int i=0;i<nStartPos.length;i++)
{
// output.writeLong(nPos[i]);
output.writeLong(fileSplitterFetch[i].nStartPos);
output.writeLong(fileSplitterFetch[i].nEndPos);
}
output.close();
}
catch(IOException e){e.printStackTrace ();}
catch(Exception e){e.printStackTrace ();}
}//读取保存的下载信息(文件指针位置)
private void read_nPos()
{
try{
DataInputStream input = new DataInputStream(new FileInputStream(tmpFile));
int nCount = input.readInt();
nStartPos = new long[nCount];
nEndPos = new long[nCount];
for(int i=0;i<nStartPos.length;i++)
{
nStartPos[i] = input.readLong();
nEndPos[i] = input.readLong();
}
input.close();
}
catch(IOException e){e.printStackTrace ();}
catch(Exception e){e.printStackTrace ();}
}private void processErrorCode(int nErrorCode)
{
System.err.println("Error Code : " + nErrorCode);
}//停止文件下载
public void siteStop()
{
bStop = true;
for(int i=0;i<nStartPos.length;i++)
fileSplitterFetch[i].splitterStop();}
}
/*
**FileSplitterFetch.java
*/
package NetFox;import java.io.*;
import java.net.*;
long nStartPos; //File Snippet Start Position
long nEndPos; //File Snippet End Position
int nThreadID; //Thread's ID
boolean bDownOver = false; //Downing is over
boolean bStop = false; //Stop identical
FileAccessI fileAccessI = null; //File Access interface public FileSplitterFetch(String sURL,String sName,long nStart,long nEnd,int id) throws IOException
{
this.sURL = sURL;
this.nStartPos = nStart;
this.nEndPos = nEnd;
nThreadID = id;
fileAccessI = new FileAccessI(sName,nStartPos);
}public void run()
{
while(nStartPos < nEndPos && !bStop)
{
try{
URL url = new URL(sURL);
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();
httpConnection.setRequestProperty("User-Agent","NetFox");
String sProperty = "bytes="+nStartPos+"-";
httpConnection.setRequestProperty("RANGE",sProperty);
Utility.log(sProperty);
InputStream input = httpConnection.getInputStream();
//logResponseHead(httpConnection); byte[] b = new byte[1024];
int nRead;
while((nRead=input.read(b,0,1024)) > 0 && nStartPos < nEndPos && !bStop)
{
nStartPos += fileAccessI.write(b,0,nRead);
//if(nThreadID == 1)
// Utility.log("nStartPos = " + nStartPos + ", nEndPos = " + nEndPos);
} Utility.log("Thread " + nThreadID + " is over!");
bDownOver = true;
//nPos = fileAccessI.write (b,0,nRead);
}
catch(Exception e){e.printStackTrace ();}
}
}//打印回应的头信息
public void logResponseHead(HttpURLConnection con)
{
for(int i=1;;i++)
{
String header=con.getHeaderFieldKey(i);
if(header!=null)
//responseHeaders.put(header,httpConnection.getHeaderField(header));
Utility.log(header+" : "+con.getHeaderField(header));
else
break;
}
}public void splitterStop()
{
bStop = true;
}
}/*
**FileAccess.java
*/
package NetFox;
import java.io.*;public class FileAccessI implements Serializable{ RandomAccessFile oSavedFile;
long nPos; public FileAccessI() throws IOException
{
this("",0);
} public FileAccessI(String sName,long nPos) throws IOException
{
oSavedFile = new RandomAccessFile(sName,"rw");
this.nPos = nPos;
oSavedFile.seek(nPos);
} public synchronized int write(byte[] b,int nStart,int nLen)
{
int n = -1;
try{
oSavedFile.write(b,nStart,nLen);
n = nLen;
}
catch(IOException e)
{
e.printStackTrace ();
} return n;
}
}/*
**SiteInfoBean.java
*/
package NetFox;public class SiteInfoBean {
private String sSiteURL; //Site's URL
private String sFilePath; //Saved File's Path
private String sFileName; //Saved File's Name
private int nSplitter; //Count of Splited Downloading File public SiteInfoBean()
{
//default value of nSplitter is 5
this("","","",5);
} public SiteInfoBean(String sURL,String sPath,String sName,int nSpiltter)
{
sSiteURL= sURL;
sFilePath = sPath;
sFileName = sName;
this.nSplitter = nSpiltter;
} public String getSSiteURL()
{
return sSiteURL;
} public void setSSiteURL(String value)
{
sSiteURL = value;
} public String getSFilePath()
{
return sFilePath;
} public void setSFilePath(String value)
{
sFilePath = value;
} public String getSFileName()
{
return sFileName;
} public void setSFileName(String value)
{
sFileName = value;
} public int getNSplitter()
{
return nSplitter;
} public void setNSplitter(int nCount)
{
nSplitter = nCount;
}
}/*
**Utility.java
*/
package NetFox;
public class Utility {
public Utility()
{
}
public static void sleep(int nSecond)
{
try{
Thread.sleep(nSecond);
}
catch(Exception e)
{
e.printStackTrace ();
}
}public static void log(String sMsg)
{
System.err.println(sMsg);
}public static void log(int sMsg)
{
System.err.println(sMsg);
}
}
/*
**TestMethod.java
*/
package NetFox;
public class TestMethod {
public TestMethod()
{ ///xx/weblogic60b2_win.exe
try{
SiteInfoBean bean = new SiteInfoBean("http://localhost/xx/weblogic60b2_win.exe";;,"L:\temp","weblogic60b2_win.exe",5);
//SiteInfoBean bean = new SiteInfoBean(" http://localhost:8080/down.zip";;,"L:\temp","weblogic60b2_win.exe",5);
SiteFileFetch fileFetch = new SiteFileFetch(bean);
fileFetch.start();
}
catch(Exception e){e.printStackTrace ();}
}
public static void main(String[] args)
{
new TestMethod();
}
}