이 기사에서는 Java의 기존 사용 가능한 라이브러리를 사용하여 FTP 클라이언트 코드를 작성하고 애플릿 컨트롤로 개발하여 웹을 기반으로 대형 파일을 업로드하고 다운로드하는 방법을 소개합니다. 이 기사는 일련의 FTP 고객 라이브러리를 기반으로 진행 막대, 중단 점 연속, 내부 및 외부 네트워크 매핑 및 애플릿의 콜백 JavaScript 기능과 같은보다 일반적이고 강력한 J-FTP 라이브러리 중 하나에 대한 자세한 설명 및 코드 구현을 제공합니다. 이 기사가 Jade를 유치하는 데 중요한 역할을하기를 희망합니다.
1. 소개
프로젝트를 구현하는 동안 웹 기반 파일 업로드 및 다운로드 요구 사항이 등장했습니다. 주 (또는 전국)의 사용자는 특정 센터의 파일 서버에 일부 파일을 업로드해야합니다. 이 문서는 일부 대규모 엔지니어링 건설에 사용되며, 여기에는 수천만 또는 수억 건의 위안의 건설 프로젝트가 포함될 수 있습니다. 파일에는 세 가지 특성이 있습니다. 하나는 파일이 크고 50m에이를 수 있다는 것입니다. 두 번째는 파일 수가 크고 약 15 일 수 있다는 것입니다. 세 번째는 데이터 보안 측면에서 디지털 서명 및 데이터 암호화가 필요하다는 것입니다.
우선, HTTP 기반 전송 방법을 고려하십시오. 그러나 비교를 통해 위의 요구가 충족되었다는 것을 빨리 발견했습니다.
1 : HTTP 프로토콜을 사용한 업로드는 웹 프로그래밍 편의성에 더 적합한 것 같습니다. 1m 미만의 파일 업로드는 FTP 프로토콜을 사용하여 파일을 업로드하는 것보다 약간 빠릅니다. 그러나 배치와 큰 파일의 전송에 대해서는 아무것도 할 수 없습니다. 물론 FTP와 달리 서버 측에서 FTP 서비스를 시작 해야하는 장점도 있습니다.
2 : FTP 프로토콜을 사용하여 1m보다 큰 파일이있는 파일 업로드는 HTTP보다 빠릅니다. 파일이 클수록 업로드 속도는 HTTP 업로드 속도보다 몇 배 빠릅니다. 그리고 Java의 프로그램 작성; FTP는 HTTP보다 편리합니다.
저자는 한때 VB를 사용하고 Batch 파일을 업로드하고 다운로드하기 위해 ActiveX 컨트롤을 작성했으며 그 기능도 매우 강력합니다. CAB 파일 또는 OCX 용 특수 디지털 서명이 없으므로 안전한 사이트 설정, 클라이언트의 보안 수준 감소 등과 같은 클라이언트에 대한 지루한 설정을 수행해야합니다. 일부 솔루션이 포기되었습니다.
동시에 파일을 클라이언트에 디지털로 서명하고 암호화해야한다는 점을 고려할 때 애플릿을 사용하여 구현하기로 결정했습니다. . 파일을 업로드하기 전에 로컬 Usbkey 키 정보를 클라이언트로부터 얻으려면 업로드 된 파일의 암호화 및 서명 처리를 완료 할 수 있습니다. 애플릿을 사용하려면 클라이언트에 JRE 런타임 환경을 설치해야하므로 클라이언트의 관리 및 사용에 약간의 불편 함을 불러 일으키려면 많은 파일 및 파일의 보안을 비교하는 것이 비교적 작은 가격 일 수 있습니다.
운영 환경을 요약하려면 :
FTP 서버 측 : 전문 FTP 서버 측 프로그램 인 Serv-U는 인터넷에 기성품 소프트웨어 다운로드가 있습니다. 물론 독자는 설명 할 서버 측 FTP 파일 수신 프로그램을 작성할 수도 있습니다. 특별한 요구 사항이나 기능이없는 경우 Serv-U는 일반적인 업로드 및 다운로드 요구를 충족시킬 수 있어야합니다.
클라이언트 : Java Applet, Java 인기를 얻은 기술인 Java Applet은 Microsoft의 ActiveX와 비교할 수 있다고 주장했습니다. 물론, 이제 Java는 Java FX를 가지고 있습니다. 애플릿을 대신할까요?
응용 프로그램 환경 : 인터넷, 궁극적 인 목적.
2. Java FTP 클라이언트 라이브러리 선택
시나리오를 상상해 보겠습니다. 원격 컴퓨터에서 실행되는 FTP 서버에서 파일을 업로드하고 다운로드하는 순수한 Java 응용 프로그램을 작성하고 싶습니다. 또한 파일 이름, 데이터 또는 파일 크기와 같은 원격 파일의 기본 파일 정보를 다운로드 할 수 있습니다.
FTP 프로토콜 핸들러를 처음부터 작성하는 것이 가능하고 흥미로울 수 있지만, 작업은 어렵고 길고 잠재적으로 위험합니다. 우리는 그러한 가공 프로그램을 작성하는 데 시간, 에너지 또는 돈을 쓰지 않기 때문에 이미 존재하는 재사용 가능한 구성 요소로 전환합니다. 그리고 많은 라이브러리가 온라인으로 제공됩니다.
우리의 요구에 맞는 훌륭한 Java FTP 클라이언트 라이브러리를 찾는 것은 간단하지 않습니다. 반대로 이것은 매우 고통스럽고 복잡한 작업입니다. 먼저 FTP 클라이언트 라이브러리를 찾는 데 시간이 걸립니다. 둘째, 기존 라이브러리를 모두 찾은 후 어떤 라이브러리를 선택해야합니까? 각 라이브러리는 다른 요구에 적합합니다. 이 라이브러리는 성능이 동일하지 않으며 설계에 근본적인 차이가 있습니다. 각 라이브러리에는 고유 한 특성이 있으며이를 설명하기 위해 다른 용어를 사용합니다. 따라서 FTP 클라이언트 라이브러리를 평가하고 비교하는 것은 어려운 작업입니다.
재사용 가능한 구성 요소를 사용하는 것은 옹호 된 접근법이지만이 경우에는 종종 처음에 낙담합니다. 나중에 조금 부끄러워 할 수도 있습니다. 좋은 FTP 라이브러리를 선택한 후에는 후속 작업이 매우 간단합니다. 간단한 규칙을 따르십시오. 현재 SimpleFTP, J-FTP 등과 같은 많은 공개 및 무료 FTP 클라이언트 라이브러리 및 기타 많은 FTPClients가 있습니다. 다음 표에서 볼 수 있듯이 테이블을 모두 나열 할 수는 없습니다. 독자에게 더 나은 클라이언트 FTP 클래스 라이브러리가있는 경우 추가 보충제를 작성하십시오.
이 기사에서 저자는 J-FTP를 채택합니다. 이것은 오픈 소스이며 매우 강력한 클라이언트 FTP 라이브러리입니다. 저자는 그것을 매우 좋아하고 모든 독자에게도 권장합니다. 무료로 잊어 버리고 광고를 만드십시오.
3. 기본 기능
1. 로그인
FTP는 파일 전송에 사용되지만 본질적으로 java.net.socket은 통신에 사용됩니다. 다음 코드는 클래스 net.sf.jftp.net.ftpconnection의 로그인 방법 중 하나입니다. 물론, 레이아웃을 저장하고 다음 코드에서 일부 원칙을 명확하게 설명하기 위해 저자는 로그 및 기타 코드와 같은 불필요한 코드를 제거했습니다. 전체 코드는 J-FTP의 소스 코드 또는 저자의 예제 소스 코드를 참조하십시오. 다음 코드 예제는 동일합니다.
public int login (문자열 사용자 이름, 문자열 비밀번호) {this.username = username; this.password = 비밀번호; int status = login_ok; JCON = 새로운 jconnection (호스트, 포트); if (jcon.isthere ()) {in = jcon.getReader (); if (getline (긍정적) == null) // ftp220_service_ready) == null) {ok = false; 상태 = 오프라인; } if (! getline (loginack) .startSwith (at at attorm)) // ftp230_logged_in)) {if (success (positive)) // ftp230_logged_in) {} else {ok = false; 상태 = 잘못된 _login_data; }}} else {if (msg) {log.debug ( "ftp 사용할 수 없음!"); OK = FALSE; 상태 = generic_failed; }} if (ok) {Connected = true; 체계(); binary (); 문자열 [] advsettings = 새 문자열 [6]; if (getostype (). indexof ( "os/2")> = 0) {list_default = "list"; } if (list.equals ( "default")) {// 첫 번째 항목을 가져옵니다 (어쨌든 첫 번째는 // ftp list 명령) advsettings = loadset.loadset (settings.adv_settings); // *** 파일을 찾을 수없는 경우, 그것을 만들고 list_default if (advsettings == null) {list = list_default; SaveSet S = New Saveset (settings.adv_settings, list); } else {list = advsettings [0]; if (list == null) {list = list_default; }}} if (getostype (). indexof ( "mvs")> = 0) {list = "list"; } // *** FireDirectoryUpdate (this); FireConnectioninitialized (this); } else {fireConnectionFailed (this, new Integer (상태) .toString ()); } 반환 상태; } 이 로그인 방법에는 소켓 소켓을 설정하는 JConnection 클래스가 있습니다. 동시에이 클래스는 별도의 스레드입니다. 장점은 인터페이스 변경과 협력하기 위해 네트워크 소켓 연결 및 기타 작업이 별도의 스레드로 처리되며 이는 인터페이스의 친근감에 도움이된다는 것입니다. 아래는 net.sf.jftp.net.jconnection 클래스의 실행 방법입니다. 물론,이 스레드의 시작은 jconnection 클래스의 생성자에서 시작됩니다.
public void run () {try {s = new Socket (호스트, 포트); localport = s.getLocalport (); // if (time> 0) s.setSotimeout (시간); out = new PrintStream (new bufferedOutputStream (s.getoutPutStream (), settings.buffersize); in = new bufferedReader (new inputStreamReader (s.getInputStream ()), settings.buffersize); isok = true; //}} catch (예외) {ex.printstacktrace (); log.out ( "경고 : 예외로 인해 연결이 닫혔습니다 (" + host + ":" + port + "); isok = false; try {if ((s! = null) &&! s.isclosed ()) {s.close (); } if (out! = null) {out.close (); } if (in! = null) {in.close (); }} catch (예외 ex2) {ex2.printstacktrace (); log.out ( "경고 : 소켓과 스트림을 닫으려고 더 많은 오류가 발생했습니다"); }} 확립 = true; }이 실행 방법의 소켓은 여기에서 두 시스템 간의 통신 엔드 포인트 인 클라이언트 소켓 ( "소켓"이라고도 함)의 이러한 유형의 구현을 설명합니다. 소켓의 실제 작업은 Socketimpl 클래스의 인스턴스에 의해 수행됩니다. 응용 프로그램은 소켓 공장을 구현하여 로컬 방화벽에 적합한 소켓을 만들 수있는 소켓 공장을 변경하여 소켓을 생성합니다. 특정 지침은 JDK5의 API 지침, 바람직하게는 중국어로 참조하십시오. 헤헤.
2 업로드 및 다운로드
파일 업로드는 다중 스레드 및 단일 스레드로 나눌 수 있으며, 단일 스레드 상황에서는 상대적으로 간단하지만 다중 스레드 상황에서는 더 많은 것을 처리하고 더 신중하게해야합니다. 아래는 net.sf.jftp.net.ftpconnection의 업로드 핸들 upload 메소드입니다. 단일 스레드와 멀티 스레드의 두 가지 유형이 고려되었습니다.
public int handlupload (문자열 파일, 문자열 실재) {if (settings.getenableMultitHreading (! settings.getS.getNouploAdMultThreading ())) {log.out ( "이 업로드에 대한 새 스레드 스폰"); ftptransfer t; if (realName! = null) {t = new ftpTransfer (호스트, 포트, getLocalPath (), getCachedPwd (), 파일, 사용자 이름, 암호, 전송 .upload, handler, Realname, CRLF); } else {t = new ftptransfer (호스트, 포트, getLocalPath (), getCachedPwd (), 파일, 사용자 이름, 암호, 송신 .upload, handler, 리스너, CRLF); } lasttransfer = t; return new_transfer_spawned; } else {if (settings.getS.getNouPloadMultitHreading ()) {log.out ( "MultithReading을 업로드했습니다."); } else {log.out ( "멀티 스레딩은 완전히 비활성화되었습니다."); } return (realName == null)? 업로드 (파일) : 업로드 (파일, realName); }} 멀티 스레딩의 경우 별도의 클래스 net.sf.jftp.net.ftptransfer가 있습니다. 물론 멀티 스레딩의 경우이 클래스는 별도의 스레드 여야합니다. jconnection과 유사하게, 스레드의 시작은 생성자에서도 시작됩니다. 실행 방법에서 파일을 읽고 전송합니다.
public void run () {if (handler.getConnection (). get (file) == null) {handler.addConnection (file, this); } else if (! pause) {log.debug ( "이미 전송 :" + 파일); 작업 = 거짓; STAT = 2; 반품; } 부울 haspaued = false; while (pause) {try {runner.sleep (100); if (listeners! = null) {for (int i = 0; i <reaters.size (); i ++) {((ConnectionListener) reater.elementat (i)). updateProgress (파일, 일시 정지, -1); }} if (! work) {if (listeners! = null) {for (int i = 0; i <reater.size (); i ++) {((ConnectionListener) Listeners.elementat (i)). updateProgress (파일, 제거, -1); }}}} catch (예외) {} haspaued = true; } while ((handler.getConnectionsize ()> = settings.getMaxConnections ()) && (handler.getConnectionize ()> 0) && work) {try {stat = 4; Runner.sleep (400); if (! haspaused && (청취자! = null)) {for (int i = 0; i <reaters.size (); i ++) {((ConnectionListener) reater.elementat (i)). updateprogress (파일, 대기, -1); }} else {break; }} catch (예외 예) {ex.printstacktrace (); }} if (! work) {if (listeners! = null) {for (int i = 0; i <reater.size (); i ++) {((ConnectionListener) Listeners.elementat (i)). updateProgress (파일, 제거, -1); }} handler.removeConnection (파일); STAT = 3; 반품; } 시작 = true; try {runner.sleep (settings.ftptransferthreadPause); } catch (예외) {} con = new ftpConnection (호스트, 포트, remotepath, crlf); Con.setConnectionHandler (핸들러); Con.setConnectionListeners (리스너); int status = con.login (사용자, 패스); if (status == ftpConnection.login_ok) {file f = 새 파일 (localPath); con.setlocalpath (f.getabsolutepath ()); if (type.equals (upload)) {if (newName! = null) {transferstatus = con.upload (file, newname); } else {transferstatus = con.upload (파일); }} else {transferstatus = con.download (file, this.newname); }} if (! pause) {handler.removeConnection (파일); }} 다운로드 프로세스는 업로드의 역 프로세스이므로 업로드 방법 및 쓰기 방법과 유사합니다. 어떤 이유로, 코드는 나열되지 않지만 아이디어와 아이디어는 정확히 동일합니다. 독자의 소스 코드를 참조하십시오.
4. 진행률 바
업로드 또는 다운로드 프로세스 중에 프롬프트가 없으면 사용자는 작업이 완료되었는지 또는 작업이 죽었는지 여부를 판단 할 수 없으며 업로드 시간이나 다운로드 시간이 너무 길어서 사용자가 오도하는 경우가 종종 있습니다. 따라서 진행률 표시 줄은 매우 중요하고 실용적입니다.
진행률 표시 줄의 구현은 실제로 매우 간단합니다. 프로그램에서 두 개의 스레드를 여는 것입니다. 첫 번째 스레드는 인터페이스에서 진행률 표시 줄의 값을 동적으로 변경하는 데 사용되며, 두 번째 스레드는 업로드 또는 다운로드 프로세스 중에 루프를 형성합니다. 이 루프에서 8192 바이트와 같은 특정 수의 데이터가 매번 읽습니다. 그런 다음이 데이터를 전달한 후 첫 번째 스레드의 UpdateProgress 메소드를 호출하여 인터페이스 진행률 표시 줄의 값을 업데이트하십시오.
업로드 또는 다운로드 프로세스 중에 (이전 섹션에서 FTPTransfer 클래스의 실행 메소드 참조) Con.upload (File, NewName) 메소드를 볼 수 있습니다. 코드는 다음과 같습니다.
public int upload (문자열 파일, 문자열 realName, inputStream in) {hasuploaded = true; log.out ( "FTP 업로드 시작 :" + this); int 통계; if ((in == null) && new file (file) .isdirectory ()) {shortprogress = true; filecount = 0; basefile = 파일; DataType = DataConnection.putDir; isdirupload = true; stat = uploaddir (파일); 단편 프로그램 = 거짓; //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 (예외) {} fire -eactionFinished (this); FireDirectoryUpdate (this); } try {thread.sleep (500); } catch (예외) {} return stat; }이 방법은 특정 수의 바이트를 업로드하는 데 도움이됩니다. 실제로, 그것을 rawupload 방법이라고합니다. 여기에 나열되어 있지 않습니다. 소스 코드를 참조하십시오. 이 바이트 데이터를 전달한 후 주 스레드의 UpdateProgressBar () 메소드는 FireActionFinished () 메소드를 호출하여 호출됩니다. 실제로 코드는 다음과 같습니다.
보호 된 void updateprogressbar () {int % = (int) (((float) lfilecompletesize / (float) lfilesize) * 100000f); pbfile.setValue ( %); // System.out.println ( "============================================================== pbfile.setString (lfilecompletesize / 1024L + " /" + lfileSize / 1024L + "KB"); 백분율 = (int) (((float) ltotalCompletesize / (float) ltotalsize) * 100000f); pbtotal.setString (ltotalCompletesize / 1024l + " /" + ltotalsize / 1024L + "KB"); pbtotal.setValue ( %); 리 페인트 (); } 위에는 두 개의 진행 막대가 사용됩니다. 첫 번째 진행률 표시 줄은 현재 파일의 업로드 또는 다운로드 진행 상황을 나타내며, 두 번째 진행률 표시 줄은 모든 파일 다운로드 또는 업로드의 진행 상황을 나타냅니다. 동시에,보다 명백한 진행 또는 진행 상황을 생성하기 위해 진행률 표시 줄의 최대 값은 PBFile.setMaximum (10000) 및 PBTOTAL.SETMAXIMUM (10000)으로 10,000으로 설정합니다. 저자는 때때로 업로드하거나 다운로드 할 때 네트워크 이유로 인해 변경 사항이 비교적 작을 수 있기 때문에 이것이 더 좋다고 생각합니다. 100으로 설정되면 변경 사항은 특별히 분명하지 않습니다.
위는 큰 배치의 FTP 파일을 업로드하고 다운로드하기위한 기본 기사입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.