Este artículo presenta cómo usar bibliotecas disponibles existentes en Java para escribir el código de cliente FTP y desarrollarlo en controles de applets para hacer controles por lotes, carga de archivos grandes y descarga de controles basados en la web. Basado en una serie de bibliotecas de clientes FTP, el artículo proporciona explicaciones detalladas e implementaciones de código en una de las bibliotecas J-FTP más comunes y potentes, como barras de progreso, continuación de punto de ruptura, mapeo de redes internas y externas, y las funciones de JavaScript de devolución de llamada en Applet. Se espera que este artículo juegue un papel en la atraer el jade.
1. Introducción
Durante la implementación de un proyecto, ha surgido un requisito de carga y descarga de archivos basado en la web. Los usuarios de la provincia (o en todo el país) deben cargar algunos archivos en el servidor de archivos en un centro determinado. Estos documentos se utilizan para una construcción de ingeniería a gran escala, que pueden involucrar proyectos de construcción por valor de decenas de millones o incluso cientos de millones de yuanes. Los archivos tienen tres características distintas: una es que el archivo es grande, que puede alcanzar 50 m; El segundo es que el número de archivos es grande, que puede ser de aproximadamente 15; El tercero es que se requieren firmas digitales y cifrado de datos en términos de seguridad de datos.
En primer lugar, considere el método de transmisión basado en HTTP. Sin embargo, a través de la comparación, rápidamente descubrí que las necesidades anteriores se cumplían:
1: La carga utilizando el protocolo HTTP parece ser más adecuado para la conveniencia de la programación web; Cargar archivos menos de 1 m es un poco más rápido que cargar archivos utilizando el protocolo FTP. Pero puede que no haya nada que hacer sobre la transferencia de lotes y archivos grandes. Por supuesto, también tiene sus ventajas, como a diferencia de FTP, es necesario iniciar un servicio FTP en el lado del servidor.
2: Cargar archivos con archivos mayores de 1m usando el protocolo FTP es más rápido que HTTP. Cuanto más grande sea el archivo, la velocidad de carga será varias veces más rápida que la velocidad de carga HTTP. Y escribir programas en Java; FTP es más conveniente que HTTP.
El autor una vez usó VB y escribió controles ActiveX para cargar y descargar archivos por lotes, y sus funciones también son muy potentes. Es solo que, dado que no hay una firma digital especial para los archivos CAB u OCX, es necesario realizar una configuración tediosa para el cliente, como configurar un sitio seguro, reducir el nivel de seguridad del cliente, etc., se han abandonado algunas soluciones.
Al mismo tiempo, teniendo en cuenta que los archivos deben firmarse digitalmente y encriptarlo en el cliente, se decidió usar el applet para implementarlos. . Antes de cargar el archivo, la información local de la clave USBKEY se puede obtener del cliente para completar el cifrado y el procesamiento de firma del archivo cargado. Aunque el uso de Applet requiere la instalación del entorno de tiempo de ejecución JRE en el cliente, lo que aporta algunos inconvenientes a la administración y el uso del cliente, puede ser un precio relativamente pequeño para comparar la seguridad de una cantidad tan grande de archivos y archivos.
Para resumir el entorno operativo:
FTP Side Side: Serv-U, un programa profesional del lado del servidor FTP, hay descargas de software preparadas en Internet, por supuesto, los lectores también pueden escribir un programa de recepción de archivos FTP del lado del servidor para explicar. Si no hay requisitos o funciones especiales, Serv-U debería poder satisfacer nuestras necesidades generales de carga y descarga;
Cliente: Java Applet, una tecnología que hizo popular Java en ese entonces, afirmaba ser comparable a ActiveX de Microsoft. Por supuesto, ahora Java tiene Java FX. ¿Es un sustituto del applet?
Entorno de aplicación: Internet, propósito final.
2. Elección de la biblioteca de clientes Java FTP
Imaginemos un escenario: queremos escribir una aplicación Java pura que cargue y descarga archivos de un servidor FTP que se ejecuta en una computadora remota; También queremos obtener información básica del archivo para esos archivos remotos para descargar, como el nombre del archivo, los datos o el tamaño del archivo.
Si bien es posible y quizás interesante escribir un controlador de protocolo FTP desde cero, el trabajo también es difícil, largo y potencialmente peligroso. Debido a que no estamos dispuestos a gastar tiempo, energía o dinero en escribir dicho programa de procesamiento nosotros mismos, recurrimos a componentes reutilizables que ya existen. Y muchas bibliotecas están disponibles en línea.
Encontrar una excelente biblioteca de clientes Java FTP que se adapte a nuestras necesidades no es tan simple como parece. Por el contrario, esta es una tarea muy dolorosa y complicada. Primero, lleva algún tiempo encontrar una biblioteca de clientes FTP. En segundo lugar, después de encontrar todas las bibliotecas existentes, ¿cuál deberíamos elegir? Cada biblioteca es adecuada para diferentes necesidades. Estas bibliotecas no son equivalentes en el rendimiento y tienen diferencias fundamentales en su diseño. Cada biblioteca tiene sus propias características y utiliza diferentes términos para describirlas. Por lo tanto, evaluar y comparar bibliotecas de clientes FTP es una tarea difícil.
El uso de componentes reutilizables es un enfoque defendido, pero en este caso a menudo es desalentador al principio. Más tarde, podría estar un poco avergonzado: después de elegir una buena biblioteca FTP, el trabajo posterior es muy simple, solo siga las reglas simples. En la actualidad, hay muchas biblioteca de clientes FTP pública y gratuita, como SimpleFTP, J-FTP, etc. y muchos otros FTPClients. Como se muestra en la siguiente tabla, la tabla no se puede enumerar todo. Si los lectores tienen una mejor biblioteca de clases FTP Client, haga suplementos adicionales.
En este artículo, el autor adopta J-FTP. Este es un código abierto y una biblioteca FTP de cliente muy potente. Al autor le gusta mucho, y también lo recomienda a todos los lectores. Olvídalo gratis y haz un anuncio para ello.
3. Funciones básicas
1. Iniciar sesión
FTP se usa para la transferencia de archivos, pero en esencia, java.net.socket se utiliza para la comunicación. El siguiente código es solo uno de los métodos de inicio de sesión de la clase net.sf.jftp.net.ftpconnection. Por supuesto, para guardar el diseño y explicar algunos principios claramente en el siguiente código, el autor ha eliminado algunos códigos innecesarios, como registros y otros códigos. Para el código completo, consulte el código fuente de J-FTP o el código fuente de ejemplo del autor. Los siguientes ejemplos de código son los mismos:
public int login (String UserName, String Password) {this.Username = username; this.password = contraseña; int status = login_ok; jcon = new JConnection (host, puerto); if (jcon.sthere ()) {in = jcon.getReader (); if (getLine (positivo) == null) // ftp220_service_ready) == null) {ok = false; estado = fuera de línea; } if (! getLine (loginack) .Startswith (positivo)) // ftp230_logged_in)) {if (strace (positive)) // ftp230_logged_in)) {} else {ok = false; status = Wrong_login_data; }}} else {if (msg) {log.debug ("ftp no disponible!"); OK = falso; status = genic_failed; }} if (ok) {conectado = true; sistema(); binario(); Cadena [] advSettings = nueva cadena [6]; if (getOSType (). indexOf ("OS/2")> = 0) {list_default = "list"; } if (list.equals ("predeterminado")) {// Simplemente obtenga el primer elemento (de alguna manera sabe que primero es el comando // ftp list) advSettings = loadset.loadSet (settings.Adv_Settings); // *** Si no se encuentra el archivo, cree y configúrelo en 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 (esto); FirEConnectionInitialized (esto); } else {FireConnectionFailed (this, nuevo entero (status) .ToString ()); } estado de retorno; } En este método de inicio de sesión, hay una clase JConnection, que es responsable de establecer sockets. Al mismo tiempo, esta clase es un hilo separado. La ventaja es que para cooperar con los cambios en la interfaz, las conexiones de socket de red y otras tareas se procesan como hilos separados, que conducen a la amistad de la interfaz. A continuación se muestra el método Ejecutar de la clase net.sf.jftp.net.jconnection. Por supuesto, el inicio de este hilo se inicia en el constructor de la clase JConnection.
public void run () {try {s = new Socket (host, puerto); localport = s.getLocalport (); // if (tiempo> 0) S.SetSotimeOut (tiempo); out = new PrintStream (new BufferedOutputStream (s.getOutputStream (), settings.bufferSize)); in = new BufferedReader (new InputStreamReader (s.getInputStream ()), settings.bufferSize); isok = verdadero; //}} Catch (Exception Ex) {Ex.PrintStackTrace (); Log.out ("Advertencia: conexión cerrada debido a la excepción (" + host + ":" + puerto + ")"); isok = falso; intente {if ((s! = null) &&! s.isclosed ()) {s.close (); } if (out! = null) {out.close (); } if (in! = null) {in.close (); }} capt (excepción ex2) {ex2.printstackTrace (); Log.out ("Advertencia: obtuve más errores tratando de cerrar el socket y las transmisiones"); }} establecido = true; }El socket en este método de ejecución explicará aquí que este tipo de implementación de sockets de cliente (también llamados "sockets"), que son puntos finales de comunicación entre dos máquinas. El trabajo real del socket se realiza mediante una instancia de la clase SocketiMPL. Una aplicación implementa una fábrica de socket que crea enchufes cambiando la fábrica de socket que puede configurarse para crear enchufes que sean adecuados para el firewall local. Para obtener instrucciones específicas, consulte las instrucciones API de JDK5, preferiblemente en chino. jeje.
2 Subir y descargar
La carga de archivos se puede dividir en múltiples subprocesos y de un solo subproceso, que es relativamente simple en situaciones de un solo hilo, mientras que en situaciones de múltiples subprocesos, más cosas para manejar y más cuidadosas. A continuación se muestra el método de carga HandleUpload de net.sf.jftp.net.ftpconnection. Se han considerado dos tipos diferentes, un solo hilo y subprocesos múltiples.
public int handleupload (string file, string realName) {if (settings.getenableMultithreading () && (! settings.getNoUploadMultithReading ())) {log.out ("desove un nuevo hilo para esta carga."); Ftptransfer t; if (RealName! = NULL) {t = new ftptransfer (host, puerto, getLocalPath (), getCachedPwd (), archivo, nombre de usuario, contraseña, transferencia. } else {t = new ftptransfer (host, puerto, getLocalPath (), getCachedPwd (), archivo, nombre de usuario, contraseña, transferencia. } lasttransfer = t; return new_transfer_spawned; } else {if (settings.getNoUploAdMultithReading ()) {log.out ("cargar múltiple está deshabilitado."); } else {log.out ("múltiples listas está completamente deshabilitada"); } return (realName == null)? cargar (archivo): upload (archivo, realName); }} En el caso de múltiples subprocesos, hay una clase separada net.sf.jftp.net.ftptransfer. Por supuesto, en el caso de múltiples subprocesos, esta clase debe ser un hilo separado. Similar a JConnection, el inicio de su hilo también se inicia en el constructor. En su método de ejecución, el archivo se lee y transmite.
public void run () {if (handler.getConnections (). get (file) == null) {handler.addconnection (archivo, this); } else if (! pause) {log.debug ("transferir ya en progreso:" + archivo); trabajo = falso; stat = 2; devolver; } boolean haspAused = false; while (pausa) {try {runner.sleep (100); if (oyentes! = nulo) {for (int i = 0; i <oyeers.size (); i ++) {((ConnectionListener) oyentes.elementat (i)). updateProgress (archivo, pause, -1); }} if (! Work) {if (oyentes! = null) {for (int i = 0; i <oyeers.size (); i ++) {((ConnectionListener) oyentes.elementat (i)). updateProgress (archivo, eliminado, -1); }}}} capt (excepción ex) {} HaspAused = true; } while ((handler.getConnectionSize ()> = settings.getMaxConnections ()) && (handler.getConnectionSize ()> 0) && work) {try {stat = 4; Runner.Sleep (400); if (! HaspAused && (oyentes! = nulo)) {for (int i = 0; i <oyentes.size (); i ++) {((ConnectionListener) oyentes }} else {break; }} capt (excepción ex) {ex.printstackTrace (); }} if (! Work) {if (oyentes! = null) {for (int i = 0; i <oyeers.size (); i ++) {((ConnectionListener) oyentes.elementat (i)). updateProgress (archivo, eliminado, -1); }} handler.removeconnection (archivo); stat = 3; devolver; } inicio = verdadero; intente {runner.sleep (settings.ftptransferthreadpause); } capt (excepción ex) {} con = nueva ftpconnection (host, puerto, remotaPath, CRLF); con.setConnectionHandler (Handler); con.setConnectionListeners (oyentes); int status = con.login (usuario, pase); if (status == ftpconnection.login_ok) {archivo f = nuevo archivo (localpath); con.setLocalPath (f.getabsolutePath ()); if (type.equals (upload)) {if (newname! = null) {transferstatus = con.upload (archivo, newname); } else {transferstatus = con.upload (archivo); }} else {transferstatus = con.download (archivo, this.newname); }} if (! Pause) {handler.removeconnection (archivo); }} En cuanto al proceso de descarga, debido a que es un proceso inverso de carga, es similar al método de carga y el método de escritura. Por algunas razones, el código no figura en la lista, pero sus ideas e ideas son exactamente las mismas. Consulte el código fuente para los lectores.
4. Barra de progreso
Se puede imaginar que si no hay un mensaje durante el proceso de carga o descarga, el usuario no puede juzgar si la tarea se completa o si la tarea está muerta, y el usuario a menudo es engañoso debido a que el tiempo de carga o el tiempo de descarga son demasiado largos. Por lo tanto, la barra de progreso es muy importante y práctica.
La implementación de la barra de progreso es en realidad muy simple. Es para abrir dos hilos en el programa. El primer hilo se usa para cambiar dinámicamente el valor de la barra de progreso en la interfaz, mientras que el segundo subproceso forma un bucle durante el proceso de carga o descarga. En este bucle, se leen un cierto número de datos como 8192 bytes cada vez. Luego, después de pasar estos datos, llame al método UpdateProgress en el primer hilo para actualizar el valor de la barra de progreso de la interfaz.
Durante el proceso de carga o descarga (consulte el método Ejecutar de la clase FTPTransfer en la sección anterior), puede ver el método Con.upload (archivo, Newname), el código es el siguiente.
public int upload (archivo de cadena, string realName, inputStream in) {Hasuploaded = true; Log.out ("ftp cargando iniciado:" + this); int stat; if ((in == null) && new File (archivo) .IsDirectory ()) {shortProgress = true; fileCount = 0; basefile = archivo; DataType = dataConnection.putDir; isDirupload = true; stat = uploadDir (archivo); ShortProgress = false; //System.out.println(filecount + ":" + basefile); FirProgressUpdate (BaseFile, DataConnection.dfinished + ":" + FileCount, -1); Fuegofinado (esto); FiredIrectoryUpdate (esto); } else {datatype = dataConnection.put; stat = rawUpload (archivo, realName, in); intente {thread.sleep (100); } catch (excepción ex) {} FireActionFinishished (esto); FiredIrectoryUpdate (esto); } try {thread.sleep (500); } catch (excepción ex) {} return stat; }Este método es responsable de cargar un cierto número de bytes. De hecho, se llama el método Rawupload. No se enumera aquí. Consulte el código fuente. Después de pasar estos datos de byte, el método UpdateProgressBar () en el hilo principal se llama llamando al método FireActionFinished (). En realidad, el código es el siguiente:
Proteged Void UpdateProgressBar () {int porcent. pbfile.setValue (porcentaje); // System.out.println ("=================================================="+por ciento); pbfile.setString (lFileCompletesize / 1024l + " /" + lfilesize / 1024l + "kb"); porcentaje = (int) ((((float) ltotalCompleteSize / (float) ltotalSize) * 10000f); pbtotal.setString (ltotalcompletesize / 1024l + " /" + ltotalSize / 1024l + "kb"); pbtotal.setValue (porcentaje); repintado (); } Se usan dos barras de progreso arriba. La primera barra de progreso representa el progreso de carga o descarga del archivo actual, y la segunda barra de progreso representa el progreso de todos los archivos descarga o carga. Al mismo tiempo, para generar una progresión o cambio de progreso más obvio, el valor máximo de la barra de progreso se establece en 10,000 a través de pbfile.setMaximum (10000) y pbtotal.setMaximum (10000), en lugar de los 100 que generalmente establecemos. El autor cree que esto es mejor, porque a veces al cargar o descargar, los cambios pueden ser relativamente pequeños debido a las razones de la red. Si se establece en 100, el cambio no es particularmente obvio.
El anterior es el artículo básico para cargar y descargar grandes lotes de archivos FTP. Espero que sea útil para el aprendizaje de todos, y espero que todos apoyen más a Wulin.com.