Total Pageviews

2019/11/04

[Java] [FTP Client] 中文檔名問題

Problem
When I try to upload Chinese file name via commons-net, I get this error : 550 can't access file. The complete log is as bellows:
220-written by Tim Kosse (Tim.Kosse@gmx.de)
220 Please visit http://sourceforge.net/projects/filezilla/
USER *******
331 Password required for chtuser
PASS *******
230 Logged on
TYPE I
200 Type set to I
CWD /tcpb
250 CWD successful. "/tcpb" is current directory.
PASV
227 Entering Passive Mode (192,168,32,66,8,2)
STOR 中文測試.zip
150 Connection accepted
550 can't access file.
QUIT
221 Goodbye


FtpService is as following:

  package test.service;
  
  import java.io.BufferedOutputStream;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.io.PrintWriter;
  import java.util.Arrays;
  import java.util.List;
  import java.util.stream.Collectors;
  
  import org.apache.commons.net.PrintCommandListener;
  import org.apache.commons.net.ftp.FTP;
  import org.apache.commons.net.ftp.FTPClient;
  import org.apache.commons.net.ftp.FTPFile;
  import org.apache.commons.net.ftp.FTPReply;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.stereotype.Service;
  
  import lombok.extern.slf4j.Slf4j;
  
  @Slf4j
  @Service
  public class FtpService {
  
      @Value("${ftp.host}")
      private String host;
  
      @Value("${ftp.port}")
      private Integer port;
  
      @Value("${ftp.user}")
      private String user;
  
      @Value("${ftp.password}")
      private String password;
  
      private FTPClient client;
  
      /**
       * Stores a file on the server using the given name.
       * 
       * @param directory
       *            specific working directory
       * @param file
       *            local file
       * @throws IOException
       */
      public void uploadFile(String directory, File file) throws IOException {
          try (InputStream is = new FileInputStream(file);) {
              connect();
  
              client.changeWorkingDirectory(directory);
              client.storeFile(file.getName(), is);
          } catch (IOException e) {
              throw new IOException("fail to upload file", e);
          } finally {
              disconnect();
          }
      }
  
      /**
       * Connect to FTP server.
       * 
       * @throws IOException
       */
      private void connect() throws IOException {
          try {
              client = new FTPClient();
              client.addProtocolCommandListener(
                      new PrintCommandListener(new PrintWriter(System.out), true));
              
              client.connect(host, port);
              int reply = client.getReplyCode();
              if (!FTPReply.isPositiveCompletion(reply)) {
                  client.disconnect();
                  throw new IOException("Exception in connecting to FTP Server");
              }
  
              client.login(user, password);
              client.enterLocalPassiveMode();
              client.setFileType(FTP.BINARY_FILE_TYPE);
  
              log.debug("connect to FTP server succesfully");
          } catch (IOException e) {
              throw new IOException("fail to connect to FTP server", e);
          }
      }
  
      /**
       * Disconnect from FTP server.
       * 
       * @throws IOException
       */
      private void disconnect() throws IOException {
          try {
              if (client.isConnected()) {
                  client.logout();
                  client.disconnect();
              }
              log.debug("disconnect from FTP server succesfully");
          } catch (IOException e) {
              throw new IOException("fail to disconnect from FTP server", e);
          }
      }
  
  }
  


How-To
Owning to the FTP server does not know the file name encoding, so you need to convert file name encoding to iso-8859-1. The uploadFile method should be modified as bellows:
    /**
     * Stores a file on the server using the given name.
     * 
     * @param directory
     *            specific working directory
     * @param file
     *            local file
     * @throws IOException
     */
    public void uploadFile(String directory, File file) throws IOException {
        try (InputStream is = new FileInputStream(file);) {
            connect();

            client.changeWorkingDirectory(directory);
            client.storeFile(new String(file.getName().getBytes(), "iso-8859-1"), is);
        } catch (IOException e) {
            throw new IOException("fail to upload file", e);
        } finally {
            disconnect();
        }
    }






No comments: