This is an automated email from the ASF dual-hosted git repository.

haonan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new e825af4aade feature add iotdb backup (#12365)
e825af4aade is described below

commit e825af4aade4370a68c7c4a84918f3d3ca30bb7f
Author: CloudWise-Lukemiao <[email protected]>
AuthorDate: Tue Apr 23 15:00:16 2024 +0800

    feature add iotdb backup (#12365)
    
    Co-authored-by: luke.miao <[email protected]>
---
 .../cli/src/assembly/resources/tools/backup.bat    | 118 +++
 .../cli/src/assembly/resources/tools/backup.sh     | 128 +++
 .../org/apache/iotdb/tool/IoTDBDataBackTool.java   | 985 +++++++++++++++++++++
 3 files changed, 1231 insertions(+)

diff --git a/iotdb-client/cli/src/assembly/resources/tools/backup.bat 
b/iotdb-client/cli/src/assembly/resources/tools/backup.bat
new file mode 100644
index 00000000000..c91b426a34e
--- /dev/null
+++ b/iotdb-client/cli/src/assembly/resources/tools/backup.bat
@@ -0,0 +1,118 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM     http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+@echo off
+setlocal enabledelayedexpansion
+
+if "%OS%" == "Windows_NT" setlocal
+
+pushd %~dp0..
+if NOT DEFINED IOTDB_HOME set IOTDB_HOME=%CD%
+popd
+
+if NOT DEFINED JAVA_HOME goto :err
+
+set JAVA_OPTS=-ea^
+ -DIOTDB_HOME=%IOTDB_HOME%
+
+SET IOTDB_CONF=%IOTDB_HOME%\conf
+IF EXIST "%IOTDB_CONF%\datanode-env.bat" (
+  CALL "%IOTDB_CONF%\datanode-env.bat" > nul 2>&1
+) ELSE (
+  echo Can't find datanode-env.bat
+)
+
+IF EXIST "%IOTDB_CONF%\iotdb-datanode.properties" (
+  for /f  "eol=# tokens=2 delims==" %%i in ('findstr /i "^dn_rpc_port"
+    %IOTDB_CONF%\iotdb-datanode.properties') do (
+      set dn_rpc_port=%%i
+  )
+) ELSE (
+  set dn_rpc_port=6667
+)
+
+IF EXIST "%IOTDB_CONF%\iotdb-confignode.properties" (
+  for /f  "eol=# tokens=2 delims==" %%i in ('findstr /i "^cn_internal_port"
+    %IOTDB_CONF%\iotdb-confignode.properties') do (
+      set cn_internal_port=%%i
+  )
+) ELSE (
+  set cn_internal_port=10710
+)
+
+set "local_iotdb_occupied_ports="
+set "operation_dirs="
+set dn_rpc_port_occupied=0
+set cn_internal_port_occupied=0
+
+for /f  "tokens=1,3,7 delims=: " %%i in ('netstat /ano') do (
+    if %%i==TCP (
+       if %%j==%dn_rpc_port% (
+         if !dn_rpc_port_occupied!==0 (
+           set spid=%%k
+           call :checkIfIOTDBProcess !spid! is_iotdb
+           if !is_iotdb!==1 (
+             set local_iotdb_occupied_ports=%dn_rpc_port% 
!local_iotdb_occupied_ports!
+           )
+         )
+
+       ) else if %%j==%cn_internal_port% (
+         if !cn_internal_port_occupied!==0 (
+             set spid=%%k
+             call :checkIfIOTDBProcess !spid! is_iotdb
+             if !is_iotdb!==1 (
+              set local_iotdb_occupied_ports=%cn_internal_port% 
!local_iotdb_occupied_ports!
+             )
+         )
+       )
+    )
+)
+
+if defined local_iotdb_occupied_ports (
+     goto :checkFail
+)
+
+set CLASSPATH=%CLASSPATH%;%IOTDB_HOME%\lib\*
+if NOT DEFINED MAIN_CLASS set 
MAIN_CLASS=org.apache.iotdb.tool.IoTDBDataBackTool
+
+"%JAVA_HOME%\bin\java" -DIOTDB_HOME=!IOTDB_HOME! !JAVA_OPTS! -cp !CLASSPATH! 
!MAIN_CLASS! %*
+pause
+exit /b
+
+:checkIfIOTDBProcess
+setlocal
+
+set "pid_to_check=%~1"
+set "is_iotdb=0"
+
+for /f "usebackq tokens=*" %%i in (`wmic process where 
"ProcessId=%pid_to_check%" get CommandLine /format:list ^| findstr 
/c:"CommandLine="`) do (
+    set command_line=%%i
+)
+echo %command_line% | findstr /i /c:"iotdb" >nul && set is_iotdb=1
+endlocal & set "is_iotdb=%is_iotdb%"
+exit /b
+
+:err
+echo JAVA_HOME environment variable must be set!
+set ret_code=1
+exit /b
+
+:checkFail
+echo Please stop IoTDB
+exit /b
\ No newline at end of file
diff --git a/iotdb-client/cli/src/assembly/resources/tools/backup.sh 
b/iotdb-client/cli/src/assembly/resources/tools/backup.sh
new file mode 100755
index 00000000000..56cf5d2c998
--- /dev/null
+++ b/iotdb-client/cli/src/assembly/resources/tools/backup.sh
@@ -0,0 +1,128 @@
+#!/bin/bash
+#
+# 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.
+#
+
+echo ------------------------------------------
+echo Starting IoTDB Client Data Back Script
+echo ------------------------------------------
+
+
+if [ -z "${IOTDB_INCLUDE}" ]; then
+  #do nothing
+  :
+elif [ -r "$IOTDB_INCLUDE" ]; then
+    . "$IOTDB_INCLUDE"
+fi
+
+if [ -z "${IOTDB_HOME}" ]; then
+    export IOTDB_HOME="$(cd "`dirname "$0"`"/..; pwd)"
+fi
+
+if [ -n "$JAVA_HOME" ]; then
+    for java in "$JAVA_HOME"/bin/amd64/java "$JAVA_HOME"/bin/java; do
+        if [ -x "$java" ]; then
+            JAVA="$java"
+            break
+        fi
+    done
+else
+    JAVA=java
+fi
+
+if [ -z $JAVA ] ; then
+    echo Unable to find java executable. Check JAVA_HOME and PATH environment 
variables.  > /dev/stderr
+    exit 1;
+fi
+
+datanodeclassname=org.apache.iotdb.db.service.DataNode
+
+confignodeclassname=org.apache.iotdb.db.service.ConfigNode
+
+check_tool_env() {
+  if  ! type lsof > /dev/null 2>&1 ; then
+    echo ""
+    echo " Warning: No tool 'lsof', Please install it."
+    echo " Note: Some checking function need 'lsof'."
+    echo ""
+    return 1
+  else
+    return 0
+  fi
+}
+
+get_properties_value() {
+    local file_name=$1
+    local property_name=$2
+    local default_value=$3
+    local property_value=$(sed "/^${property_name}=/!d;s/.*=//" 
"${IOTDB_HOME}/conf/${file_name}.properties")
+    if [ -z "$property_value" ]; then
+            property_value="$default_value"
+    fi
+    echo "$property_value"
+}
+iotdb_listening_ports=()
+check_running_process() {
+    DATANODE="iotdb-datanode"
+    CONFIGNODE="iotdb-confignode"
+    dn_rpc_port=$(get_properties_value $DATANODE "dn_rpc_port" "6667")
+    cn_internal_port=$(get_properties_value $CONFIGNODE "cn_internal_port" 
"10710")
+    local_ports+=("$dn_rpc_port")
+    local_ports+=("$cn_internal_port")
+    for port in "${local_ports[@]}"; do
+      # Check if lsof command is available
+      if command -v lsof >/dev/null 2>&1; then
+        listening=$(lsof -i :$port -sTCP:LISTEN -P -n | grep LISTEN)
+        if [ -n "$listening" ]; then
+            process_command=$(echo "$listening" | awk '{print $2}')
+            iotdb_check=$(ps -p "$process_command" -o args= | grep "iotdb")
+            if [ -n "$iotdb_check" ]; then
+              iotdb_listening_ports+=("$port ")
+            fi
+        fi
+      elif command -v netstat >/dev/null 2>&1; then
+          listening=$(netstat -tln | awk '{print $4}' | grep ":$port$")
+          if [ -n "$listening" ]; then
+            process_command=$(echo "$listening" | awk '{print $2}')
+            iotdb_check=$(ps -p "$process_command" -o args= | grep "iotdb")
+            if [ -n "$iotdb_check" ]; then
+              iotdb_listening_ports+=("$port ")
+            fi
+          fi
+      else
+          echo "Error: Unable to detect port occupation. Please install 'lsof' 
or 'netstat' command."
+          exit 1
+      fi
+    done
+    if [ ${#iotdb_listening_ports[@]} -gt 0 ]; then
+          echo " Please stop IoTDB"  >&2
+          echo " Exit..."  >&2
+          echo ""
+          exit 1
+    fi
+}
+
+check_running_process
+
+for f in ${IOTDB_HOME}/lib/*.jar; do
+    CLASSPATH=${CLASSPATH}":"$f
+done
+
+MAIN_CLASS=org.apache.iotdb.tool.IoTDBDataBackTool
+
+"$JAVA" -DIOTDB_HOME=${IOTDB_HOME} -cp "$CLASSPATH" "$MAIN_CLASS" "$@"
diff --git 
a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/IoTDBDataBackTool.java 
b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/IoTDBDataBackTool.java
new file mode 100644
index 00000000000..19388312050
--- /dev/null
+++ 
b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/IoTDBDataBackTool.java
@@ -0,0 +1,985 @@
+/*
+ * 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.commons.conf.IoTDBConstant;
+import org.apache.iotdb.db.conf.IoTDBConfig;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class IoTDBDataBackTool {
+  static Map<String, String> mm = new HashMap<>();
+  static Map<String, String> cpmm = new HashMap<>();
+  static String type = "";
+  static String nodeTypeParam = "";
+
+  static String targetDirParam = "";
+  static String targetDataDirParam = "";
+  static String targetWalDirParam = "";
+
+  static String DATA_NODE_CONF_NAME = IoTDBConfig.CONFIG_NAME;
+  static String CONFIG_NODE_CONF_NAME = "iotdb-confignode.properties";
+  static AtomicInteger fileCount = new AtomicInteger(0);
+  static AtomicInteger targetFileCount = new AtomicInteger(0);
+  static AtomicInteger processFileCount = new AtomicInteger(0);
+  static final String filename = "data.txt";
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(AbstractDataTool.class);
+
+  private static final IoTDBDescriptor ioTDBDescriptor = 
IoTDBDescriptor.getInstance();
+  static String sourcePath = System.getProperty(IoTDBConstant.IOTDB_HOME, 
null);
+  static String DEFAULT_DN_DATA_DIRS =
+      "data"
+          + File.separator
+          + IoTDBConstant.DN_ROLE
+          + File.separator
+          + IoTDBConstant.DATA_FOLDER_NAME;
+  static String DEFAULT_DN_SYSTEM_DIR =
+      "data"
+          + File.separator
+          + IoTDBConstant.DN_ROLE
+          + File.separator
+          + IoTDBConstant.SYSTEM_FOLDER_NAME;
+
+  static String DEFAULT_DN_CONSENSUS_DIR =
+      "data"
+          + File.separator
+          + IoTDBConstant.DN_ROLE
+          + File.separator
+          + IoTDBConstant.CONSENSUS_FOLDER_NAME;
+  static String DEFAULT_DN_WAL_DIRS =
+      "data"
+          + File.separator
+          + IoTDBConstant.DN_ROLE
+          + File.separator
+          + IoTDBConstant.WAL_FOLDER_NAME;
+
+  static String DEFAULT_DN_TRACING_DIR =
+      "data" + File.separator + IoTDBConstant.DN_ROLE + File.separator + 
"tracing";
+
+  static String DEFAULT_CN_SYSTEM_DIR =
+      "data"
+          + File.separator
+          + IoTDBConstant.CN_ROLE
+          + File.separator
+          + IoTDBConstant.SYSTEM_FOLDER_NAME;
+
+  static String DEFAULT_CN_CONSENSUS_DIR =
+      "data"
+          + File.separator
+          + IoTDBConstant.CN_ROLE
+          + File.separator
+          + IoTDBConstant.CONSENSUS_FOLDER_NAME;
+
+  private static void argsParse(String[] args) {
+    for (int i = 0; i < args.length; i++) {
+      if (args[i].equalsIgnoreCase("-quick")) {
+        type = "quick";
+      } else if (args[i].equalsIgnoreCase("-node") && i + 1 < args.length) {
+        nodeTypeParam = args[i + 1];
+      } else if (args[i].equalsIgnoreCase("-targetdir") && i + 1 < 
args.length) {
+        targetDirParam = args[i + 1];
+      } else if (args[i].equalsIgnoreCase("-targetdatadir") && i + 1 < 
args.length) {
+        targetDataDirParam = args[i + 1];
+      } else if (args[i].equalsIgnoreCase("-targetwaldir") && i + 1 < 
args.length) {
+        targetWalDirParam = args[i + 1];
+      }
+    }
+  }
+
+  public static boolean vaildParam(String dnDataDirs, String dnWalDirs) {
+    boolean isVaild = true;
+    if (type == null || type.trim().length() == 0 || !type.equals("quick")) {
+      if (targetDirParam.isEmpty()) {
+        LOGGER.error(" -targetdir cannot be empty, The backup folder must be 
specified");
+        isVaild = false;
+      }
+
+      if (!targetDataDirParam.isEmpty()) {
+        if (!matchPattern(targetDataDirParam, dnDataDirs)) {
+          LOGGER.error(
+              "-targetdatadir parameter exception, the number of original 
paths does not match the number of specified paths");
+          isVaild = false;
+        }
+      }
+
+      if (!targetWalDirParam.isEmpty()) {
+        if (!matchPattern(targetWalDirParam, dnWalDirs)) {
+          LOGGER.error(
+              "-targetwaldir parameter exception, the number of original paths 
does not match the number of specified paths");
+          isVaild = false;
+        }
+      }
+    }
+    return isVaild;
+  }
+
+  public static void main(String[] args) {
+    argsParse(args);
+    File sourceDir = new File(sourcePath);
+    Properties dataProperties = getProperties(IoTDBConfig.CONFIG_NAME);
+    initDataNodeProperties(dataProperties);
+    Properties configProperties = getProperties(CONFIG_NODE_CONF_NAME);
+    initConfigNodeProperties(configProperties);
+
+    StringBuilder targetDirString = new StringBuilder();
+    Map<String, String> copyMap = new HashMap<>();
+    Map<String, String> dnDataDirsMap = new HashMap<>();
+    Map<String, String> cnMapProperties = new HashMap<>();
+    Map<String, String> dnMapProperties = new HashMap<>();
+    processFileCount.set(readFileData(filename));
+    if (type != null && type.equals("quick")) {
+      targetDirString
+          .append(sourceDir.getParent())
+          .append(File.separatorChar)
+          .append("iotdb_backup");
+      File targetDir = new File(targetDirString.toString());
+      if (!targetDir.exists()) {
+        targetDir.mkdirs();
+      } else {
+        LOGGER.error("The backup folder already exists:{}", targetDirString);
+        System.exit(0);
+      }
+
+      countConfigNodeFile(targetDirString.toString(), copyMap, 
cnMapProperties);
+      countDataNodeFile(targetDirString.toString(), copyMap, dnDataDirsMap, 
dnMapProperties);
+      countNodeBack(targetDirString.toString(), copyMap);
+      for (Map.Entry<String, String> entry : copyMap.entrySet()) {
+        countFiles(entry.getKey());
+      }
+      for (Map.Entry<String, String> entry : dnDataDirsMap.entrySet()) {
+        countFiles(entry.getKey());
+      }
+
+      ioTDBDataBack(copyMap, dnDataDirsMap);
+      propertiesFileUpdate(
+          targetDirString.toString()
+              + File.separatorChar
+              + "conf"
+              + File.separatorChar
+              + CONFIG_NODE_CONF_NAME,
+          cnMapProperties);
+      propertiesFileUpdate(
+          targetDirString.toString()
+              + File.separatorChar
+              + "conf"
+              + File.separatorChar
+              + DATA_NODE_CONF_NAME,
+          dnMapProperties);
+    } else {
+      if (targetDirParam != null && targetDirParam.length() > 0) {
+        targetDirString.append(targetDirParam);
+        File targetDir = new File(targetDirString.toString());
+        if (!targetDir.exists()) {
+          targetDir.mkdirs();
+        }
+      }
+
+      if (nodeTypeParam.equalsIgnoreCase("confignode")) {
+        countConfigNodeFile(targetDirString.toString(), copyMap, 
cnMapProperties);
+        countNodeBack(targetDirString.toString(), copyMap);
+        for (Map.Entry<String, String> entry : copyMap.entrySet()) {
+          countFiles(entry.getKey());
+        }
+        ioTDBDataBack(copyMap, dnDataDirsMap);
+        propertiesFileUpdate(
+            targetDirString.toString()
+                + File.separatorChar
+                + "conf"
+                + File.separatorChar
+                + CONFIG_NODE_CONF_NAME,
+            cnMapProperties);
+      } else if (nodeTypeParam.equalsIgnoreCase("datanode")) {
+        countNodeBack(targetDirString.toString(), copyMap);
+        countDataNodeFile(targetDirString.toString(), copyMap, dnDataDirsMap, 
dnMapProperties);
+        for (Map.Entry<String, String> entry : copyMap.entrySet()) {
+          countFiles(entry.getKey());
+        }
+        for (Map.Entry<String, String> entry : dnDataDirsMap.entrySet()) {
+          countFiles(entry.getKey());
+        }
+        ioTDBDataBack(copyMap, dnDataDirsMap);
+        propertiesFileUpdate(
+            targetDirString.toString()
+                + File.separatorChar
+                + "conf"
+                + File.separatorChar
+                + DATA_NODE_CONF_NAME,
+            dnMapProperties);
+      } else if (nodeTypeParam.equalsIgnoreCase("all") || 
nodeTypeParam.isEmpty()) {
+        countNodeBack(targetDirString.toString(), copyMap);
+        countConfigNodeFile(targetDirString.toString(), copyMap, 
cnMapProperties);
+        countDataNodeFile(targetDirString.toString(), copyMap, dnDataDirsMap, 
dnMapProperties);
+        for (Map.Entry<String, String> entry : copyMap.entrySet()) {
+          countFiles(entry.getKey());
+        }
+        for (Map.Entry<String, String> entry : dnDataDirsMap.entrySet()) {
+          countFiles(entry.getKey());
+        }
+        ioTDBDataBack(copyMap, dnDataDirsMap);
+        propertiesFileUpdate(
+            targetDirString.toString()
+                + File.separatorChar
+                + "conf"
+                + File.separatorChar
+                + CONFIG_NODE_CONF_NAME,
+            cnMapProperties);
+        propertiesFileUpdate(
+            targetDirString.toString()
+                + File.separatorChar
+                + "conf"
+                + File.separatorChar
+                + DATA_NODE_CONF_NAME,
+            dnMapProperties);
+      }
+    }
+    LOGGER.info("all operations are complete");
+    delFile(filename);
+  }
+
+  private static void ioTDBDataBack(
+      Map<String, String> copyMap, Map<String, String> dnDataDirsMap) {
+
+    for (Map.Entry<String, String> entry : copyMap.entrySet()) {
+      File file = new File(entry.getKey());
+      if (file.isDirectory()) {
+        compareAndcopyDirectory(file, new File(entry.getValue()));
+      } else {
+        if (file.exists()) {
+          File targetFile = new File(entry.getValue());
+          try {
+            Files.copy(file.toPath(), targetFile.toPath(), 
StandardCopyOption.REPLACE_EXISTING);
+            targetFileCount.incrementAndGet();
+          } catch (IOException e) {
+            LOGGER.error("copy file error", e);
+          }
+        }
+      }
+    }
+
+    for (Map.Entry<String, String> entry : dnDataDirsMap.entrySet()) {
+      File file = new File(entry.getKey());
+      if (file.isDirectory()) {
+        compareAndLinkDirectory(file, new File(entry.getValue()));
+      } else {
+        if (file.exists()) {
+          File targetFile = new File(entry.getValue());
+          try {
+            Files.copy(file.toPath(), targetFile.toPath(), 
StandardCopyOption.REPLACE_EXISTING);
+            targetFileCount.incrementAndGet();
+          } catch (IOException e) {
+            LOGGER.error("copy file error", e);
+          }
+        }
+      }
+    }
+  }
+
+  private static void countNodeBack(String targetDirString, Map<String, 
String> copyMap) {
+    File sourceDir = new File(sourcePath);
+    Properties dataProperties = getProperties(IoTDBConfig.CONFIG_NAME);
+    initDataNodeProperties(dataProperties);
+    Properties configProperties = getProperties(CONFIG_NODE_CONF_NAME);
+    initConfigNodeProperties(configProperties);
+
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + ".env",
+        targetDirString + File.separatorChar + ".env");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + "conf",
+        targetDirString + File.separatorChar + "conf");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + "ext",
+        targetDirString + File.separatorChar + "ext");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + "licenses",
+        targetDirString + File.separatorChar + "licenses");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + "tools",
+        targetDirString + File.separatorChar + "tools");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + "sbin",
+        targetDirString + File.separatorChar + "sbin");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + "LICENSE",
+        targetDirString + File.separatorChar + "LICENSE");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + "NOTICE",
+        targetDirString + File.separatorChar + "NOTICE");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + "README.md",
+        targetDirString + File.separatorChar + "README.md");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + "README_ZH.md",
+        targetDirString + File.separatorChar + "README_ZH.md");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + File.separatorChar 
+ "RELEASE_NOTES.md",
+        targetDirString + File.separatorChar + "RELEASE_NOTES.md");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + "activation",
+        targetDirString + File.separatorChar + "activation");
+    copyMap.put(
+        sourceDir.getAbsolutePath() + File.separatorChar + "lib",
+        targetDirString + File.separatorChar + "lib");
+  }
+
+  private static void countDataNodeFile(
+      String targetDirString,
+      Map<String, String> copyMap,
+      Map<String, String> dnDataDirsMap,
+      Map<String, String> dnMapProperties) {
+    Properties dataProperties = getProperties(IoTDBConfig.CONFIG_NAME);
+    initDataNodeProperties(dataProperties);
+
+    String dnSystemDir = dataProperties.getProperty("dn_system_dir");
+    String dnConsensusDir = dataProperties.getProperty("dn_consensus_dir");
+
+    String dnTracingDir = dataProperties.getProperty("dn_tracing_dir");
+
+    String dnWalDirs = dataProperties.getProperty("dn_wal_dirs");
+    String dnDataDirs = dataProperties.getProperty("dn_data_dirs");
+
+    dnSystemDir = pathHandler(dnSystemDir);
+    dnConsensusDir = pathHandler(dnConsensusDir);
+    dnTracingDir = pathHandler(dnTracingDir);
+    dnWalDirs = pathHandler(dnWalDirs);
+    dnDataDirs = pathHandler(dnDataDirs);
+    String bakDnSystemDir = targetDirString + File.separatorChar + 
DEFAULT_DN_SYSTEM_DIR;
+    String bakDnConsensusDir = targetDirString + File.separatorChar + 
DEFAULT_DN_CONSENSUS_DIR;
+    String bakDnTracingDir = targetDirString + File.separatorChar + 
DEFAULT_DN_TRACING_DIR;
+    String bakDnWalDirs = targetDirString + File.separatorChar + 
DEFAULT_DN_WAL_DIRS;
+
+    if (type.equals("quick")) {
+      targetDataDirParam = 
sourceDnDataDirsCoverTargetDnDataDirsHandler(dnDataDirs);
+      targetWalDirParam = sourceWalCoverTargetWalDirsHandler(dnWalDirs, 
bakDnWalDirs);
+    }
+    if (targetWalDirParam.isEmpty()) {
+      targetWalDirParam = sourceWalCoverTargetWalDirsHandler(dnWalDirs, 
bakDnWalDirs);
+    } else {
+      targetWalDirParam = getCreateDnDataPathString(dnWalDirs, 
targetWalDirParam, "wal");
+    }
+    String targetDnDataDirs = "";
+    if (targetDataDirParam.isEmpty()) {
+      targetDnDataDirs = 
sourceDnDataDirsCoverTargetDnDataDirsHandler(dnDataDirs);
+    } else {
+      targetDnDataDirs = getCreateDnDataPathString(dnDataDirs, 
targetDataDirParam, "data");
+    }
+    // dnDataDirs = pathHandler(targetDataDirParam);
+    if (!vaildParam(targetDataDirParam, targetWalDirParam)) {
+      System.exit(0);
+    }
+
+    Map<String, String> dnSystemDirMap =
+        getCreatePathMapping(Objects.requireNonNull(dnSystemDir), 
bakDnSystemDir, "system");
+    dnDataDirsMap.putAll(getCreatePathMapping(dnDataDirs, targetDnDataDirs, 
"data"));
+    Map<String, String> dnConsensusDirMap =
+        getCreatePathMapping(
+            Objects.requireNonNull(dnConsensusDir), bakDnConsensusDir, 
"consensus");
+    Map<String, String> dnTracingDirMap =
+        getCreatePathMapping(dnTracingDir, bakDnTracingDir, "tracing");
+    Map<String, String> dnWalDirsMap = getCreatePathMapping(dnWalDirs, 
targetWalDirParam, "wal");
+    copyMap.putAll(dnSystemDirMap);
+    copyMap.putAll(dnConsensusDirMap);
+    copyMap.putAll(dnWalDirsMap);
+    copyMap.putAll(dnTracingDirMap);
+
+    dnMapProperties.put("dn_system_dir", bakDnSystemDir);
+    dnMapProperties.put("dn_data_dirs", targetDnDataDirs);
+    dnMapProperties.put("dn_wal_dirs", targetWalDirParam);
+    dnMapProperties.put("dn_tracing_dir", bakDnTracingDir);
+    dnMapProperties.put("dn_consensus_dir", bakDnConsensusDir);
+  }
+
+  private static void countConfigNodeFile(
+      String targetDirString, Map<String, String> copyMap, Map<String, String> 
cnMapProperties) {
+    Properties configProperties = getProperties(CONFIG_NODE_CONF_NAME);
+    initConfigNodeProperties(configProperties);
+
+    String bakCnSystemDir = targetDirString + File.separatorChar + 
DEFAULT_CN_SYSTEM_DIR;
+    String bakCnConsensusDir = targetDirString + File.separatorChar + 
DEFAULT_CN_CONSENSUS_DIR;
+
+    if (!vaildParam(targetDataDirParam, targetWalDirParam)) {
+      System.exit(0);
+    }
+    String cnSystemDir = configProperties.getProperty("cn_system_dir");
+    String cnConsensusDir = configProperties.getProperty("cn_consensus_dir");
+    cnSystemDir = pathHandler(cnSystemDir);
+    cnConsensusDir = pathHandler(cnConsensusDir);
+    Map<String, String> cnSystemDirMap =
+        getCreatePathMapping(cnSystemDir, bakCnSystemDir, "system");
+    Map<String, String> cnConsensusDirMap =
+        getCreatePathMapping(cnConsensusDir, bakCnConsensusDir, "consensus");
+
+    copyMap.putAll(cnSystemDirMap);
+    copyMap.putAll(cnConsensusDirMap);
+
+    cnMapProperties.put("cn_system_dir", bakCnSystemDir);
+    cnMapProperties.put("cn_consensus_dir", bakCnConsensusDir);
+  }
+
+  private static String pathHandler(String pathsList) {
+    StringBuilder pathStrb = new StringBuilder();
+    String[] pathList = pathsList.split(";");
+    for (int t = 0; t < pathList.length; t++) {
+      String paths = pathList[t];
+      String[] dirList = paths.split(",");
+      for (int i = 0; i < dirList.length; i++) {
+        if (isRelativePath(dirList[i])) {
+          if (i == 0) {
+            
pathStrb.append(sourcePath).append(File.separatorChar).append(dirList[i]);
+          } else {
+            pathStrb.append(",");
+            
pathStrb.append(sourcePath).append(File.separatorChar).append(dirList[i]);
+          }
+        } else {
+          if (i == 0) {
+            pathStrb.append(dirList[i]);
+          } else {
+            pathStrb.append(",");
+            pathStrb.append(dirList[i]);
+          }
+        }
+      }
+      if (t < pathList.length - 1) {
+        pathStrb.append(";");
+      }
+    }
+
+    return pathStrb.toString();
+  }
+
+  private static boolean isRelativePath(String path) {
+    Path p = Paths.get(path);
+    return !p.isAbsolute();
+  }
+
+  public static String sourceDnDataDirsCoverTargetDnDataDirsHandler(String 
dnDirs) {
+    String[] sourcePathsList = dnDirs.split(";");
+    StringBuilder targetDataDirSb = new StringBuilder();
+    for (int t = 0; t < sourcePathsList.length; t++) {
+      String sourcePaths = sourcePathsList[t];
+      String[] sourcePathList = sourcePaths.split(",");
+      StringBuilder subTargetDataDir = new StringBuilder();
+      for (int i = 0; i < sourcePathList.length; i++) {
+        String path = sourcePathList[i];
+        path = path + "_back";
+        if (i == sourcePathList.length - 1) {
+          subTargetDataDir.append(path);
+        } else {
+          subTargetDataDir.append(path).append(",");
+        }
+      }
+      if (t == sourcePathsList.length - 1) {
+        targetDataDirSb.append(subTargetDataDir);
+      } else {
+        targetDataDirSb.append(subTargetDataDir).append(";");
+      }
+    }
+    return targetDataDirSb.toString();
+  }
+
+  public static String sourceWalCoverTargetWalDirsHandler(String dnDirs, 
String targetDirs) {
+    String[] sourcePathList = dnDirs.split(",");
+    StringBuilder subTargetDataDir = new StringBuilder();
+    for (int i = 0; i < sourcePathList.length; i++) {
+      if (i == sourcePathList.length - 1) {
+        
subTargetDataDir.append(targetDirs).append(File.separatorChar).append("wal").append(i
 + 1);
+      } else {
+        subTargetDataDir
+            .append(targetDirs)
+            .append(File.separatorChar)
+            .append("wal")
+            .append(i + 1)
+            .append(",");
+      }
+    }
+    return subTargetDataDir.toString();
+  }
+
+  public static void propertiesFileUpdate(
+      String sourcePropertiesPath, Map<String, String> mapProperties) {
+    for (Map.Entry<String, String> entry : mapProperties.entrySet()) {
+      propertiesFileUpdate(sourcePropertiesPath, entry.getKey(), 
entry.getValue());
+    }
+  }
+
+  public static String getCreateDnDataPathString(
+      String resourcePath, String targetPath, String dirType) {
+
+    String[] sourcePathsList = resourcePath.split(";");
+    String[] targetPathsList = targetPath.split(";");
+    StringBuilder pathStrb = new StringBuilder();
+    if (sourcePathsList.length != targetPathsList.length) {
+      int num = 1;
+      for (int i = 0; i < sourcePathsList.length; i++) {
+        String[] sourcePathArray = sourcePathsList[i].split(",");
+        for (int j = 0; j < sourcePathArray.length; j++) {
+          String newPath = targetPathsList[0];
+          if (sourcePathsList.length == 1 && targetPathsList.length == 1) {
+            newPath = newPath + File.separatorChar + dirType;
+          } else {
+            newPath = newPath + File.separatorChar + dirType + num;
+          }
+          pathStrb.append(newPath);
+          if (j < sourcePathArray.length - 1) {
+            pathStrb.append(",");
+          }
+          num++;
+        }
+        if (i < sourcePathsList.length - 1) {
+          pathStrb.append(";");
+        }
+      }
+    } else {
+      int num = 1;
+      for (int i = 0; i < sourcePathsList.length; i++) {
+        String[] sourcePathArray = sourcePathsList[i].split(",");
+        String[] targetPathArray = targetPathsList[i].split(",");
+        if (sourcePathArray.length != targetPathArray.length) {
+          if (targetPathArray.length == 1) {
+            for (int j = 0; j < sourcePathArray.length; j++) {
+              String newPath = "";
+              if (sourcePathsList.length == 1 && targetPathsList.length == 1) {
+                newPath = targetPathArray[0] + File.separatorChar + dirType;
+              } else {
+                newPath = targetPathArray[0] + File.separatorChar + dirType + 
num;
+              }
+              pathStrb.append(newPath);
+              if (j < sourcePathArray.length - 1) {
+                pathStrb.append(",");
+              }
+              num++;
+            }
+          } else {
+            for (int j = 0; j < sourcePathArray.length; j++) {
+              pathStrb.append(targetPathArray[j]);
+              if (j < sourcePathArray.length - 1) {
+                pathStrb.append(",");
+              }
+            }
+          }
+        } else {
+          for (int j = 0; j < sourcePathArray.length; j++) {
+            pathStrb.append(targetPathArray[j]);
+            if (j < sourcePathArray.length - 1) {
+              pathStrb.append(",");
+            }
+          }
+        }
+        if (sourcePathsList.length > 1 && i < sourcePathsList.length - 1) {
+          pathStrb.append(";");
+        }
+      }
+    }
+
+    return pathStrb.toString();
+  }
+
+  public static Map<String, String> getCreatePathMapping(
+      String resourcePath, String targetPath, String dirType) {
+    Map<String, String> map = new HashMap<>();
+    String[] sourcePathsList = resourcePath.split(";");
+    String[] targetPathsList = targetPath.split(";");
+    if (sourcePathsList.length != targetPathsList.length) {
+      int num = 1;
+      for (int i = 0; i < sourcePathsList.length; i++) {
+        String[] sourcePathArray = sourcePathsList[i].split(",");
+        for (int j = 0; j < sourcePathArray.length; j++) {
+          String newPath = targetPathsList[0];
+          if (sourcePathsList.length == 1 && targetPathsList.length == 1) {
+            newPath = newPath + File.separatorChar + dirType;
+          } else {
+            newPath = newPath + File.separatorChar + dirType + num;
+          }
+          createDirectory(newPath);
+          map.put(sourcePathArray[j], newPath);
+          num++;
+        }
+      }
+    } else {
+      int num = 1;
+      for (int i = 0; i < sourcePathsList.length; i++) {
+        String[] sourcePathArray = sourcePathsList[i].split(",");
+        String[] targetPathArray = targetPathsList[i].split(",");
+        if (sourcePathArray.length != targetPathArray.length) {
+          if (targetPathArray.length == 1) {
+            for (int j = 0; j < sourcePathArray.length; j++) {
+              String newPath = "";
+              if (sourcePathsList.length == 1 && targetPathsList.length == 1) {
+                newPath = targetPathArray[0] + File.separatorChar + dirType;
+              } else {
+                newPath = targetPathArray[0] + File.separatorChar + dirType + 
num;
+              }
+              createDirectory(newPath);
+              map.put(sourcePathArray[j], newPath);
+              num++;
+            }
+          } else {
+            for (int j = 0; j < sourcePathArray.length; j++) {
+              map.put(sourcePathArray[j], targetPathArray[j]);
+            }
+          }
+        } else {
+          for (int j = 0; j < sourcePathArray.length; j++) {
+            map.put(sourcePathArray[j], targetPathArray[j]);
+          }
+        }
+      }
+    }
+
+    return map;
+  }
+
+  public static boolean matchPattern(String input, String pattern) {
+    if (input.contains(";") && pattern.contains(";")) {
+      String[] inputDirs = input.split(";");
+      String[] patternDirs = pattern.split(";");
+      if (inputDirs.length != patternDirs.length) {
+        return false;
+      }
+      for (int i = 0; i < inputDirs.length; i++) {
+        String inputDir = inputDirs[i];
+        String patternDir = patternDirs[i];
+        if (!matchDirectory(inputDir, patternDir)) {
+          return false;
+        }
+      }
+      return true;
+    } else if (pattern.contains(";") && !input.contains(";")) {
+      return !input.contains(",");
+    } else if (!pattern.contains(";") && input.contains(";")) {
+      return false;
+    }
+    return matchDirectory(input, pattern);
+  }
+
+  private static boolean matchDirectory(String inputDir, String patternDir) {
+    String[] inputLevels = inputDir.split(",");
+    String[] patternLevels = patternDir.split(",");
+    return inputLevels.length == patternLevels.length || inputLevels.length == 
1;
+  }
+
+  private static void initDataNodeProperties(Properties properties) {
+    if (properties.getProperty("dn_system_dir") == null) {
+      properties.setProperty("dn_system_dir", DEFAULT_DN_SYSTEM_DIR);
+    }
+    if (properties.getProperty("dn_consensus_dir") == null) {
+      properties.setProperty("dn_consensus_dir", DEFAULT_DN_CONSENSUS_DIR);
+    }
+    if (properties.getProperty("dn_data_dirs") == null) {
+      properties.setProperty("dn_data_dirs", DEFAULT_DN_DATA_DIRS);
+    }
+    if (properties.getProperty("dn_tracing_dir") == null) {
+      properties.setProperty("dn_tracing_dir", DEFAULT_DN_TRACING_DIR);
+    }
+    if (properties.getProperty("dn_wal_dirs") == null) {
+      properties.setProperty("dn_wal_dirs", DEFAULT_DN_WAL_DIRS);
+    }
+  }
+
+  private static void initConfigNodeProperties(Properties properties) {
+
+    if (properties.getProperty("cn_system_dir") == null) {
+      properties.setProperty("cn_system_dir", DEFAULT_CN_SYSTEM_DIR);
+    }
+    if (properties.getProperty("cn_consensus_dir") == null) {
+      properties.setProperty("cn_consensus_dir", DEFAULT_CN_CONSENSUS_DIR);
+    }
+  }
+
+  private static Properties getProperties(String configName) {
+    URL url = ioTDBDescriptor.getPropsUrl(configName);
+    Properties properties = new Properties();
+    if (url != null) {
+      try (InputStream inputStream = url.openStream()) {
+        LOGGER.info("Start to read config file {}", url);
+        properties.load(new InputStreamReader(inputStream, 
StandardCharsets.UTF_8));
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+    return properties;
+  }
+
+  private static boolean filesAreEqual(Path file1, Path file2) throws 
IOException {
+    long size1 = Files.size(file1);
+    long size2 = Files.size(file2);
+    return size1 == size2;
+  }
+
+  public static void compareAndcopyDirectory(File sourceDirectory, File 
targetDirectory) {
+    try {
+      Files.walkFileTree(
+          sourceDirectory.toPath(),
+          new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes 
attrs)
+                throws IOException {
+              Path targetFile =
+                  
targetDirectory.toPath().resolve(sourceDirectory.toPath().relativize(file));
+              if (Files.exists(file)) {
+                cpmm.put(file.toFile().getAbsolutePath(), "1");
+                targetFileCount.incrementAndGet();
+                if (!Files.exists(targetFile) || !filesAreEqual(file, 
targetFile)) {
+                  Files.copy(file, targetFile, 
StandardCopyOption.REPLACE_EXISTING);
+                }
+              }
+              if (processFileCount.get() > targetFileCount.get()) {
+                writeFileData(filename, processFileCount.get());
+                LOGGER.info(
+                    "total file number:" + fileCount + ",backup file number:" 
+ processFileCount);
+              } else {
+                writeFileData(filename, targetFileCount.get());
+                LOGGER.info(
+                    "total file number:" + fileCount + ",backup file number:" 
+ targetFileCount);
+              }
+              return FileVisitResult.CONTINUE;
+            }
+
+            @Override
+            public FileVisitResult preVisitDirectory(Path dir, 
BasicFileAttributes attrs)
+                throws IOException {
+              Path targetDir =
+                  
targetDirectory.toPath().resolve(sourceDirectory.toPath().relativize(dir));
+              if (!Files.exists(targetDir)) {
+                Files.createDirectories(targetDir);
+              }
+              return FileVisitResult.CONTINUE;
+            }
+          });
+    } catch (IOException e) {
+      LOGGER.error("copy file error {}", sourceDirectory, e);
+    }
+  }
+
+  public static void createDirectory(String directoryPath) {
+    File directory = new File(directoryPath);
+    if (!directory.exists()) {
+      boolean created = directory.mkdirs();
+      if (created) {
+        LOGGER.info("Directory created successfully:{}", directoryPath);
+      } else {
+        LOGGER.error("Failed to create directory:{}", directoryPath);
+      }
+    }
+  }
+
+  public static void compareAndLinkDirectory(File sourceDirectory, File 
targetDirectory) {
+    try {
+      Files.walkFileTree(
+          sourceDirectory.toPath(),
+          new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes 
attrs)
+                throws IOException {
+              Path targetFile =
+                  
targetDirectory.toPath().resolve(sourceDirectory.toPath().relativize(file));
+              if (Files.exists(file)) {
+                cpmm.put(file.toFile().getAbsolutePath(), "1");
+                targetFileCount.incrementAndGet();
+                if (!Files.exists(targetFile) || !filesAreEqual(file, 
targetFile)) {
+                  try {
+                    Files.createLink(targetFile, file);
+                  } catch (UnsupportedOperationException | IOException e) {
+                    LOGGER.error("link file error {}", sourceDirectory, e);
+                    try {
+                      Files.copy(file, targetFile, 
StandardCopyOption.REPLACE_EXISTING);
+                    } catch (IOException ex) {
+                      targetFileCount.decrementAndGet();
+                      LOGGER.error("copy file error {}", sourceDirectory, ex);
+                    }
+                  }
+                }
+              }
+              if (processFileCount.get() > targetFileCount.get()) {
+                writeFileData(filename, processFileCount.get());
+                LOGGER.info(
+                    "total file number:" + fileCount + ",backup file number:" 
+ processFileCount);
+
+              } else {
+                writeFileData(filename, targetFileCount.get());
+                LOGGER.info(
+                    "total file number:" + fileCount + ",backup file number:" 
+ targetFileCount);
+              }
+              return FileVisitResult.CONTINUE;
+            }
+
+            @Override
+            public FileVisitResult preVisitDirectory(Path dir, 
BasicFileAttributes attrs)
+                throws IOException {
+              Path targetDir =
+                  
targetDirectory.toPath().resolve(sourceDirectory.toPath().relativize(dir));
+              if (!Files.exists(targetDir)) {
+                Files.createDirectories(targetDir);
+              }
+              return FileVisitResult.CONTINUE;
+            }
+          });
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private static String formatPathForOS(String path) {
+    String os = System.getProperty("os.name").toLowerCase();
+    if (os.contains("win")) {
+      return path.replace("\\", "\\\\");
+    } else {
+      return path;
+    }
+  }
+
+  public static void propertiesFileUpdate(String filePath, String key, String 
newValue) {
+    try {
+      newValue = formatPathForOS(newValue);
+      FileInputStream fileInputStream = new FileInputStream(filePath);
+      BufferedReader reader = new BufferedReader(new 
InputStreamReader(fileInputStream));
+
+      List<String> lines = new ArrayList<>();
+      String line;
+      while ((line = reader.readLine()) != null) {
+        lines.add(line);
+      }
+      reader.close();
+      boolean keyFound = false;
+
+      for (int i = 0; i < lines.size(); i++) {
+        String currentLine = lines.get(i);
+        currentLine = currentLine.trim();
+        if (currentLine.startsWith("#") && 
currentLine.substring(1).trim().equals(key)) {
+        } else if (currentLine.contains("=")) {
+          int equalsIndex = currentLine.indexOf("=");
+          String propertyKey = currentLine.substring(0, equalsIndex).trim();
+          if (propertyKey.equals(key)) {
+            lines.set(i, propertyKey + "=" + newValue);
+            keyFound = true;
+            break;
+          }
+        }
+      }
+      if (!keyFound) {
+        lines.add(key + "=" + newValue);
+      }
+
+      FileOutputStream fileOutputStream = new FileOutputStream(filePath);
+      PrintWriter printWriter = new PrintWriter(fileOutputStream);
+      for (String fileLine : lines) {
+        printWriter.println(fileLine);
+      }
+
+      printWriter.close();
+      fileOutputStream.close();
+
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+
+  public static int countFiles(String directoryPath) {
+    countFilesRecursively(new File(directoryPath), fileCount);
+    return fileCount.get();
+  }
+
+  private static void countFilesRecursively(File file, AtomicInteger 
fileCount) {
+
+    if (file.isDirectory() && file.exists()) {
+      File[] files = file.listFiles();
+      if (files != null) {
+        for (File subFile : files) {
+          countFilesRecursively(subFile, fileCount);
+        }
+      }
+    } else {
+      if (file.exists()) {
+        mm.put(file.getAbsolutePath(), "1");
+        fileCount.incrementAndGet();
+      }
+    }
+  }
+
+  public static int readFileData(String filename) {
+    Path filePath = Paths.get(filename);
+    createFile(filename);
+
+    try {
+      List<String> lines = Files.readAllLines(filePath, 
StandardCharsets.UTF_8);
+      if (!lines.isEmpty()) {
+        return Integer.parseInt(lines.get(0));
+      }
+    } catch (IOException e) {
+      LOGGER.error("Failed to read data from file: {}", filename, e);
+    }
+    return 0;
+  }
+
+  public static void delFile(String filename) {
+    File file = new File(filename);
+    if (file.exists()) {
+      file.delete();
+    }
+  }
+
+  public static void writeFileData(String filename, int data) {
+    Path filePath = Paths.get(filename);
+    try {
+      Files.write(filePath, 
Integer.toString(data).getBytes(StandardCharsets.UTF_8));
+    } catch (IOException e) {
+      LOGGER.error("Failed to write data to file: {}", filename, e);
+    }
+  }
+
+  public static void createFile(String filename) {
+    Path filePath = Paths.get(filename);
+    if (!Files.exists(filePath)) {
+      try {
+        Files.createFile(filePath);
+      } catch (IOException e) {
+        LOGGER.error("Failed to create file: {}", filename, e);
+      }
+    }
+  }
+}


Reply via email to