Java implementation of FTP server function instance code

  • 2020-04-01 04:29:52
  • OfStack

FTP(File Transfer Protocol) is a Protocol used to Transfer files over the Internet. You can Upload or Download files on the Internet via an FTP server. FTP is the real-time online service, before using it must be with the service of a user (user name and password), work the client have to login to the server side of the machine, after the user login to file search and file transfer and related operations, such as changing the current working directory, file directory, set the transmission parameters and file transfer, etc. FTP can be used to transfer all types of files, such as text files, binary executable files, image files, sound files, and data compression files.

The FTP command

The main operations of FTP are based on various commands. Common commands are:
Set the transfer mode, it include ASC Ⅱ (text) and BINARY BINARY mode;
Directory operation to change or display the current directory of the remote computer (CD, dir/ls command);
Connection operation. The open command is used to establish a connection to the remote computer. The close command is used to close the connection;
The send operation, the put command is used to transfer files to a remote computer. The mput command is used to transfer multiple files to a remote computer.
The get command is used to receive a file. The mget command is used to receive multiple files.


import java.net.Socket; 
import org.apache.log4j.Logger; 
 
public class ServerA{ 
  public static void main(String[] args){ 
    final String F_DIR = "c:/test";//Root path
    final int PORT = 22;//Monitor port number
    Logger.getRootLogger(); 
    Logger logger = Logger.getLogger("com"); 
    try{ 
      ServerSocket s = new ServerSocket(PORT); 
      logger.info("Connecting to server A..."); 
      logger.info("Connected Successful! Local Port:"+s.getLocalPort()+". Default Directory:'"+F_DIR+"'."); 
      while( true ){ 
        //Accept client requests
        Socket client = s.accept(); 
        //Create a service thread
        new ClientThread(client, F_DIR).start(); 
      } 
    } catch(Exception e) { 
      logger.error(e.getMessage()); 
      for(StackTraceElement ste : e.getStackTrace()){ 
        logger.error(ste.toString()); 
      } 
    } 
  } 
} 
import java.io.BufferedReader;  
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.OutputStream; 
import java.io.PrintWriter; 
import java.io.RandomAccessFile; 
import java.net.ConnectException; 
import java.net.InetAddress; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.net.UnknownHostException; 
import java.nio.charset.Charset; 
import java.util.Random; 
import org.apache.log4j.Logger; 
 
public class ClientThread extends Thread { 
  private Socket socketClient;//The client socket
  private Logger logger;//The log object
  private String dir;//An absolute path
  private String pdir = "/";//Relative paths
  private final static Random generator = new Random();//The random number
  public ClientThread(Socket client, String F_DIR){ 
    this.socketClient = client; 
    this.dir = F_DIR; 
  } 
  @Override 
  public void run() { 
    Logger.getRootLogger(); 
    logger = Logger.getLogger("com"); 
    InputStream is = null; 
    OutputStream os = null; 
    try { 
      is = socketClient.getInputStream(); 
      os = socketClient.getOutputStream(); 
    } catch (IOException e) { 
      logger.error(e.getMessage()); 
      for(StackTraceElement ste : e.getStackTrace()){ 
        logger.error(ste.toString()); 
      } 
    } 
    BufferedReader br = new BufferedReader(new InputStreamReader(is, 
        Charset.forName("UTF-8"))); 
    PrintWriter pw = new PrintWriter(os); 
    String clientIp = socketClient.getInetAddress().toString().substring(1);//Record client IP
    String username = "not logged in";//The user name
    String password = "";//password
    String command = "";//The command
    boolean loginStuts = false;//The login status
    final String LOGIN_WARNING = "530 Please log in with USER and PASS first."; 
    String str = "";//Command content string
    int port_high = 0; 
    int port_low = 0; 
    String retr_ip = "";//The IP address of the received file
    Socket tempsocket = null; 
    //Print welcome message
    pw.println("220-FTP Server A version 1.0 written by Leon Guo"); 
    pw.flush(); 
    logger.info("("+username+") ("+clientIp+")> Connected, sending welcome message..."); 
    logger.info("("+username+") ("+clientIp+")> 220-FTP Server A version 1.0 written by Leon Guo"); 
    boolean b = true; 
    while ( b ){ 
      try { 
        // Gets input from the user The command
        command = br.readLine(); 
        if(null == command) break; 
      } catch (IOException e) { 
        pw.println("331 Failed to get command"); 
        pw.flush(); 
        logger.info("("+username+") ("+clientIp+")> 331 Failed to get command"); 
        logger.error(e.getMessage()); 
        for(StackTraceElement ste : e.getStackTrace()){ 
          logger.error(ste.toString()); 
        } 
        b = false; 
      } 
       
      // USERThe command
      if(command.toUpperCase().startsWith("USER")){ 
        logger.info("(not logged in) ("+clientIp+")> "+command); 
        username = command.substring(4).trim();  
        if("".equals(username)){ 
          pw.println("501 Syntax error"); 
          pw.flush(); 
          logger.info("(not logged in) ("+clientIp+")> 501 Syntax error"); 
          username = "not logged in"; 
        } 
        else{ 
          pw.println("331 Password required for " + username); 
          pw.flush(); 
          logger.info("(not logged in) ("+clientIp+")> 331 Password required for " + username); 
        } 
        loginStuts = false; 
      } //end USER 
      // PASSThe command
      else if(command.toUpperCase().startsWith("PASS")){ 
        logger.info("(not logged in) ("+clientIp+")> "+command); 
        password = command.substring(4).trim();  
        if(username.equals("root") && password.equals("root")){ 
          pw.println("230 Logged on"); 
          pw.flush(); 
          logger.info("("+username+") ("+clientIp+")> 230 Logged on"); 
//Logger.info (" client "+clientIp+" by "+username+" user login ");
          loginStuts = true; 
        } 
        else{ 
          pw.println("530 Login or password incorrect!"); 
          pw.flush(); 
          logger.info("(not logged in) ("+clientIp+")> 530 Login or password incorrect!"); 
          username = "not logged in"; 
        } 
      } //end PASS 
      // PWDThe command
      else if(command.toUpperCase().startsWith("PWD")){ 
        logger.info("("+username+") ("+clientIp+")> "+command); 
        if(loginStuts){ 
//Logger.info (" user "+clientIp+" : "+username+" execute PWD command ");
          pw.println("257 /""+pdir+"/" is current directory"); 
          pw.flush(); 
          logger.info("("+username+") ("+clientIp+")> 257 /""+pdir+"/" is current directory"); 
        } 
        else{ 
          pw.println(LOGIN_WARNING); 
          pw.flush(); 
          logger.info("("+username+") ("+clientIp+")> "+LOGIN_WARNING); 
        } 
      } //end PWD 
      // CWDThe command
      else if(command.toUpperCase().startsWith("CWD")){ 
        logger.info("("+username+") ("+clientIp+")> "+command); 
        if(loginStuts){ 
          str = command.substring(3).trim(); 
          if("".equals(str)){ 
            pw.println("250 Broken client detected, missing argument to CWD. /""+pdir+"/" is current directory."); 
            pw.flush(); 
            logger.info("("+username+") ("+clientIp+")> 250 Broken client detected, missing argument to CWD. /""+pdir+"/" is current directory."); 
          } 
          else{ 
            //Determine if the directory exists
            String tmpDir = dir + "/" + str; 
            File file = new File(tmpDir); 
            if(file.exists()){//Directory exists
              dir = dir + "/" + str; 
              if("/".equals(pdir)){ 
                pdir = pdir + str; 
              } 
              else{ 
                pdir = pdir + "/" + str; 
              } 
//Logger.info (" user "+clientIp+" : "+username+" execute CWD command ");
              pw.println("250 CWD successful. /""+pdir+"/" is current directory"); 
              pw.flush(); 
              logger.info("("+username+") ("+clientIp+")> 250 CWD successful. /""+pdir+"/" is current directory"); 
            } 
            else{//Directory does not exist
              pw.println("550 CWD failed. /""+pdir+"/": directory not found."); 
              pw.flush(); 
              logger.info("("+username+") ("+clientIp+")> 550 CWD failed. /""+pdir+"/": directory not found."); 
            } 
          } 
        } 
        else{ 
          pw.println(LOGIN_WARNING); 
          pw.flush(); 
          logger.info("("+username+") ("+clientIp+")> "+LOGIN_WARNING); 
        } 
      } //end CWD 
      // QUITThe command
      else if(command.toUpperCase().startsWith("QUIT")){ 
        logger.info("("+username+") ("+clientIp+")> "+command); 
        b = false; 
        pw.println("221 Goodbye"); 
        pw.flush(); 
        logger.info("("+username+") ("+clientIp+")> 221 Goodbye"); 
        try { 
          Thread.currentThread(); 
          Thread.sleep(1000); 
        } catch (InterruptedException e) { 
          logger.error(e.getMessage()); 
          for(StackTraceElement ste : e.getStackTrace()){ 
            logger.error(ste.toString()); 
          } 
        } 
      } //end QUIT 
       
      //PORT command, transmit data in active mode
      else if(command.toUpperCase().startsWith("PORT")){ 
        logger.info("("+username+") ("+clientIp+")> "+command); 
        if(loginStuts){ 
          try { 
            str = command.substring(4).trim(); 
            port_low = Integer.parseInt(str.substring(str.lastIndexOf(",")+1)); 
            port_high = Integer.parseInt(str.substring(0, str.lastIndexOf(",")) 
                .substring(str.substring(0, str.lastIndexOf(",")).lastIndexOf(",")+1)); 
            String str1 = str.substring(0, str.substring(0, str.lastIndexOf(",")).lastIndexOf(",")); 
            retr_ip = str1.replace(",", "."); 
            try { 
              //Instantiate sockets in active mode
              tempsocket = new Socket(retr_ip,port_high * 256 + port_low); 
//Logger.info (" user "+clientIp+" : "+username+" execute PORT command ");
              pw.println("200 port command successful"); 
              pw.flush(); 
              logger.info("("+username+") ("+clientIp+")> 200 port command successful"); 
            } catch (ConnectException ce) { 
              pw.println("425 Can't open data connection."); 
              pw.flush(); 
              logger.info("("+username+") ("+clientIp+")> 425 Can't open data connection."); 
              logger.error(ce.getMessage()); 
              for(StackTraceElement ste : ce.getStackTrace()){ 
                logger.error(ste.toString()); 
              } 
            } catch (UnknownHostException e) { 
              logger.error(e.getMessage()); 
              for(StackTraceElement ste : e.getStackTrace()){ 
                logger.error(ste.toString()); 
              } 
            } catch (IOException e) { 
              logger.error(e.getMessage()); 
              for(StackTraceElement ste : e.getStackTrace()){ 
                logger.error(ste.toString()); 
              } 
            } 
          } catch (NumberFormatException e) { 
            pw.println("503 Bad sequence of commands."); 
            pw.flush(); 
            logger.info("("+username+") ("+clientIp+")> 503 Bad sequence of commands."); 
            logger.error(e.getMessage()); 
            for(StackTraceElement ste : e.getStackTrace()){ 
              logger.error(ste.toString()); 
            } 
          } 
        } 
        else{ 
          pw.println(LOGIN_WARNING); 
          pw.flush(); 
          logger.info("("+username+") ("+clientIp+")> "+LOGIN_WARNING); 
        } 
      } //end PORT 
      //PASV command, transfer data in passive mode
      else if(command.toUpperCase().startsWith("PASV")) {  
        logger.info("("+username+") ("+clientIp+")> "+command); 
        if(loginStuts){ 
          ServerSocket ss = null; 
          while( true ){ 
            //Gets the server's free port
            port_high = 1 + generator.nextInt(20); 
            port_low = 100 + generator.nextInt(1000); 
            try { 
              //Server bound port
              ss = new ServerSocket(port_high * 256 + port_low); 
              break; 
            } catch (IOException e) { 
              continue; 
            } 
          } 
//Logger.info (" user "+clientIp+" : "+username+" execute PASV command ");
          InetAddress i = null; 
          try { 
            i = InetAddress.getLocalHost(); 
          } catch (UnknownHostException e1) { 
            e1.printStackTrace(); 
          } 
          pw.println("227 Entering Passive Mode ("+i.getHostAddress().replace(".", ",")+","+port_high+","+port_low+")"); 
          pw.flush(); 
          logger.info("("+username+") ("+clientIp+")> 227 Entering Passive Mode ("+i.getHostAddress().replace(".", ",")+","+port_high+","+port_low+")"); 
          try { 
            //Socket in passive mode
            tempsocket = ss.accept(); 
            ss.close(); 
          } catch (IOException e) { 
            logger.error(e.getMessage()); 
            for(StackTraceElement ste : e.getStackTrace()){ 
              logger.error(ste.toString()); 
            } 
          } 
        } 
        else{ 
          pw.println(LOGIN_WARNING); 
          pw.flush(); 
          logger.info("("+username+") ("+clientIp+")> "+LOGIN_WARNING); 
        } 
      } //end PASV 
      //RETRThe command
      else if(command.toUpperCase().startsWith("RETR")){ 
        logger.info("("+username+") ("+clientIp+")> "+command); 
        if(loginStuts){ 
          str = command.substring(4).trim(); 
          if("".equals(str)){ 
            pw.println("501 Syntax error"); 
            pw.flush(); 
            logger.info("("+username+") ("+clientIp+")> 501 Syntax error"); 
          } 
          else { 
            try { 
              pw.println("150 Opening data channel for file transfer."); 
              pw.flush(); 
              logger.info("("+username+") ("+clientIp+")> 150 Opening data channel for file transfer."); 
              RandomAccessFile outfile = null; 
              OutputStream outsocket = null; 
              try { 
                //Creates a stream of randomly accessed files with the specified name that are read from and optionally written to
                outfile = new RandomAccessFile(dir+"/"+str,"r"); 
                outsocket = tempsocket.getOutputStream();  
              } catch (FileNotFoundException e) {  
                logger.error(e.getMessage()); 
                for(StackTraceElement ste : e.getStackTrace()){ 
                  logger.error(ste.toString()); 
                } 
              } catch (IOException e) { 
                logger.error(e.getMessage()); 
                for(StackTraceElement ste : e.getStackTrace()){ 
                  logger.error(ste.toString()); 
                } 
              }  
              byte bytebuffer[]= new byte[1024];  
              int length;  
              try{  
                while((length = outfile.read(bytebuffer)) != -1){  
                  outsocket.write(bytebuffer, 0, length);  
                }  
                outsocket.close();  
                outfile.close();  
                tempsocket.close();  
              }  
              catch(IOException e){ 
                logger.error(e.getMessage()); 
                for(StackTraceElement ste : e.getStackTrace()){ 
                  logger.error(ste.toString()); 
                } 
              } 
//Logger.info (" user "+clientIp+" : "+username+" execute RETR command ");
              pw.println("226 Transfer OK"); 
              pw.flush(); 
              logger.info("("+username+") ("+clientIp+")> 226 Transfer OK"); 
            } catch (Exception e){ 
              pw.println("503 Bad sequence of commands."); 
              pw.flush(); 
              logger.info("("+username+") ("+clientIp+")> 503 Bad sequence of commands."); 
              logger.error(e.getMessage()); 
              for(StackTraceElement ste : e.getStackTrace()){ 
                logger.error(ste.toString()); 
              } 
            } 
          } 
        } 
        else{ 
          pw.println(LOGIN_WARNING); 
          pw.flush(); 
          logger.info("("+username+") ("+clientIp+")> "+LOGIN_WARNING); 
        } 
      }//end RETR 
      //STORThe command
      else if(command.toUpperCase().startsWith("STOR")){  
        logger.info("("+username+") ("+clientIp+")> "+command); 
        if(loginStuts){ 
          str = command.substring(4).trim(); 
          if("".equals(str)){ 
            pw.println("501 Syntax error"); 
            pw.flush(); 
            logger.info("("+username+") ("+clientIp+")> 501 Syntax error"); 
          } 
          else { 
            try { 
              pw.println("150 Opening data channel for file transfer.");  
              pw.flush(); 
              logger.info("("+username+") ("+clientIp+")> 150 Opening data channel for file transfer."); 
              RandomAccessFile infile = null; 
              InputStream insocket = null; 
              try { 
                infile = new RandomAccessFile(dir+"/"+str,"rw"); 
                insocket = tempsocket.getInputStream();  
              } catch (FileNotFoundException e) {  
                logger.error(e.getMessage());  
                for(StackTraceElement ste : e.getStackTrace()){ 
                  logger.error(ste.toString()); 
                } 
              } catch (IOException e) { 
                logger.error(e.getMessage());  
                for(StackTraceElement ste : e.getStackTrace()){ 
                  logger.error(ste.toString()); 
                } 
              }  
              byte bytebuffer[] = new byte[1024];  
              int length;  
              try{ 
                while((length =insocket.read(bytebuffer) )!= -1){  
                  infile.write(bytebuffer, 0, length);  
                } 
                insocket.close();  
                infile.close();  
                tempsocket.close();  
              }  
              catch(IOException e){ 
                logger.error(e.getMessage()); 
                for(StackTraceElement ste : e.getStackTrace()){ 
                  logger.error(ste.toString()); 
                } 
              } 
//Logger.info (" user "+clientIp+" : "+username+" execute STOR command ");
              pw.println("226 Transfer OK"); 
              pw.flush(); 
              logger.info("("+username+") ("+clientIp+")> 226 Transfer OK"); 
            } catch (Exception e){ 
              pw.println("503 Bad sequence of commands."); 
              pw.flush(); 
              logger.info("("+username+") ("+clientIp+")> 503 Bad sequence of commands."); 
              logger.error(e.getMessage()); 
              for(StackTraceElement ste : e.getStackTrace()){ 
                logger.error(ste.toString()); 
              } 
            } 
          } 
        } else { 
          pw.println(LOGIN_WARNING); 
          pw.flush(); 
          logger.info("("+username+") ("+clientIp+")> "+LOGIN_WARNING); 
        } 
      } //end STOR 
      //NLSTThe command
      else if(command.toUpperCase().startsWith("NLST")) {  
        logger.info("("+username+") ("+clientIp+")> "+command); 
        if(loginStuts){ 
          try { 
            pw.println("150 Opening data channel for directory list.");  
            pw.flush(); 
            logger.info("("+username+") ("+clientIp+")> 150 Opening data channel for directory list."); 
            PrintWriter pwr = null; 
            try { 
              pwr= new PrintWriter(tempsocket.getOutputStream(),true); 
            } catch (IOException e1) { 
              e1.printStackTrace(); 
            }  
            File file = new File(dir);  
            String[] dirstructure = new String[10];  
            dirstructure= file.list();  
            for(int i=0;i<dirstructure.length;i++){ 
              pwr.println(dirstructure[i]);  
            } 
            try { 
              tempsocket.close(); 
              pwr.close(); 
            } catch (IOException e) { 
              logger.error(e.getMessage()); 
              for(StackTraceElement ste : e.getStackTrace()){ 
                logger.error(ste.toString()); 
              } 
            }  
//Logger.info (" user "+clientIp+" : "+username+" execute NLST command ");
            pw.println("226 Transfer OK");  
            pw.flush(); 
            logger.info("("+username+") ("+clientIp+")> 226 Transfer OK"); 
          } catch (Exception e){ 
            pw.println("503 Bad sequence of commands."); 
            pw.flush(); 
            logger.info("("+username+") ("+clientIp+")> 503 Bad sequence of commands."); 
            logger.error(e.getMessage()); 
            for(StackTraceElement ste : e.getStackTrace()){ 
              logger.error(ste.toString()); 
            } 
          } 
        }else{ 
          pw.println(LOGIN_WARNING); 
          pw.flush(); 
          logger.info("("+username+") ("+clientIp+")> "+LOGIN_WARNING); 
        } 
      } //end NLST 
      //LISTThe command
      else if(command.toUpperCase().startsWith("LIST")) {  
        logger.info("("+username+") ("+clientIp+")> "+command); 
        if(loginStuts){ 
          try{ 
            pw.println("150 Opening data channel for directory list.");  
            pw.flush(); 
            logger.info("("+username+") ("+clientIp+")> 150 Opening data channel for directory list."); 
            PrintWriter pwr = null; 
            try { 
              pwr= new PrintWriter(tempsocket.getOutputStream(),true); 
            } catch (IOException e) { 
              logger.error(e.getMessage()); 
              for(StackTraceElement ste : e.getStackTrace()){ 
                logger.error(ste.toString()); 
              } 
            }  
            FtpUtil.getDetailList(pwr, dir); 
            try { 
              tempsocket.close(); 
              pwr.close(); 
            } catch (IOException e) { 
              logger.error(e.getMessage()); 
              for(StackTraceElement ste : e.getStackTrace()){ 
                logger.error(ste.toString()); 
              } 
            }  
//Logger.info (" user "+clientIp+" : "+username+" execute the LIST command ");
            pw.println("226 Transfer OK");  
            pw.flush(); 
            logger.info("("+username+") ("+clientIp+")> 226 Transfer OK"); 
          } catch (Exception e){ 
            pw.println("503 Bad sequence of commands."); 
            pw.flush(); 
            logger.info("("+username+") ("+clientIp+")> 503 Bad sequence of commands."); 
            logger.error(e.getMessage()); 
            for(StackTraceElement ste : e.getStackTrace()){ 
              logger.error(ste.toString()); 
            } 
          } 
        } else { 
          pw.println(LOGIN_WARNING); 
          pw.flush(); 
          logger.info("("+username+") ("+clientIp+")> "+LOGIN_WARNING); 
        } 
      } //end LIST 
      //  Enter illegal The command
      else{ 
        logger.info("("+username+") ("+clientIp+")> "+command); 
        pw.println("500 Syntax error, command unrecognized."); 
        pw.flush(); 
        logger.info("("+username+") ("+clientIp+")> 500 Syntax error, command unrecognized."); 
      } 
    } //end while 
    try { 
      logger.info("("+username+") ("+clientIp+")> disconnected."); 
//Logger.info (" user "+clientIp+" : "+username+" exit ");
      br.close(); 
      socketClient.close(); 
      pw.close(); 
      if(null != tempsocket){ 
        tempsocket.close(); 
      } 
    } catch (IOException e) { 
      logger.error(e.getMessage()); 
      for(StackTraceElement ste : e.getStackTrace()){ 
        logger.error(ste.toString()); 
      } 
    } 
  } 
} 
import java.io.File;  
import java.io.PrintWriter; 
import java.text.SimpleDateFormat; 
import java.util.Date; 
 
public class FtpUtil { 
  public static void getDetailList(PrintWriter pw, String path){ 
    File dir = new File(path); 
    if (!dir.isDirectory()) { 
      pw.println("500 No such file or directory./r/n"); 
    } 
    File[] files = dir.listFiles(); 
    String modifyDate; 
    for (int i = 0; i < files.length; i++) { 
      modifyDate = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss") 
          .format(new Date(files[i].lastModified())); 
      if (files[i].isDirectory()) { 
        pw.println("drwxr-xr-x ftp   ftp      0 " 
            + modifyDate + " " + files[i].getName()); 
      } else { 
        pw.println("-rw-r-r--1 ftp   ftp      " 
            + files[i].length() + " " + modifyDate + " " 
            + files[i].getName()); 
      } 
      pw.flush(); 
    } 
    pw.println("total:" + files.length); 
  } 
} 
### set log levels ### 
log4j.logger.com =debug,stdout,D,E 
###  Output to console  ### 
log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
log4j.appender.stdout.Target=System.out 
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n 
##  The output DEBUG Logs above level  
log4j.appender.D=org.apache.log4j.DailyRollingFileAppender 
log4j.appender.D.File=c:/logs/logs.log 
log4j.appender.D.Append =true 
##  The output DEBUG Logs above level  
log4j.appender.D.Threshold=DEBUG 
log4j.appender.D.layout=org.apache.log4j.PatternLayout 
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n 
###  Save the exception information to a separate file  ### 
log4j.appender.E=org.apache.log4j.DailyRollingFileAppender 
##  Exception log file name  
log4j.appender.E.File=c:/logs/errors.log 
log4j.appender.E.Append=true 
##  Only the output ERROR Logs above level !!! 
log4j.appender.E.Threshold=ERROR 
log4j.appender.E.layout=org.apache.log4j.PatternLayout 
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n 

The above content is this site to introduce the Java implementation of FTP server function instance code of the relevant knowledge, I hope you like.


Related articles: