@SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
  public void run() throws IOException {
    if (ModificationFile.getExclusiveMods(new File(filename)).exists()) {
      throw new IOException("Unsupported to split TsFile with modification currently.");
    }

    TsFileIOWriter writer = null;

    try (TsFileSequenceReader reader = new TsFileSequenceReader(filename)) {
      Iterator<List<Path>> pathIterator = reader.getPathsIterator();
      Set<IDeviceID> devices = new HashSet<>();
      String[] filePathSplit = filename.split(IoTDBConstant.FILE_NAME_SEPARATOR);
      int originVersionIndex = Integer.parseInt(filePathSplit[filePathSplit.length - 3]);
      int versionIndex = originVersionIndex + 1;
      filePathSplit[filePathSplit.length - 2] = levelNum;

      while (pathIterator.hasNext()) {
        for (Path path : pathIterator.next()) {
          IDeviceID deviceId = path.getIDeviceID();
          if (devices.add(deviceId)) {
            if (writer != null && writer.getPos() < targetSplitFileSize) {
              writer.endChunkGroup();
              writer.startChunkGroup(deviceId);
            } else {
              if (writer != null) {
                // seal last TsFile
                TsFileResource resource = endFileAndGenerateResource(writer);
                resource.close();
              }

              filePathSplit[filePathSplit.length - 3] = String.valueOf(versionIndex);
              StringBuilder sb = new StringBuilder();
              for (int i = 0; i < filePathSplit.length; i++) {
                sb.append(filePathSplit[i]);
                if (i != filePathSplit.length - 1) {
                  sb.append(IoTDBConstant.FILE_NAME_SEPARATOR);
                }
              }
              // open a new TsFile
              writer = new TsFileIOWriter(fsFactory.getFile(sb.toString()));
              versionIndex++;
              writer.startChunkGroup(deviceId);
            }
          }

          List<ChunkMetadata> chunkMetadataList = reader.getChunkMetadataList(path);
          assert writer != null;

          ChunkMetadata firstChunkMetadata = chunkMetadataList.get(0);
          reader.position(firstChunkMetadata.getOffsetOfChunkHeader());
          ChunkHeader chunkHeader = reader.readChunkHeader(reader.readMarker());
          if (chunkHeader.getChunkType()
                  == (byte) (MetaMarker.CHUNK_HEADER | TsFileConstant.TIME_COLUMN_MASK)
              || chunkHeader.getChunkType()
                  == (byte) (MetaMarker.CHUNK_HEADER | TsFileConstant.VALUE_COLUMN_MASK)
              || chunkHeader.getChunkType()
                  == (byte)
                      (MetaMarker.ONLY_ONE_PAGE_CHUNK_HEADER | TsFileConstant.TIME_COLUMN_MASK)
              || chunkHeader.getChunkType()
                  == (byte)
                      (MetaMarker.ONLY_ONE_PAGE_CHUNK_HEADER | TsFileConstant.VALUE_COLUMN_MASK)) {
            throw new IOException("Unsupported to split TsFile with aligned timeseries currently.");
          }

          MeasurementSchema measurementSchema =
              new MeasurementSchema(
                  chunkHeader.getMeasurementID(), chunkHeader.getDataType(),
                  chunkHeader.getEncodingType(), chunkHeader.getCompressionType());

          int numInChunk = 0;
          ChunkWriterImpl chunkWriter = new ChunkWriterImpl(measurementSchema);

          for (int i = 0; i < chunkMetadataList.size(); i++) {
            if (i != 0) {
              reader.position(chunkMetadataList.get(i).getOffsetOfChunkHeader());
              chunkHeader = reader.readChunkHeader(reader.readMarker());
            }

            TSDataType dataType = chunkHeader.getDataType();
            int dataSize = chunkHeader.getDataSize();
            Decoder valueDecoder =
                Decoder.getDecoderByType(chunkHeader.getEncodingType(), dataType);
            Decoder defaultTimeDecoder =
                Decoder.getDecoderByType(
                    TSEncoding.valueOf(TSFileDescriptor.getInstance().getConfig().getTimeEncoder()),
                    TSDataType.INT64);

            while (dataSize > 0) {
              valueDecoder.reset();

              // a new Page
              PageHeader pageHeader =
                  reader.readPageHeader(
                      dataType,
                      ((byte) (chunkHeader.getChunkType() & 0x3F)) == MetaMarker.CHUNK_HEADER);
              ByteBuffer pageData = reader.readPage(pageHeader, chunkHeader.getCompressionType());
              PageReader pageReader =
                  new PageReader(pageData, dataType, valueDecoder, defaultTimeDecoder);
              BatchData batchData = pageReader.getAllSatisfiedPageData();

              while (batchData.hasCurrent()) {
                writeToChunkWriter(
                    chunkWriter,
                    batchData.currentTime(),
                    batchData.currentValue(),
                    chunkHeader.getDataType());
                numInChunk++;
                if (numInChunk == chunkPointNumLowerBoundInCompaction) {
                  chunkWriter.writeToFileWriter(writer);
                  numInChunk = 0;
                }
                batchData.next();
              }

              dataSize -= pageHeader.getSerializedPageSize();
            }
          }
          if (numInChunk != 0) {
            chunkWriter.writeToFileWriter(writer);
          }
        }
      }

      if (writer != null) {
        // seal last TsFile
        TsFileResource resource = endFileAndGenerateResource(writer);
        resource.close();
      }
    } finally {
      if (writer != null) {
        writer.close();
      }
    }
  }
If the chunk point num is lower than this threshold, it will be deserialized into points,
default is 100
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/TsFileSplitTool.java