Caideyipi commented on code in PR #12541:
URL: https://github.com/apache/iotdb/pull/12541#discussion_r1619748929


##########
iotdb-client/cli/src/assembly/resources/tools/load-tsfile.bat:
##########
@@ -22,15 +22,13 @@
 @REM You can put your env variable here
 @REM set JAVA_HOME=%JAVA_HOME%
 
-title IoTDB Load

Review Comment:
   Why delete this? However, the title can indeed be "Load tsFile" or 
something...



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,436 @@
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")

Review Comment:
   Concurrency of tsfile loading (Or words with similar means)



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,436 @@
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";

Review Comment:
   TSFILEDB...



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);
+      if (helpCommandLine.hasOption(HELP_ARGS)) {
+        hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+        System.exit(CODE_ERROR);
+      }
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      commandLine = parser.parse(options, args, true);
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      parseBasicParams(commandLine);
+      parseSpecialParams(commandLine);
+    } catch (ArgsErrorException e) {
+      ioTPrinter.println("Args error: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    } catch (Exception e) {
+      ioTPrinter.println("Encounter an error, because: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    }
+
+    System.exit(importFromTargetPath());
+  }
+
+  private static void parseSpecialParams(CommandLine commandLine) throws 
ArgsErrorException {
+
+    source = commandLine.getOptionValue(SOURCE_ARGS);
+    if (!Files.exists(Paths.get(source))) {
+      ioTPrinter.println("source file is not exist");
+      System.exit(CODE_OK);
+    }
+    onSuccess = commandLine.getOptionValue(ON_SUCCESS_ARGS);
+    onFail = commandLine.getOptionValue(ON_FAIL_ARGS);
+
+    boolean checkSuccessFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onSuccess)
+        || Operation.CP.name().equalsIgnoreCase(onSuccess)) {
+      File file = createSuccessDir(commandLine);
+      checkSuccessFileStory = checkFileStory(source, file);

Review Comment:
   Maybe "storage" here? And maybe "isTargetDirEqualsSourceDir" is better...



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);
+      if (helpCommandLine.hasOption(HELP_ARGS)) {
+        hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+        System.exit(CODE_ERROR);
+      }
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      commandLine = parser.parse(options, args, true);
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      parseBasicParams(commandLine);
+      parseSpecialParams(commandLine);
+    } catch (ArgsErrorException e) {
+      ioTPrinter.println("Args error: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    } catch (Exception e) {
+      ioTPrinter.println("Encounter an error, because: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    }
+
+    System.exit(importFromTargetPath());
+  }
+
+  private static void parseSpecialParams(CommandLine commandLine) throws 
ArgsErrorException {
+
+    source = commandLine.getOptionValue(SOURCE_ARGS);
+    if (!Files.exists(Paths.get(source))) {
+      ioTPrinter.println("source file is not exist");
+      System.exit(CODE_OK);
+    }
+    onSuccess = commandLine.getOptionValue(ON_SUCCESS_ARGS);
+    onFail = commandLine.getOptionValue(ON_FAIL_ARGS);
+
+    boolean checkSuccessFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onSuccess)
+        || Operation.CP.name().equalsIgnoreCase(onSuccess)) {
+      File file = createSuccessDir(commandLine);
+      checkSuccessFileStory = checkFileStory(source, file);
+    }
+
+    boolean checkFailFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onFail)
+        || Operation.CP.name().equalsIgnoreCase(onFail)) {
+      File file = createFailDir(commandLine);
+      checkFailFileStory = checkFileStory(source, file);
+    }
+
+    successOperation = Operation.getOperation(onSuccess, 
checkSuccessFileStory);
+    failOperation = Operation.getOperation(onFail, checkFailFileStory);
+
+    if (commandLine.getOptionValue(THREAD_NUM_ARGS) != null) {
+      threadNum = 
Integer.parseInt(commandLine.getOptionValue(THREAD_NUM_ARGS));
+    }
+  }
+
+  public static boolean checkFileStory(String filePath1, File file) {
+    Path path1 = Paths.get(filePath1);
+    Path path2 = file.toPath();
+
+    try {
+      FileStore store1 = Files.getFileStore(path1);
+      FileStore store2 = Files.getFileStore(path2);
+      return store1.equals(store2);
+    } catch (IOException e) {
+      e.printStackTrace();
+      ioTPrinter.println("check file story fail : " + e.getMessage());
+      return false;
+    }
+  }
+
+  public static File createSuccessDir(CommandLine commandLine) {
+    if (commandLine.getOptionValue(SUCCESS_DIR_ARGS) != null) {
+      successDir = commandLine.getOptionValue(SUCCESS_DIR_ARGS);
+    }
+    File file = new File(successDir);
+    if (!file.isDirectory()) {
+      file.mkdirs();
+    }
+    return file;
+  }
+
+  public static File createFailDir(CommandLine commandLine) {
+    if (commandLine.getOptionValue(FAIL_DIR_ARGS) != null) {
+      failDir = commandLine.getOptionValue(FAIL_DIR_ARGS);
+    }
+    File file = new File(failDir);
+    if (!file.isDirectory()) {
+      file.mkdirs();
+    }
+    return file;
+  }
+
+  public static int importFromTargetPath() {
+    try {
+      sessionPool = new SessionPool(host, Integer.parseInt(port), username, 
password, threadNum);
+      File file = new File(source);
+      sourceFullPath = file.getAbsolutePath();
+      if (!file.isFile() && !file.isDirectory()) {
+        ioTPrinter.println("File not found!");
+        return CODE_ERROR;
+      }
+      traverse(file);
+      asyncImportTsFiles();
+    } catch (InterruptedException e) {
+      ioTPrinter.println("Traversing file exceptions: " + e.getMessage());
+      return CODE_ERROR;
+    } finally {
+      if (sessionPool != null) {
+        sessionPool.close();
+      }
+    }
+    return CODE_OK;
+  }
+
+  public static void traverse(File file) throws InterruptedException {
+    if (file.isFile()) {
+      linkedBlockingQueue.put(file.getAbsolutePath());
+    } else if (file.isDirectory()) {
+      File[] files = file.listFiles();
+      if (files != null) {
+        for (File f : files) {
+          traverse(f);
+        }
+      }
+    }
+  }
+
+  public static void asyncImportTsFiles() {
+    List<Thread> list = new ArrayList<>(threadNum);
+    for (int i = 0; i < threadNum; i++) {
+      Thread thread = new Thread(ImportTsFile::importTsFile);
+      thread.start();
+      list.add(thread);
+    }
+    list.forEach(
+        thread -> {
+          try {
+            thread.join();
+          } catch (InterruptedException e) {
+            ioTPrinter.println("importTsFile thread join interrupted: " + 
e.getMessage());
+          }
+        });
+  }
+
+  public static void importTsFile() {
+    String filePath;
+    try {
+      while ((filePath = linkedBlockingQueue.poll()) != null) {
+        String sql = "load '" + filePath + "' onSuccess=none ";
+        try {
+          sessionPool.executeNonQueryStatement(sql);
+          ioTPrinter.println("Import [ " + filePath + " ] file success");
+          processingSuccess(filePath);
+        } catch (Exception e) {
+          ioTPrinter.println("Import [ " + filePath + " ] file fail: " + 
e.getMessage());
+          processingFailed(filePath);
+        }
+      }
+    } catch (Exception e) {
+      ioTPrinter.println("Import file exceptions: " + e.getMessage());
+    }
+  }
+
+  public static void processingSuccess(String filePath) {
+    String relativePath = filePath.substring(sourceFullPath.length() + 1);
+
+    switch (successOperation) {
+      case DELETE:
+        try {
+          Files.delete(Paths.get(filePath));
+        } catch (IOException e) {
+          ioTPrinter.println("File delete fail: " + e.getMessage());
+        }
+        break;
+      case CP:
+        try {
+          Files.copy(
+              Paths.get(filePath),
+              Paths.get(successDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+          ioTPrinter.println("File copied fail: " + e.getMessage());
+        }
+        break;
+      case HD:
+        try {
+          Files.createLink(
+              Paths.get(successDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              Paths.get(filePath));
+        } catch (FileAlreadyExistsException e) {
+          ioTPrinter.println("File headlinked fail: File Already Exists " + 
e.getMessage());
+        } catch (IOException e) {
+          e.printStackTrace();
+          ioTPrinter.println("File headlinked fail: " + e.getMessage());
+        }
+        break;
+      case MV:
+        try {
+          Files.move(
+              Paths.get(filePath),
+              Paths.get(successDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+          ioTPrinter.println("File moved fail: " + e.getMessage());
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  public static void processingFailed(String filePath) {
+    String relativePath = filePath.substring(sourceFullPath.length() + 1);
+
+    switch (failOperation) {
+      case DELETE:
+        try {
+          Files.delete(Paths.get(filePath));
+        } catch (IOException e) {
+          ioTPrinter.println("File delete fail: " + e.getMessage());
+        }
+        break;
+      case CP:
+        try {
+          Files.copy(
+              Paths.get(filePath),
+              Paths.get(failDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+          ioTPrinter.println("File copied fail: " + e.getMessage());
+        }
+        break;
+      case HD:
+        try {
+          Files.createLink(
+              Paths.get(failDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              Paths.get(filePath));
+        } catch (FileAlreadyExistsException e) {
+          ioTPrinter.println("File headlinked fail: File Already Exists " + 
e.getMessage());
+        } catch (IOException e) {
+          ioTPrinter.println("File headlinked fail: " + e.getMessage());
+        }
+        break;
+      case MV:
+        try {
+          Files.move(
+              Paths.get(filePath),
+              Paths.get(failDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+          ioTPrinter.println("File moved fail: " + e.getMessage());
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  private enum Operation {
+    NONE,
+    MV,
+    HD,
+    CP,
+    DELETE,
+    ;
+
+    public static Operation getOperation(String operation, boolean fileStory) {

Review Comment:
   Better rename the variable "fileStory"...



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,436 @@
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")

Review Comment:
   The target folder when 'of' is 'mv' or 'cp'.



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,436 @@
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()

Review Comment:
   ...



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);

Review Comment:
   Why we need a "helpCommandLine" and "helpOptions" here?



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,436 @@
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)

Review Comment:
   Better keep the same sequence with "AbstractTsFileTool".



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);
+      if (helpCommandLine.hasOption(HELP_ARGS)) {
+        hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+        System.exit(CODE_ERROR);
+      }
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      commandLine = parser.parse(options, args, true);
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      parseBasicParams(commandLine);
+      parseSpecialParams(commandLine);
+    } catch (ArgsErrorException e) {
+      ioTPrinter.println("Args error: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    } catch (Exception e) {
+      ioTPrinter.println("Encounter an error, because: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    }
+
+    System.exit(importFromTargetPath());
+  }
+
+  private static void parseSpecialParams(CommandLine commandLine) throws 
ArgsErrorException {
+
+    source = commandLine.getOptionValue(SOURCE_ARGS);
+    if (!Files.exists(Paths.get(source))) {
+      ioTPrinter.println("source file is not exist");
+      System.exit(CODE_OK);
+    }
+    onSuccess = commandLine.getOptionValue(ON_SUCCESS_ARGS);
+    onFail = commandLine.getOptionValue(ON_FAIL_ARGS);
+
+    boolean checkSuccessFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onSuccess)
+        || Operation.CP.name().equalsIgnoreCase(onSuccess)) {
+      File file = createSuccessDir(commandLine);
+      checkSuccessFileStory = checkFileStory(source, file);
+    }
+
+    boolean checkFailFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onFail)
+        || Operation.CP.name().equalsIgnoreCase(onFail)) {
+      File file = createFailDir(commandLine);
+      checkFailFileStory = checkFileStory(source, file);
+    }
+
+    successOperation = Operation.getOperation(onSuccess, 
checkSuccessFileStory);
+    failOperation = Operation.getOperation(onFail, checkFailFileStory);
+
+    if (commandLine.getOptionValue(THREAD_NUM_ARGS) != null) {
+      threadNum = 
Integer.parseInt(commandLine.getOptionValue(THREAD_NUM_ARGS));
+    }
+  }
+
+  public static boolean checkFileStory(String filePath1, File file) {
+    Path path1 = Paths.get(filePath1);
+    Path path2 = file.toPath();
+
+    try {
+      FileStore store1 = Files.getFileStore(path1);
+      FileStore store2 = Files.getFileStore(path2);
+      return store1.equals(store2);
+    } catch (IOException e) {
+      e.printStackTrace();
+      ioTPrinter.println("check file story fail : " + e.getMessage());
+      return false;
+    }
+  }
+
+  public static File createSuccessDir(CommandLine commandLine) {
+    if (commandLine.getOptionValue(SUCCESS_DIR_ARGS) != null) {
+      successDir = commandLine.getOptionValue(SUCCESS_DIR_ARGS);
+    }
+    File file = new File(successDir);
+    if (!file.isDirectory()) {
+      file.mkdirs();
+    }
+    return file;
+  }
+
+  public static File createFailDir(CommandLine commandLine) {
+    if (commandLine.getOptionValue(FAIL_DIR_ARGS) != null) {
+      failDir = commandLine.getOptionValue(FAIL_DIR_ARGS);
+    }
+    File file = new File(failDir);
+    if (!file.isDirectory()) {
+      file.mkdirs();
+    }
+    return file;
+  }
+
+  public static int importFromTargetPath() {
+    try {
+      sessionPool = new SessionPool(host, Integer.parseInt(port), username, 
password, threadNum);
+      File file = new File(source);
+      sourceFullPath = file.getAbsolutePath();
+      if (!file.isFile() && !file.isDirectory()) {
+        ioTPrinter.println("File not found!");
+        return CODE_ERROR;
+      }
+      traverse(file);
+      asyncImportTsFiles();
+    } catch (InterruptedException e) {
+      ioTPrinter.println("Traversing file exceptions: " + e.getMessage());
+      return CODE_ERROR;
+    } finally {
+      if (sessionPool != null) {
+        sessionPool.close();
+      }
+    }
+    return CODE_OK;
+  }
+
+  public static void traverse(File file) throws InterruptedException {
+    if (file.isFile()) {
+      linkedBlockingQueue.put(file.getAbsolutePath());
+    } else if (file.isDirectory()) {
+      File[] files = file.listFiles();
+      if (files != null) {
+        for (File f : files) {
+          traverse(f);
+        }
+      }
+    }
+  }
+
+  public static void asyncImportTsFiles() {
+    List<Thread> list = new ArrayList<>(threadNum);
+    for (int i = 0; i < threadNum; i++) {
+      Thread thread = new Thread(ImportTsFile::importTsFile);
+      thread.start();
+      list.add(thread);
+    }
+    list.forEach(
+        thread -> {
+          try {
+            thread.join();
+          } catch (InterruptedException e) {
+            ioTPrinter.println("importTsFile thread join interrupted: " + 
e.getMessage());
+          }
+        });
+  }
+
+  public static void importTsFile() {
+    String filePath;
+    try {
+      while ((filePath = linkedBlockingQueue.poll()) != null) {
+        String sql = "load '" + filePath + "' onSuccess=none ";
+        try {
+          sessionPool.executeNonQueryStatement(sql);
+          ioTPrinter.println("Import [ " + filePath + " ] file success");
+          processingSuccess(filePath);
+        } catch (Exception e) {
+          ioTPrinter.println("Import [ " + filePath + " ] file fail: " + 
e.getMessage());
+          processingFailed(filePath);
+        }
+      }
+    } catch (Exception e) {
+      ioTPrinter.println("Import file exceptions: " + e.getMessage());
+    }
+  }
+
+  public static void processingSuccess(String filePath) {
+    String relativePath = filePath.substring(sourceFullPath.length() + 1);
+
+    switch (successOperation) {
+      case DELETE:
+        try {
+          Files.delete(Paths.get(filePath));
+        } catch (IOException e) {
+          ioTPrinter.println("File delete fail: " + e.getMessage());
+        }
+        break;
+      case CP:
+        try {
+          Files.copy(
+              Paths.get(filePath),
+              Paths.get(successDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+          ioTPrinter.println("File copied fail: " + e.getMessage());
+        }
+        break;
+      case HD:
+        try {
+          Files.createLink(
+              Paths.get(successDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              Paths.get(filePath));
+        } catch (FileAlreadyExistsException e) {
+          ioTPrinter.println("File headlinked fail: File Already Exists " + 
e.getMessage());

Review Comment:
   hardLink....



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);
+      if (helpCommandLine.hasOption(HELP_ARGS)) {
+        hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+        System.exit(CODE_ERROR);
+      }
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      commandLine = parser.parse(options, args, true);
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      parseBasicParams(commandLine);
+      parseSpecialParams(commandLine);
+    } catch (ArgsErrorException e) {
+      ioTPrinter.println("Args error: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    } catch (Exception e) {
+      ioTPrinter.println("Encounter an error, because: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    }
+
+    System.exit(importFromTargetPath());
+  }
+
+  private static void parseSpecialParams(CommandLine commandLine) throws 
ArgsErrorException {
+
+    source = commandLine.getOptionValue(SOURCE_ARGS);
+    if (!Files.exists(Paths.get(source))) {
+      ioTPrinter.println("source file is not exist");
+      System.exit(CODE_OK);
+    }
+    onSuccess = commandLine.getOptionValue(ON_SUCCESS_ARGS);
+    onFail = commandLine.getOptionValue(ON_FAIL_ARGS);
+
+    boolean checkSuccessFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onSuccess)
+        || Operation.CP.name().equalsIgnoreCase(onSuccess)) {
+      File file = createSuccessDir(commandLine);
+      checkSuccessFileStory = checkFileStory(source, file);
+    }
+
+    boolean checkFailFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onFail)
+        || Operation.CP.name().equalsIgnoreCase(onFail)) {
+      File file = createFailDir(commandLine);
+      checkFailFileStory = checkFileStory(source, file);
+    }
+
+    successOperation = Operation.getOperation(onSuccess, 
checkSuccessFileStory);
+    failOperation = Operation.getOperation(onFail, checkFailFileStory);
+
+    if (commandLine.getOptionValue(THREAD_NUM_ARGS) != null) {
+      threadNum = 
Integer.parseInt(commandLine.getOptionValue(THREAD_NUM_ARGS));
+    }
+  }
+
+  public static boolean checkFileStory(String filePath1, File file) {
+    Path path1 = Paths.get(filePath1);
+    Path path2 = file.toPath();
+
+    try {
+      FileStore store1 = Files.getFileStore(path1);
+      FileStore store2 = Files.getFileStore(path2);
+      return store1.equals(store2);
+    } catch (IOException e) {
+      e.printStackTrace();
+      ioTPrinter.println("check file story fail : " + e.getMessage());

Review Comment:
   Maybe "storage" here.



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);
+      if (helpCommandLine.hasOption(HELP_ARGS)) {
+        hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+        System.exit(CODE_ERROR);
+      }
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      commandLine = parser.parse(options, args, true);
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      parseBasicParams(commandLine);
+      parseSpecialParams(commandLine);
+    } catch (ArgsErrorException e) {
+      ioTPrinter.println("Args error: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    } catch (Exception e) {
+      ioTPrinter.println("Encounter an error, because: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    }
+
+    System.exit(importFromTargetPath());
+  }
+
+  private static void parseSpecialParams(CommandLine commandLine) throws 
ArgsErrorException {
+
+    source = commandLine.getOptionValue(SOURCE_ARGS);
+    if (!Files.exists(Paths.get(source))) {
+      ioTPrinter.println("source file is not exist");
+      System.exit(CODE_OK);

Review Comment:
   Why "CODE_OK" here?



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);
+      if (helpCommandLine.hasOption(HELP_ARGS)) {
+        hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+        System.exit(CODE_ERROR);
+      }
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      commandLine = parser.parse(options, args, true);
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      parseBasicParams(commandLine);
+      parseSpecialParams(commandLine);
+    } catch (ArgsErrorException e) {
+      ioTPrinter.println("Args error: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    } catch (Exception e) {
+      ioTPrinter.println("Encounter an error, because: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    }
+
+    System.exit(importFromTargetPath());
+  }
+
+  private static void parseSpecialParams(CommandLine commandLine) throws 
ArgsErrorException {
+
+    source = commandLine.getOptionValue(SOURCE_ARGS);
+    if (!Files.exists(Paths.get(source))) {
+      ioTPrinter.println("source file is not exist");
+      System.exit(CODE_OK);
+    }
+    onSuccess = commandLine.getOptionValue(ON_SUCCESS_ARGS);
+    onFail = commandLine.getOptionValue(ON_FAIL_ARGS);
+
+    boolean checkSuccessFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onSuccess)
+        || Operation.CP.name().equalsIgnoreCase(onSuccess)) {
+      File file = createSuccessDir(commandLine);
+      checkSuccessFileStory = checkFileStory(source, file);
+    }
+
+    boolean checkFailFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onFail)
+        || Operation.CP.name().equalsIgnoreCase(onFail)) {
+      File file = createFailDir(commandLine);

Review Comment:
   Better rename it to "failDir"



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);
+      if (helpCommandLine.hasOption(HELP_ARGS)) {
+        hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+        System.exit(CODE_ERROR);
+      }
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      commandLine = parser.parse(options, args, true);
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      parseBasicParams(commandLine);
+      parseSpecialParams(commandLine);
+    } catch (ArgsErrorException e) {
+      ioTPrinter.println("Args error: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    } catch (Exception e) {
+      ioTPrinter.println("Encounter an error, because: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    }
+
+    System.exit(importFromTargetPath());
+  }
+
+  private static void parseSpecialParams(CommandLine commandLine) throws 
ArgsErrorException {
+
+    source = commandLine.getOptionValue(SOURCE_ARGS);
+    if (!Files.exists(Paths.get(source))) {
+      ioTPrinter.println("source file is not exist");
+      System.exit(CODE_OK);
+    }
+    onSuccess = commandLine.getOptionValue(ON_SUCCESS_ARGS);
+    onFail = commandLine.getOptionValue(ON_FAIL_ARGS);
+
+    boolean checkSuccessFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onSuccess)
+        || Operation.CP.name().equalsIgnoreCase(onSuccess)) {
+      File file = createSuccessDir(commandLine);

Review Comment:
   Better rename it to "successDir"



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);
+      if (helpCommandLine.hasOption(HELP_ARGS)) {
+        hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+        System.exit(CODE_ERROR);
+      }
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      commandLine = parser.parse(options, args, true);
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      parseBasicParams(commandLine);
+      parseSpecialParams(commandLine);
+    } catch (ArgsErrorException e) {
+      ioTPrinter.println("Args error: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    } catch (Exception e) {
+      ioTPrinter.println("Encounter an error, because: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    }
+
+    System.exit(importFromTargetPath());
+  }
+
+  private static void parseSpecialParams(CommandLine commandLine) throws 
ArgsErrorException {
+
+    source = commandLine.getOptionValue(SOURCE_ARGS);
+    if (!Files.exists(Paths.get(source))) {
+      ioTPrinter.println("source file is not exist");
+      System.exit(CODE_OK);
+    }
+    onSuccess = commandLine.getOptionValue(ON_SUCCESS_ARGS);
+    onFail = commandLine.getOptionValue(ON_FAIL_ARGS);
+
+    boolean checkSuccessFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onSuccess)
+        || Operation.CP.name().equalsIgnoreCase(onSuccess)) {
+      File file = createSuccessDir(commandLine);
+      checkSuccessFileStory = checkFileStory(source, file);
+    }
+
+    boolean checkFailFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onFail)
+        || Operation.CP.name().equalsIgnoreCase(onFail)) {
+      File file = createFailDir(commandLine);
+      checkFailFileStory = checkFileStory(source, file);
+    }
+
+    successOperation = Operation.getOperation(onSuccess, 
checkSuccessFileStory);
+    failOperation = Operation.getOperation(onFail, checkFailFileStory);
+
+    if (commandLine.getOptionValue(THREAD_NUM_ARGS) != null) {
+      threadNum = 
Integer.parseInt(commandLine.getOptionValue(THREAD_NUM_ARGS));
+    }
+  }
+
+  public static boolean checkFileStory(String filePath1, File file) {
+    Path path1 = Paths.get(filePath1);
+    Path path2 = file.toPath();
+
+    try {
+      FileStore store1 = Files.getFileStore(path1);
+      FileStore store2 = Files.getFileStore(path2);
+      return store1.equals(store2);
+    } catch (IOException e) {
+      e.printStackTrace();
+      ioTPrinter.println("check file story fail : " + e.getMessage());
+      return false;
+    }
+  }
+
+  public static File createSuccessDir(CommandLine commandLine) {
+    if (commandLine.getOptionValue(SUCCESS_DIR_ARGS) != null) {
+      successDir = commandLine.getOptionValue(SUCCESS_DIR_ARGS);
+    }
+    File file = new File(successDir);
+    if (!file.isDirectory()) {
+      file.mkdirs();
+    }
+    return file;
+  }
+
+  public static File createFailDir(CommandLine commandLine) {
+    if (commandLine.getOptionValue(FAIL_DIR_ARGS) != null) {
+      failDir = commandLine.getOptionValue(FAIL_DIR_ARGS);
+    }
+    File file = new File(failDir);
+    if (!file.isDirectory()) {
+      file.mkdirs();
+    }
+    return file;
+  }
+
+  public static int importFromTargetPath() {
+    try {
+      sessionPool = new SessionPool(host, Integer.parseInt(port), username, 
password, threadNum);
+      File file = new File(source);
+      sourceFullPath = file.getAbsolutePath();
+      if (!file.isFile() && !file.isDirectory()) {
+        ioTPrinter.println("File not found!");
+        return CODE_ERROR;
+      }
+      traverse(file);
+      asyncImportTsFiles();
+    } catch (InterruptedException e) {
+      ioTPrinter.println("Traversing file exceptions: " + e.getMessage());
+      return CODE_ERROR;
+    } finally {
+      if (sessionPool != null) {
+        sessionPool.close();
+      }
+    }
+    return CODE_OK;
+  }
+
+  public static void traverse(File file) throws InterruptedException {
+    if (file.isFile()) {
+      linkedBlockingQueue.put(file.getAbsolutePath());
+    } else if (file.isDirectory()) {
+      File[] files = file.listFiles();
+      if (files != null) {
+        for (File f : files) {
+          traverse(f);
+        }
+      }
+    }
+  }
+
+  public static void asyncImportTsFiles() {
+    List<Thread> list = new ArrayList<>(threadNum);
+    for (int i = 0; i < threadNum; i++) {
+      Thread thread = new Thread(ImportTsFile::importTsFile);
+      thread.start();
+      list.add(thread);
+    }
+    list.forEach(
+        thread -> {
+          try {
+            thread.join();
+          } catch (InterruptedException e) {
+            ioTPrinter.println("importTsFile thread join interrupted: " + 
e.getMessage());
+          }
+        });
+  }
+
+  public static void importTsFile() {
+    String filePath;
+    try {
+      while ((filePath = linkedBlockingQueue.poll()) != null) {
+        String sql = "load '" + filePath + "' onSuccess=none ";
+        try {
+          sessionPool.executeNonQueryStatement(sql);
+          ioTPrinter.println("Import [ " + filePath + " ] file success");
+          processingSuccess(filePath);
+        } catch (Exception e) {
+          ioTPrinter.println("Import [ " + filePath + " ] file fail: " + 
e.getMessage());
+          processingFailed(filePath);
+        }
+      }
+    } catch (Exception e) {
+      ioTPrinter.println("Import file exceptions: " + e.getMessage());
+    }
+  }
+
+  public static void processingSuccess(String filePath) {
+    String relativePath = filePath.substring(sourceFullPath.length() + 1);
+
+    switch (successOperation) {
+      case DELETE:
+        try {
+          Files.delete(Paths.get(filePath));
+        } catch (IOException e) {
+          ioTPrinter.println("File delete fail: " + e.getMessage());
+        }
+        break;
+      case CP:
+        try {
+          Files.copy(
+              Paths.get(filePath),
+              Paths.get(successDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+          ioTPrinter.println("File copied fail: " + e.getMessage());
+        }
+        break;
+      case HD:
+        try {
+          Files.createLink(
+              Paths.get(successDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              Paths.get(filePath));
+        } catch (FileAlreadyExistsException e) {
+          ioTPrinter.println("File headlinked fail: File Already Exists " + 
e.getMessage());
+        } catch (IOException e) {
+          e.printStackTrace();
+          ioTPrinter.println("File headlinked fail: " + e.getMessage());
+        }
+        break;
+      case MV:
+        try {
+          Files.move(
+              Paths.get(filePath),
+              Paths.get(successDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+          ioTPrinter.println("File moved fail: " + e.getMessage());
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  public static void processingFailed(String filePath) {
+    String relativePath = filePath.substring(sourceFullPath.length() + 1);
+
+    switch (failOperation) {
+      case DELETE:
+        try {
+          Files.delete(Paths.get(filePath));
+        } catch (IOException e) {
+          ioTPrinter.println("File delete fail: " + e.getMessage());
+        }
+        break;
+      case CP:
+        try {
+          Files.copy(
+              Paths.get(filePath),
+              Paths.get(failDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+          ioTPrinter.println("File copied fail: " + e.getMessage());
+        }
+        break;
+      case HD:
+        try {
+          Files.createLink(
+              Paths.get(failDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              Paths.get(filePath));
+        } catch (FileAlreadyExistsException e) {
+          ioTPrinter.println("File headlinked fail: File Already Exists " + 
e.getMessage());
+        } catch (IOException e) {
+          ioTPrinter.println("File headlinked fail: " + e.getMessage());
+        }
+        break;
+      case MV:
+        try {
+          Files.move(
+              Paths.get(filePath),
+              Paths.get(failDir + File.separator + 
relativePath.replace(File.separator, "_")),
+              StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+          ioTPrinter.println("File moved fail: " + e.getMessage());
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  private enum Operation {
+    NONE,
+    MV,
+    HD,
+    CP,
+    DELETE,
+    ;
+
+    public static Operation getOperation(String operation, boolean fileStory) {
+      switch (operation.toLowerCase()) {
+        case "none":
+          return Operation.NONE;
+        case "mv":
+          return Operation.MV;
+        case "cp":
+          if (fileStory) {
+            return Operation.HD;

Review Comment:
   Why hardlink if source dir == target dir?



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);
+      if (helpCommandLine.hasOption(HELP_ARGS)) {
+        hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+        System.exit(CODE_ERROR);
+      }
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      commandLine = parser.parse(options, args, true);
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      parseBasicParams(commandLine);
+      parseSpecialParams(commandLine);
+    } catch (ArgsErrorException e) {
+      ioTPrinter.println("Args error: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    } catch (Exception e) {
+      ioTPrinter.println("Encounter an error, because: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    }
+
+    System.exit(importFromTargetPath());
+  }
+
+  private static void parseSpecialParams(CommandLine commandLine) throws 
ArgsErrorException {
+

Review Comment:
   Delete the blank line here.



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);
+      if (helpCommandLine.hasOption(HELP_ARGS)) {
+        hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+        System.exit(CODE_ERROR);
+      }
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      commandLine = parser.parse(options, args, true);
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      parseBasicParams(commandLine);
+      parseSpecialParams(commandLine);
+    } catch (ArgsErrorException e) {
+      ioTPrinter.println("Args error: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    } catch (Exception e) {
+      ioTPrinter.println("Encounter an error, because: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    }
+
+    System.exit(importFromTargetPath());
+  }
+
+  private static void parseSpecialParams(CommandLine commandLine) throws 
ArgsErrorException {
+
+    source = commandLine.getOptionValue(SOURCE_ARGS);
+    if (!Files.exists(Paths.get(source))) {
+      ioTPrinter.println("source file is not exist");
+      System.exit(CODE_OK);
+    }
+    onSuccess = commandLine.getOptionValue(ON_SUCCESS_ARGS);
+    onFail = commandLine.getOptionValue(ON_FAIL_ARGS);
+
+    boolean checkSuccessFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onSuccess)
+        || Operation.CP.name().equalsIgnoreCase(onSuccess)) {
+      File file = createSuccessDir(commandLine);
+      checkSuccessFileStory = checkFileStory(source, file);
+    }
+
+    boolean checkFailFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onFail)
+        || Operation.CP.name().equalsIgnoreCase(onFail)) {
+      File file = createFailDir(commandLine);
+      checkFailFileStory = checkFileStory(source, file);
+    }
+
+    successOperation = Operation.getOperation(onSuccess, 
checkSuccessFileStory);
+    failOperation = Operation.getOperation(onFail, checkFailFileStory);
+
+    if (commandLine.getOptionValue(THREAD_NUM_ARGS) != null) {
+      threadNum = 
Integer.parseInt(commandLine.getOptionValue(THREAD_NUM_ARGS));
+    }
+  }
+
+  public static boolean checkFileStory(String filePath1, File file) {
+    Path path1 = Paths.get(filePath1);
+    Path path2 = file.toPath();
+
+    try {
+      FileStore store1 = Files.getFileStore(path1);
+      FileStore store2 = Files.getFileStore(path2);
+      return store1.equals(store2);
+    } catch (IOException e) {
+      e.printStackTrace();
+      ioTPrinter.println("check file story fail : " + e.getMessage());
+      return false;
+    }
+  }
+
+  public static File createSuccessDir(CommandLine commandLine) {
+    if (commandLine.getOptionValue(SUCCESS_DIR_ARGS) != null) {
+      successDir = commandLine.getOptionValue(SUCCESS_DIR_ARGS);
+    }
+    File file = new File(successDir);
+    if (!file.isDirectory()) {
+      file.mkdirs();

Review Comment:
   It's a little bit more user-friendly if we log the failed "mkdir" here, 
because of either "successDir" is a regular file or some authentication 
problems.



##########
iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java:
##########
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tool;
+
+import org.apache.iotdb.cli.utils.IoTPrinter;
+import org.apache.iotdb.exception.ArgsErrorException;
+import org.apache.iotdb.session.pool.SessionPool;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class ImportTsFile extends AbstractTsFileTool {
+
+  private static final String SOURCE_ARGS = "s";
+  private static final String SOURCE_NAME = "source";
+
+  private static final String ON_SUCCESS_ARGS = "os";
+  private static final String ON_SUCCESS_NAME = "on_success";
+
+  private static final String SUCCESS_DIR_ARGS = "sd";
+  private static final String SUCCESS_DIR_NAME = "success_dir";
+
+  private static final String FAIL_DIR_ARGS = "fd";
+  private static final String FAIL_DIR_NAME = "fail_dir";
+
+  private static final String ON_FAIL_ARGS = "of";
+  private static final String ON_FAIL_NAME = "on_fail";
+
+  private static final String THREAD_NUM_ARGS = "tn";
+  private static final String THREAD_NUM_NAME = "thread_num";
+
+  private static final IoTPrinter ioTPrinter = new IoTPrinter(System.out);
+
+  private static final String TSFILEDB_CLI_PREFIX = "ImportTsFile";
+
+  private static String source;
+  private static String sourceFullPath;
+  private static String failDir = "fail/";
+  private static String successDir = "success/";
+  private static String onSuccess;
+  private static String onFail;
+  private static Operation successOperation;
+  private static Operation failOperation;
+  private static int threadNum = 8;
+  private static final LinkedBlockingQueue<String> linkedBlockingQueue =
+      new LinkedBlockingQueue<>();
+
+  private static void createOptions() {
+    createBaseOptions();
+
+    Option opSource =
+        Option.builder(SOURCE_ARGS)
+            .longOpt(SOURCE_NAME)
+            .required()
+            .required()
+            .argName(SOURCE_NAME)
+            .hasArg()
+            .desc(
+                "If input a file path, load a file, "
+                    + "otherwise load all file under this directory 
(required)")
+            .build();
+    options.addOption(opSource);
+
+    Option opOnSuccess =
+        Option.builder(ON_SUCCESS_ARGS)
+            .longOpt(ON_SUCCESS_NAME)
+            .argName(ON_SUCCESS_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile successfully, do operation on tsfile, 
optional parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnSuccess);
+
+    Option opOnFail =
+        Option.builder(ON_FAIL_ARGS)
+            .longOpt(ON_FAIL_NAME)
+            .argName(ON_FAIL_NAME)
+            .required()
+            .hasArg()
+            .desc(
+                "When loading tsfile failed, do operation on tsfile, optional 
parameters are none, mv, cp, delete.")
+            .build();
+    options.addOption(opOnFail);
+
+    Option opSuccessDir =
+        Option.builder(SUCCESS_DIR_ARGS)
+            .longOpt(SUCCESS_DIR_NAME)
+            .argName(SUCCESS_DIR_NAME)
+            .hasArg()
+            .desc("When os is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opSuccessDir);
+
+    Option opFailDir =
+        Option.builder(FAIL_DIR_ARGS)
+            .longOpt(FAIL_DIR_NAME)
+            .argName(FAIL_DIR_NAME)
+            .hasArg()
+            .desc("When of is mv, cp, you need to specify the folder to 
operate on.")
+            .build();
+    options.addOption(opFailDir);
+
+    Option opThreadNum =
+        Option.builder(THREAD_NUM_ARGS)
+            .longOpt(THREAD_NUM_NAME)
+            .argName(THREAD_NUM_NAME)
+            .hasArgs()
+            .desc("Support for concurrent parameters")
+            .build();
+    options.addOption(opThreadNum);
+  }
+
+  public static void main(String[] args) {
+    createOptions();
+    hf = new HelpFormatter();
+    hf.setOptionComparator(null);
+    hf.setWidth(MAX_HELP_CONSOLE_WIDTH);
+    CommandLine commandLine = null;
+    CommandLineParser parser = new DefaultParser();
+
+    if (args == null || args.length == 0) {
+      ioTPrinter.println("Too few params input, please check the following 
hint.");
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      CommandLine helpCommandLine = parser.parse(helpOptions, args, true);
+      if (helpCommandLine.hasOption(HELP_ARGS)) {
+        hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+        System.exit(CODE_ERROR);
+      }
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      commandLine = parser.parse(options, args, true);
+    } catch (ParseException e) {
+      ioTPrinter.println("Parse error: " + e.getMessage());
+      hf.printHelp(TSFILEDB_CLI_PREFIX, options, true);
+      System.exit(CODE_ERROR);
+    }
+
+    try {
+      parseBasicParams(commandLine);
+      parseSpecialParams(commandLine);
+    } catch (ArgsErrorException e) {
+      ioTPrinter.println("Args error: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    } catch (Exception e) {
+      ioTPrinter.println("Encounter an error, because: " + e.getMessage());
+      System.exit(CODE_ERROR);
+    }
+
+    System.exit(importFromTargetPath());
+  }
+
+  private static void parseSpecialParams(CommandLine commandLine) throws 
ArgsErrorException {
+
+    source = commandLine.getOptionValue(SOURCE_ARGS);
+    if (!Files.exists(Paths.get(source))) {
+      ioTPrinter.println("source file is not exist");
+      System.exit(CODE_OK);
+    }
+    onSuccess = commandLine.getOptionValue(ON_SUCCESS_ARGS);
+    onFail = commandLine.getOptionValue(ON_FAIL_ARGS);
+
+    boolean checkSuccessFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onSuccess)
+        || Operation.CP.name().equalsIgnoreCase(onSuccess)) {
+      File file = createSuccessDir(commandLine);
+      checkSuccessFileStory = checkFileStory(source, file);
+    }
+
+    boolean checkFailFileStory = false;
+    if (Operation.MV.name().equalsIgnoreCase(onFail)
+        || Operation.CP.name().equalsIgnoreCase(onFail)) {
+      File file = createFailDir(commandLine);
+      checkFailFileStory = checkFileStory(source, file);
+    }
+
+    successOperation = Operation.getOperation(onSuccess, 
checkSuccessFileStory);
+    failOperation = Operation.getOperation(onFail, checkFailFileStory);
+
+    if (commandLine.getOptionValue(THREAD_NUM_ARGS) != null) {
+      threadNum = 
Integer.parseInt(commandLine.getOptionValue(THREAD_NUM_ARGS));
+    }
+  }
+
+  public static boolean checkFileStory(String filePath1, File file) {
+    Path path1 = Paths.get(filePath1);
+    Path path2 = file.toPath();
+
+    try {
+      FileStore store1 = Files.getFileStore(path1);
+      FileStore store2 = Files.getFileStore(path2);
+      return store1.equals(store2);
+    } catch (IOException e) {
+      e.printStackTrace();
+      ioTPrinter.println("check file story fail : " + e.getMessage());
+      return false;
+    }
+  }
+
+  public static File createSuccessDir(CommandLine commandLine) {
+    if (commandLine.getOptionValue(SUCCESS_DIR_ARGS) != null) {
+      successDir = commandLine.getOptionValue(SUCCESS_DIR_ARGS);
+    }
+    File file = new File(successDir);
+    if (!file.isDirectory()) {
+      file.mkdirs();
+    }
+    return file;
+  }
+
+  public static File createFailDir(CommandLine commandLine) {
+    if (commandLine.getOptionValue(FAIL_DIR_ARGS) != null) {
+      failDir = commandLine.getOptionValue(FAIL_DIR_ARGS);
+    }
+    File file = new File(failDir);
+    if (!file.isDirectory()) {
+      file.mkdirs();
+    }
+    return file;
+  }
+
+  public static int importFromTargetPath() {
+    try {
+      sessionPool = new SessionPool(host, Integer.parseInt(port), username, 
password, threadNum);
+      File file = new File(source);
+      sourceFullPath = file.getAbsolutePath();
+      if (!file.isFile() && !file.isDirectory()) {
+        ioTPrinter.println("File not found!");
+        return CODE_ERROR;
+      }
+      traverse(file);
+      asyncImportTsFiles();
+    } catch (InterruptedException e) {
+      ioTPrinter.println("Traversing file exceptions: " + e.getMessage());
+      return CODE_ERROR;
+    } finally {
+      if (sessionPool != null) {
+        sessionPool.close();
+      }
+    }
+    return CODE_OK;
+  }
+
+  public static void traverse(File file) throws InterruptedException {
+    if (file.isFile()) {
+      linkedBlockingQueue.put(file.getAbsolutePath());
+    } else if (file.isDirectory()) {
+      File[] files = file.listFiles();
+      if (files != null) {
+        for (File f : files) {
+          traverse(f);
+        }
+      }
+    }
+  }
+
+  public static void asyncImportTsFiles() {
+    List<Thread> list = new ArrayList<>(threadNum);
+    for (int i = 0; i < threadNum; i++) {
+      Thread thread = new Thread(ImportTsFile::importTsFile);
+      thread.start();
+      list.add(thread);
+    }
+    list.forEach(
+        thread -> {
+          try {
+            thread.join();
+          } catch (InterruptedException e) {
+            ioTPrinter.println("importTsFile thread join interrupted: " + 
e.getMessage());
+          }
+        });
+  }
+
+  public static void importTsFile() {
+    String filePath;
+    try {
+      while ((filePath = linkedBlockingQueue.poll()) != null) {
+        String sql = "load '" + filePath + "' onSuccess=none ";
+        try {
+          sessionPool.executeNonQueryStatement(sql);
+          ioTPrinter.println("Import [ " + filePath + " ] file success");
+          processingSuccess(filePath);
+        } catch (Exception e) {
+          ioTPrinter.println("Import [ " + filePath + " ] file fail: " + 
e.getMessage());
+          processingFailed(filePath);
+        }
+      }
+    } catch (Exception e) {
+      ioTPrinter.println("Import file exceptions: " + e.getMessage());
+    }
+  }
+
+  public static void processingSuccess(String filePath) {

Review Comment:
   Maybe avoiding using "Paths.get" each time by pass in the transformed path 
directly?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to