You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tsfile.apache.org by ji...@apache.org on 2026/09/08 10:55:09 UTC

(tsfile) branch develop updated: Refactor data type handling with type interfaces (#872)

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

jt2594838 pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/tsfile.git


The following commit(s) were added to refs/heads/develop by this push:
     new 02b503b92 Refactor data type handling with type interfaces (#872)
02b503b92 is described below

commit 02b503b92416a04fcfb360f446c08ef3e0978ed2
Author: Jiang Tian <jt...@163.com>
AuthorDate: Tue Sep 8 18:55:03 2026 +0800

    Refactor data type handling with type interfaces (#872)
    
    * add interface for addValueOfDataType
    
    * add interface for createValueColumnOfDataType
    
    * add interface for serializeColumn
    
    * add interface for readvaluesFromBuffer
    
    * add interface for equals
    
    * add interface for getValue
    
    * add interface for ramBytesUsed
    
    * add interface for ramBytesUsed
    
    * add interface for createColumn
    
    * Add TypeServices
    
    * Add TypeServices
    
    * Add getTsPrimitiveType
    
    * Add arePositionsEqual
    
    * Add arePositionsEqual
    
    * Add getDefaultEncoding
    
    * Add toBytes
    
    * Add getCompressor
    
    * Add calcTypeSize
    
    * Add getDecoder
    
    * Add getOneItemMaxSize
    
    * Add updateStatistics
    
    * Add getCurrentValue
    
    * refactor calcTypeSize
    
    * refactor calcTypeSize
    
    * refactor currentTsPrimitiveType
    
    * refactor BatchData.init
    
    * refactor BatchData.putAnObject
    
    * refactor BatchData.serializeData
    
    * refactor DescReadWriteBatchData.new
    
    * refactor DescReadWriteBatchData.serializeData
    
    * refactor Field.getStringValue
    
    * add Type.estimateArraySize
    
    * add Type.estimateArraySize
    
    * add Type.estimateValueSize
    
    * add Field.getObjectValue
    
    * add Field.getField
    
    * add Field.setTsPrimitiveValue
    
    * add Type.deserializeColumn
    
    * add Type.deserializeColumn
    
    * add Column.serializeWithoutNulls
    
    * add Type.createNullColumn
    
    * add Type.addPoint
    
    * add READ_PAGE_VALUE_TO_BATCHDATA_SERVICE
    
    * add READ_PAGE_VALUE_TO_TSBLOCK_SERVICE
    
    * refactor nextBatch
    
    * refactor nextValue
    
    * refactor nextValueBatch
    
    * refactor writeColumnBuilderWithNextBatch
    
    * refactor writeColumnBuilderWithNextBatch
    
    * refactor writeColumnBuilderWithNextBatch
    
    * refactor writeEmptyDataInOneRow
    
    * refactor getDataPoint
    
    * refactor write
    
    * refactor write
    
    * refactor write
    
    * refactor write
    
    * refactor write
    
    * refactor batchWrite
    
    * refactor writeWithTsRecord
    
    * refactor getEncoder
    
    * refactor getEncoder
    
    * add Type.copyArrayElement
    
    * add Type.arrayCopyOf
    
    * remove Type.copyArrayElement
    
    * refactor getEncoder
    
    * add Type.setTo
    
    * add      REGULAR_ENCODER_SERVICE
    
    * add GORILLA_V2_ENCODER_SERVICE
    
    * add estimateArraySize
    
    * refactor addValue
    
    * add Date compatibility
    
    * add Date compatibility
    
    * refactor putValueToField
    
    * add Type.serializeValue
    
    * refactor fetchRecords
    
    * add Type.serializeValue
    
    * refactor copy
    
    * add Type.deserialize
    
    * refactor fillSingleMeasurementColumn
    
    * refactor setTo
    
    * refactor fillIdColumn
    
    * add Type.serializeArray
    
    * refactor updateWithoutTimeColumn
    
    * refactor rewrite
    
    * enhance type check
    
    * add Type.serializedSize
    
    * refactor rewrite
    
    * refactor TsBlockBuilder
    
    * refactor buildValueColumnBuilders
    
    * refactor buildValueColumnBuilders
    
    * add createStatistics
    
    * add getValueAsTsPrimitiveType
    
    * refactor getSizeByType
    
    * refactor ValueFilterApi
    
    * refactor generate
    
    * refactor TsFileSequenceRead
    
    * refactor ValueConverter
    
    * refactor ValueConverter
    
    * refactor TSEncodingBuilder
    
    * refactor StatisticsTest
    
    * refactor StatisticsTest
    
    * add write
    
    * refactor BatchDataTest
    
    * refactor BatchDataTest
    
    * refactor TsBlockFilterTest
    
    * refactor PageReaderTest
    
    * refactor TsFileLastReaderTest
    
    * refactor TableViewTest
    
    * refactor TabletTest
    
    * refactor TypeCastTest
    
    * refactor RecordUtils
    
    * refactor castFromSingleValue
    
    * refactor castFromArray
    
    * refactor getDataTypeSize
    
    * refactor isNumeric
    
    * refactor   public boolean isComparable() {
    
    * add update
    
    * fix null binary conversion
    
    * add write
    
    * return serialized size
    
    * add TsPrimitiveType.copy
    
    * add Type.deserializeArray
    
    * spotless
    
    * add Column.writeTo
    
    * add Type.write
    
    * add Type.write
    
    * add Type.write
    
    * add Type.write
    
    * add Type.write
    
    * add Type.write
    
    * add Column.convertTo
    
    * add Type.deserialize
    
    * spotless
    
    * add Type.serialize
    
    * add Type.deserialize
    
    * bump version
    
    * Fix descending batch data value list initialization
---
 cpp/pom.xml                                        |    2 +-
 java/common/pom.xml                                |    2 +-
 .../org/apache/tsfile/block/column/Column.java     |   33 +
 .../java/org/apache/tsfile/enums/TSDataType.java   |  633 +++---
 .../org/apache/tsfile/utils/TsPrimitiveType.java   |  216 +-
 .../tsfile/write/UnSupportedDataTypeException.java |   13 +
 .../org/apache/tsfile/i18n/messages.properties     |   12 +
 .../org/apache/tsfile/i18n/messages_zh.properties  |   12 +
 java/examples/pom.xml                              |    4 +-
 .../main/java/org/apache/tsfile/DataGenerator.java |   48 +-
 .../java/org/apache/tsfile/TsFileSequenceRead.java |   56 +-
 java/pom.xml                                       |    6 +-
 java/tools/pom.xml                                 |    6 +-
 .../org/apache/tsfile/tools/ValueConverter.java    |  205 +-
 java/tsfile/pom.xml                                |   10 +-
 .../apache/tsfile/common/conf/TSFileConfig.java    |   84 +-
 .../apache/tsfile/encoding/decoder/Decoder.java    |  144 +-
 .../tsfile/encoding/encoder/PlainEncoder.java      |   25 +-
 .../tsfile/encoding/encoder/TSEncodingBuilder.java |  135 +-
 .../file/metadata/statistics/Statistics.java       |   59 +-
 .../apache/tsfile/read/TsFileSequenceReader.java   |   89 +-
 .../org/apache/tsfile/read/common/BatchData.java   |  260 +--
 .../java/org/apache/tsfile/read/common/Chunk.java  |   77 +-
 .../tsfile/read/common/DescReadWriteBatchData.java |  138 +-
 .../java/org/apache/tsfile/read/common/Field.java  |  144 +-
 .../apache/tsfile/read/common/block/TsBlock.java   |   46 +-
 .../tsfile/read/common/block/TsBlockBuilder.java   |  107 +-
 .../read/common/block/column/BinaryColumn.java     |   59 +-
 .../read/common/block/column/BooleanColumn.java    |   65 +
 .../read/common/block/column/ColumnFactory.java    |   27 +-
 .../read/common/block/column/ColumnUtil.java       |    9 +
 .../read/common/block/column/DictionaryColumn.java |   36 +
 .../read/common/block/column/DoubleColumn.java     |   51 +
 .../read/common/block/column/FloatColumn.java      |   51 +
 .../block/column/Int32ArrayColumnEncoder.java      |   83 +-
 .../block/column/Int64ArrayColumnEncoder.java      |   70 +-
 .../tsfile/read/common/block/column/IntColumn.java |   60 +-
 .../read/common/block/column/LongColumn.java       |   53 +-
 .../read/common/block/column/NullColumn.java       |   52 +-
 .../block/column/RunLengthEncodedColumn.java       |   29 +
 .../read/common/block/column/TimeColumn.java       |   41 +
 .../tsfile/read/common/type/AbstractIntType.java   |  457 +++++
 .../tsfile/read/common/type/AbstractLongType.java  |  453 +++++
 .../tsfile/read/common/type/AbstractType.java      |  154 ++
 .../read/common/type/AbstractVarcharType.java      |  429 ++++
 .../apache/tsfile/read/common/type/BinaryType.java |   11 +
 .../apache/tsfile/read/common/type/BlobType.java   |  439 +++++
 .../tsfile/read/common/type/BooleanType.java       |  456 +++++
 .../apache/tsfile/read/common/type/DateType.java   |  284 +++
 .../apache/tsfile/read/common/type/DoubleType.java |  459 +++++
 .../apache/tsfile/read/common/type/FloatType.java  |  457 +++++
 .../apache/tsfile/read/common/type/IntType.java    |   10 +
 .../apache/tsfile/read/common/type/LongType.java   |   10 +
 .../apache/tsfile/read/common/type/ObjectType.java |  430 ++++
 .../apache/tsfile/read/common/type/RowType.java    |   33 +
 .../apache/tsfile/read/common/type/StringType.java |   23 +
 .../tsfile/read/common/type/TimestampType.java     |   22 +
 .../org/apache/tsfile/read/common/type/Type.java   |  456 +++++
 .../apache/tsfile/read/common/type/TypeEnum.java   |    3 +-
 .../tsfile/read/common/type/TypeFactory.java       |   89 +-
 .../tsfile/read/common/type/UnknownType.java       |   22 +
 .../apache/tsfile/read/common/type/VectorType.java |  400 ++++
 .../common/type/service/BooleanTypeService.java}   |   51 +-
 .../common/type/service/DoubleTypeService.java}    |   51 +-
 .../common/type/service/FloatTypeService.java}     |   51 +-
 .../read/common/type/service/IntTypeService.java}  |   51 +-
 .../read/common/type/service/LongTypeService.java} |   51 +-
 .../read/common/type/service/TypeService.java      |   61 +
 .../tsfile/read/filter/factory/ValueFilterApi.java |  384 +---
 .../query/dataset/DataSetWithoutTimeGenerator.java |   45 +-
 .../tsfile/read/query/dataset/TableResultSet.java  |   32 +-
 .../tsfile/read/query/dataset/TreeResultSet.java   |   32 +-
 .../tsfile/read/reader/TsFileLastReader.java       |   14 +-
 .../reader/block/SingleDeviceTsBlockReader.java    |   96 +-
 .../apache/tsfile/read/reader/page/PageReader.java |  246 +--
 .../tsfile/read/reader/page/ValuePageReader.java   |  451 +----
 .../apache/tsfile/utils/EncodingTypeServices.java  |  198 ++
 .../apache/tsfile/utils/TsFileGeneratorUtils.java  |   38 +-
 .../java/org/apache/tsfile/utils/TypeServices.java |  510 +++++
 .../tsfile/utils/ValueFilterTypeServices.java      |  398 ++++
 .../write/chunk/AlignedChunkGroupWriterImpl.java   |  110 +-
 .../tsfile/write/chunk/AlignedChunkWriterImpl.java |   76 +-
 .../chunk/NonAlignedChunkGroupWriterImpl.java      |   53 +-
 .../org/apache/tsfile/write/record/Tablet.java     |  475 +----
 .../tsfile/write/record/datapoint/DataPoint.java   |   38 +-
 .../tsfile/write/v4/TableTsBlock2TsFileWriter.java |   35 +-
 .../block/ColumnSerializeWithoutNullsTest.java     |  114 ++
 .../common/block/Int32ArrayColumnEncoderTest.java  |    7 +
 .../tsfile/common/block/NullColumnUnitTest.java    |   42 +
 .../tsfile/common/conf/TSFileDescriptorTest.java   |   56 +
 .../tsfile/encoding/decoder/DecoderTest.java       |  107 +
 .../file/metadata/statistics/StatisticsTest.java   |  252 ++-
 .../apache/tsfile/read/common/BatchDataTest.java   |  176 ++
 .../org/apache/tsfile/read/common/ColumnTest.java  |  256 +++
 .../org/apache/tsfile/read/common/FieldTest.java   |   32 +
 .../apache/tsfile/read/common/type/TypeTest.java   | 2059 ++++++++++++++++++++
 .../tsfile/read/filter/TsBlockFilterTest.java      |   34 +-
 .../apache/tsfile/read/reader/PageReaderTest.java  |   46 +-
 .../tsfile/read/reader/TsFileLastReaderTest.java   |   64 +-
 .../org/apache/tsfile/tableview/TableViewTest.java |   35 +-
 .../java/org/apache/tsfile/utils/RecordUtils.java  |   45 +-
 .../apache/tsfile/utils/TsPrimitiveTypeTest.java   |   93 +-
 .../java/org/apache/tsfile/utils/TypeCastTest.java |  298 +--
 .../org/apache/tsfile/write/record/TabletTest.java |  210 +-
 .../write/writer/AlignedChunkWriterImplTest.java   |   28 +
 pom.xml                                            |    6 +-
 python/pom.xml                                     |    2 +-
 107 files changed, 11410 insertions(+), 4448 deletions(-)

diff --git a/cpp/pom.xml b/cpp/pom.xml
index c0fbbc2c5..30c70b858 100644
--- a/cpp/pom.xml
+++ b/cpp/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-parent</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>tsfile-cpp</artifactId>
     <packaging>pom</packaging>
diff --git a/java/common/pom.xml b/java/common/pom.xml
index 53e98732c..ea093dbe2 100644
--- a/java/common/pom.xml
+++ b/java/common/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-java</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>common</artifactId>
     <name>TsFile: Java: Common</name>
diff --git a/java/common/src/main/java/org/apache/tsfile/block/column/Column.java b/java/common/src/main/java/org/apache/tsfile/block/column/Column.java
index c9e30d200..7cf721bed 100644
--- a/java/common/src/main/java/org/apache/tsfile/block/column/Column.java
+++ b/java/common/src/main/java/org/apache/tsfile/block/column/Column.java
@@ -23,6 +23,9 @@ import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.TsPrimitiveType;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.Arrays;
 
 public interface Column {
@@ -33,6 +36,9 @@ public interface Column {
   /** Get the encoding for this column. */
   ColumnEncoding getEncoding();
 
+  /** Converts this column to the specified data type. */
+  Column convertTo(TSDataType type);
+
   /** Gets a boolean at {@code position}. */
   default boolean getBoolean(int position) {
     throw new UnsupportedOperationException(getClass().getName());
@@ -108,6 +114,33 @@ public interface Column {
     throw new UnsupportedOperationException(getClass().getName());
   }
 
+  /** Serializes the value at {@code index} to {@code buffer}. */
+  default void writeTo(int index, ByteBuffer buffer) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Serializes the value at {@code index} to {@code stream}. */
+  default void writeTo(int index, DataOutputStream stream) throws IOException {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Serializes all non-null values in this column. */
+  default void serializeWithoutNulls(DataOutputStream output) throws IOException {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns whether the values at the two positions are equal. */
+  default boolean arePositionsEqual(int pos1, int pos2) {
+    return arePositionsEqual(pos1, this, pos2);
+  }
+
+  /**
+   * Returns whether this value and the value in another column are equal.
+   *
+   * <p>For non-null values, this column and {@code that} must provide compatible value accessors.
+   */
+  boolean arePositionsEqual(int thisPos, Column that, int thatPos);
+
   /**
    * Is it possible the column may have a null value? If false, the column cannot contain a null,
    * but if true, the column may or may not have a null.
diff --git a/java/common/src/main/java/org/apache/tsfile/enums/TSDataType.java b/java/common/src/main/java/org/apache/tsfile/enums/TSDataType.java
index f97291046..eaa09be73 100644
--- a/java/common/src/main/java/org/apache/tsfile/enums/TSDataType.java
+++ b/java/common/src/main/java/org/apache/tsfile/enums/TSDataType.java
@@ -39,45 +39,95 @@ import java.util.Set;
 
 public enum TSDataType {
   /** BOOLEAN. */
-  BOOLEAN((byte) 0),
+  BOOLEAN(
+      (byte) 0,
+      1,
+      false,
+      true,
+      TSDataType::castIdenticalSingleValue,
+      TSDataType::castIdenticalArray),
 
   /** INT32. */
-  INT32((byte) 1),
+  INT32(
+      (byte) 1,
+      4,
+      true,
+      true,
+      TSDataType::castIdenticalSingleValue,
+      TSDataType::castIdenticalArray),
 
   /** INT64. */
-  INT64((byte) 2),
+  INT64((byte) 2, 8, true, true, TSDataType::castToLongSingleValue, TSDataType::castToLongArray),
 
   /** FLOAT. */
-  FLOAT((byte) 3),
+  FLOAT((byte) 3, 4, true, true, TSDataType::castToFloatSingleValue, TSDataType::castToFloatArray),
 
   /** DOUBLE. */
-  DOUBLE((byte) 4),
+  DOUBLE(
+      (byte) 4, 8, true, true, TSDataType::castToDoubleSingleValue, TSDataType::castToDoubleArray),
 
   /** TEXT. */
-  TEXT((byte) 5),
+  TEXT((byte) 5, 8, false, true, TSDataType::castToTextSingleValue, TSDataType::castToTextArray),
 
   /** VECTOR. */
-  VECTOR((byte) 6),
+  VECTOR(
+      (byte) 6,
+      8,
+      false,
+      false,
+      TSDataType::unsupportedSingleValueCast,
+      TSDataType::unsupportedArrayCast),
 
   /** UNKNOWN. */
-  UNKNOWN((byte) 7),
+  UNKNOWN(
+      (byte) 7,
+      TSDataType.UNSUPPORTED_DATA_TYPE_SIZE,
+      false,
+      false,
+      TSDataType::unsupportedSingleValueCast,
+      TSDataType::unsupportedArrayCast),
 
   /** TIMESTAMP. */
-  TIMESTAMP((byte) 8),
+  TIMESTAMP(
+      (byte) 8,
+      8,
+      false,
+      true,
+      TSDataType::castToTimestampSingleValue,
+      TSDataType::castToTimestampArray),
 
   /** DATE. */
-  DATE((byte) 9),
+  DATE(
+      (byte) 9,
+      4,
+      false,
+      true,
+      TSDataType::castIdenticalSingleValue,
+      TSDataType::castIdenticalArray),
 
   /** BLOB. */
-  BLOB((byte) 10),
+  BLOB((byte) 10, 8, false, false, TSDataType::castToBlobSingleValue, TSDataType::castToBlobArray),
 
   /** STRING */
-  STRING((byte) 11),
+  STRING((byte) 11, 8, false, true, TSDataType::castToTextSingleValue, TSDataType::castToTextArray),
 
   /** OBJECT */
-  OBJECT((byte) 12);
-
+  OBJECT(
+      (byte) 12,
+      8,
+      false,
+      false,
+      TSDataType::castIdenticalSingleValue,
+      TSDataType::castIdenticalArray);
+
+  private static final int UNSUPPORTED_DATA_TYPE_SIZE = -1;
+  private static final Object UNSUPPORTED_CAST = new Object();
   private final byte type;
+  private final int dataTypeSize;
+  private final boolean numeric;
+  private final boolean comparable;
+  private final SingleValueCaster singleValueCaster;
+  private final ArrayCaster arrayCaster;
   private static final Map<TSDataType, Set<TSDataType>> compatibleTypes;
 
   static {
@@ -147,8 +197,19 @@ public enum TSDataType {
     compatibleTypes.put(OBJECT, Collections.emptySet());
   }
 
-  TSDataType(byte type) {
+  TSDataType(
+      byte type,
+      int dataTypeSize,
+      boolean numeric,
+      boolean comparable,
+      SingleValueCaster singleValueCaster,
+      ArrayCaster arrayCaster) {
     this.type = type;
+    this.dataTypeSize = dataTypeSize;
+    this.numeric = numeric;
+    this.comparable = comparable;
+    this.singleValueCaster = singleValueCaster;
+    this.arrayCaster = arrayCaster;
   }
 
   /**
@@ -211,271 +272,230 @@ public enum TSDataType {
     if (Objects.isNull(value)) {
       return null;
     }
-    switch (this) {
-      case BOOLEAN:
-        if (sourceType == TSDataType.BOOLEAN) {
-          return value;
-        } else {
-          break;
-        }
-      case INT32:
-        if (sourceType == TSDataType.INT32) {
-          return value;
-        } else {
-          break;
-        }
-      case INT64:
-        if (sourceType == TSDataType.INT64) {
-          return value;
-        } else if (sourceType == INT32) {
-          return (long) ((int) value);
-        } else if (sourceType == TIMESTAMP) {
-          return value;
-        } else {
-          break;
-        }
-      case FLOAT:
-        if (sourceType == TSDataType.FLOAT) {
-          return value;
-        } else if (sourceType == INT32) {
-          return (float) ((int) value);
-        } else {
-          break;
-        }
-      case DOUBLE:
-        if (sourceType == TSDataType.DOUBLE) {
-          return value;
-        } else if (sourceType == INT32) {
-          return (double) ((int) value);
-        } else if (sourceType == INT64) {
-          return (double) ((long) value);
-        } else if (sourceType == FLOAT) {
-          return (double) ((float) value);
-        } else if (sourceType == TIMESTAMP) {
-          return (double) ((long) value);
-        } else {
-          break;
-        }
-      case TEXT:
-        if (sourceType == TSDataType.TEXT || sourceType == TSDataType.STRING) {
-          return value;
-        } else if (sourceType == TSDataType.INT32
-            || sourceType == TSDataType.INT64
-            || sourceType == TSDataType.FLOAT
-            || sourceType == TSDataType.DOUBLE
-            || sourceType == TSDataType.BOOLEAN
-            || sourceType == TSDataType.TIMESTAMP) {
-          return new Binary(String.valueOf(value), StandardCharsets.UTF_8);
-        } else if (sourceType == TSDataType.DATE) {
-          return new Binary(getDateStringValue((int) value), StandardCharsets.UTF_8);
-        } else if (sourceType == TSDataType.BLOB) {
-          return new Binary(value.toString(), StandardCharsets.UTF_8);
-        } else {
-          break;
-        }
-      case TIMESTAMP:
-        if (sourceType == TSDataType.TIMESTAMP) {
-          return value;
-        } else if (sourceType == INT32) {
-          return (long) ((int) value);
-        } else if (sourceType == INT64) {
-          return value;
-        } else {
-          break;
-        }
-      case DATE:
-        if (sourceType == TSDataType.DATE) {
-          return value;
-        } else {
-          break;
-        }
-      case BLOB:
-        if (sourceType == TSDataType.BLOB
-            || sourceType == TSDataType.STRING
-            || sourceType == TSDataType.TEXT) {
-          return value;
-        } else {
-          break;
-        }
-      case STRING:
-        if (sourceType == TSDataType.STRING || sourceType == TSDataType.TEXT) {
-          return value;
-        } else if (sourceType == TSDataType.INT32
-            || sourceType == TSDataType.INT64
-            || sourceType == TSDataType.FLOAT
-            || sourceType == TSDataType.DOUBLE
-            || sourceType == TSDataType.BOOLEAN
-            || sourceType == TSDataType.TIMESTAMP) {
-          return new Binary(String.valueOf(value), StandardCharsets.UTF_8);
-        } else if (sourceType == TSDataType.DATE) {
-          return new Binary(getDateStringValue((int) value), StandardCharsets.UTF_8);
-        } else if (sourceType == TSDataType.BLOB) {
-          return new Binary(value.toString(), StandardCharsets.UTF_8);
-        } else {
-          break;
-        }
-      case OBJECT:
-        if (sourceType == TSDataType.OBJECT) {
-          return value;
-        } else {
-          break;
-        }
-      case VECTOR:
-      case UNKNOWN:
-      default:
-        break;
+    Object result = singleValueCaster.cast(this, sourceType, value);
+    if (result != UNSUPPORTED_CAST) {
+      return result;
     }
     throw new ClassCastException(
         Messages.format("error.common.unsupported_cast", sourceType, this));
   }
 
-  @SuppressWarnings({"java:S3012", "java:S3776", "java:S6541"})
+  private static Object castIdenticalSingleValue(
+      TSDataType targetType, TSDataType sourceType, Object value) {
+    return sourceType == targetType ? value : UNSUPPORTED_CAST;
+  }
+
+  private static Object castToLongSingleValue(
+      TSDataType targetType, TSDataType sourceType, Object value) {
+    if (sourceType == INT64 || sourceType == TIMESTAMP) {
+      return value;
+    }
+    return sourceType == INT32 ? (long) ((int) value) : UNSUPPORTED_CAST;
+  }
+
+  private static Object castToFloatSingleValue(
+      TSDataType targetType, TSDataType sourceType, Object value) {
+    if (sourceType == FLOAT) {
+      return value;
+    }
+    return sourceType == INT32 ? (float) ((int) value) : UNSUPPORTED_CAST;
+  }
+
+  private static Object castToDoubleSingleValue(
+      TSDataType targetType, TSDataType sourceType, Object value) {
+    if (sourceType == DOUBLE) {
+      return value;
+    }
+    if (sourceType == INT32) {
+      return (double) ((int) value);
+    }
+    if (sourceType == INT64 || sourceType == TIMESTAMP) {
+      return (double) ((long) value);
+    }
+    return sourceType == FLOAT ? (double) ((float) value) : UNSUPPORTED_CAST;
+  }
+
+  private static Object castToTextSingleValue(
+      TSDataType targetType, TSDataType sourceType, Object value) {
+    if (sourceType == TEXT || sourceType == STRING) {
+      return value;
+    }
+    if (sourceType == INT32
+        || sourceType == INT64
+        || sourceType == FLOAT
+        || sourceType == DOUBLE
+        || sourceType == BOOLEAN
+        || sourceType == TIMESTAMP) {
+      return new Binary(String.valueOf(value), StandardCharsets.UTF_8);
+    }
+    if (sourceType == DATE) {
+      return new Binary(getDateStringValue((int) value), StandardCharsets.UTF_8);
+    }
+    return sourceType == BLOB
+        ? new Binary(value.toString(), StandardCharsets.UTF_8)
+        : UNSUPPORTED_CAST;
+  }
+
+  private static Object castToTimestampSingleValue(
+      TSDataType targetType, TSDataType sourceType, Object value) {
+    if (sourceType == TIMESTAMP || sourceType == INT64) {
+      return value;
+    }
+    return sourceType == INT32 ? (long) ((int) value) : UNSUPPORTED_CAST;
+  }
+
+  private static Object castToBlobSingleValue(
+      TSDataType targetType, TSDataType sourceType, Object value) {
+    return sourceType == BLOB || sourceType == STRING || sourceType == TEXT
+        ? value
+        : UNSUPPORTED_CAST;
+  }
+
+  private static Object unsupportedSingleValueCast(
+      TSDataType targetType, TSDataType sourceType, Object value) {
+    return UNSUPPORTED_CAST;
+  }
+
   public Object castFromArray(TSDataType sourceType, Object array) {
-    switch (this) {
-      case BOOLEAN:
-        if (sourceType == TSDataType.BOOLEAN) {
-          return array;
-        } else {
-          break;
-        }
-      case INT32:
-        if (sourceType == TSDataType.INT32) {
-          return array;
-        } else {
-          break;
-        }
-      case INT64:
-        if (sourceType == TSDataType.INT64) {
-          return array;
-        } else if (sourceType == INT32) {
-          return Arrays.stream((int[]) array).mapToLong(Long::valueOf).toArray();
-        } else if (sourceType == TIMESTAMP) {
-          return array;
-        } else {
-          break;
-        }
-      case FLOAT:
-        if (sourceType == TSDataType.FLOAT) {
-          return array;
-        } else if (sourceType == INT32) {
-          int[] tmp = (int[]) array;
-          float[] result = new float[tmp.length];
-          for (int i = 0; i < tmp.length; i++) {
-            result[i] = tmp[i];
-          }
-          return result;
-        } else {
-          break;
-        }
-      case DOUBLE:
-        if (sourceType == TSDataType.DOUBLE) {
-          return array;
-        } else if (sourceType == INT32) {
-          return Arrays.stream((int[]) array).mapToDouble(Double::valueOf).toArray();
-        } else if (sourceType == INT64) {
-          return Arrays.stream((long[]) array).mapToDouble(Double::valueOf).toArray();
-        } else if (sourceType == FLOAT) {
-          float[] tmp = (float[]) array;
-          double[] result = new double[tmp.length];
-          for (int i = 0; i < tmp.length; i++) {
-            result[i] = tmp[i];
-          }
-          return result;
-        } else if (sourceType == TIMESTAMP) {
-          return Arrays.stream((long[]) array).mapToDouble(Double::valueOf).toArray();
-        } else {
-          break;
-        }
-      case TIMESTAMP:
-        if (sourceType == TSDataType.TIMESTAMP) {
-          return array;
-        } else if (sourceType == INT32) {
-          return Arrays.stream((int[]) array).mapToLong(Long::valueOf).toArray();
-        } else if (sourceType == INT64) {
-          return array;
-        } else {
-          break;
-        }
-      case DATE:
-        if (sourceType == TSDataType.DATE) {
-          return array;
-        } else {
-          break;
-        }
-      case BLOB:
-        if (sourceType == TSDataType.BLOB
-            || sourceType == TSDataType.STRING
-            || sourceType == TSDataType.TEXT) {
-          return array;
-        } else {
-          break;
-        }
-      case TEXT:
-      case STRING:
-        if (sourceType == TSDataType.STRING
-            || sourceType == TSDataType.TEXT
-            || sourceType == TSDataType.BLOB) {
-          return array;
-        } else if (sourceType == TSDataType.INT32) {
-          int[] tmp = (int[]) array;
-          Binary[] result = new Binary[tmp.length];
-          for (int i = 0; i < tmp.length; i++) {
-            result[i] = new Binary(String.valueOf(tmp[i]), StandardCharsets.UTF_8);
-          }
-          return result;
-        } else if (sourceType == TSDataType.DATE) {
-          int[] tmp = (int[]) array;
-          Binary[] result = new Binary[tmp.length];
-          for (int i = 0; i < tmp.length; i++) {
-            result[i] = new Binary(TSDataType.getDateStringValue(tmp[i]), StandardCharsets.UTF_8);
-          }
-          return result;
-        } else if (sourceType == TSDataType.INT64 || sourceType == TSDataType.TIMESTAMP) {
-          long[] tmp = (long[]) array;
-          Binary[] result = new Binary[tmp.length];
-          for (int i = 0; i < tmp.length; i++) {
-            result[i] = new Binary(String.valueOf(tmp[i]), StandardCharsets.UTF_8);
-          }
-          return result;
-        } else if (sourceType == TSDataType.FLOAT) {
-          float[] tmp = (float[]) array;
-          Binary[] result = new Binary[tmp.length];
-          for (int i = 0; i < tmp.length; i++) {
-            result[i] = new Binary(String.valueOf(tmp[i]), StandardCharsets.UTF_8);
-          }
-          return result;
-        } else if (sourceType == TSDataType.DOUBLE) {
-          double[] tmp = (double[]) array;
-          Binary[] result = new Binary[tmp.length];
-          for (int i = 0; i < tmp.length; i++) {
-            result[i] = new Binary(String.valueOf(tmp[i]), StandardCharsets.UTF_8);
-          }
-          return result;
-        } else if (sourceType == TSDataType.BOOLEAN) {
-          boolean[] tmp = (boolean[]) array;
-          Binary[] result = new Binary[tmp.length];
-          for (int i = 0; i < tmp.length; i++) {
-            result[i] = new Binary(String.valueOf(tmp[i]), StandardCharsets.UTF_8);
-          }
-          return result;
-        } else {
-          break;
-        }
-      case OBJECT:
-        if (sourceType == TSDataType.OBJECT) {
-          return array;
-        } else {
-          break;
-        }
-      case VECTOR:
-      case UNKNOWN:
-      default:
-        break;
+    Object result = arrayCaster.cast(this, sourceType, array);
+    if (result != UNSUPPORTED_CAST) {
+      return result;
     }
     throw new ClassCastException(
         Messages.format("error.common.unsupported_cast", sourceType, this));
   }
 
+  private static Object castIdenticalArray(
+      TSDataType targetType, TSDataType sourceType, Object array) {
+    return sourceType == targetType ? array : UNSUPPORTED_CAST;
+  }
+
+  private static Object castToLongArray(
+      TSDataType targetType, TSDataType sourceType, Object array) {
+    if (sourceType == INT64 || sourceType == TIMESTAMP) {
+      return array;
+    }
+    return sourceType == INT32
+        ? Arrays.stream((int[]) array).mapToLong(Long::valueOf).toArray()
+        : UNSUPPORTED_CAST;
+  }
+
+  private static Object castToFloatArray(
+      TSDataType targetType, TSDataType sourceType, Object array) {
+    if (sourceType == FLOAT) {
+      return array;
+    }
+    if (sourceType != INT32) {
+      return UNSUPPORTED_CAST;
+    }
+    int[] values = (int[]) array;
+    float[] result = new float[values.length];
+    for (int i = 0; i < values.length; i++) {
+      result[i] = values[i];
+    }
+    return result;
+  }
+
+  private static Object castToDoubleArray(
+      TSDataType targetType, TSDataType sourceType, Object array) {
+    if (sourceType == DOUBLE) {
+      return array;
+    }
+    if (sourceType == INT32) {
+      return Arrays.stream((int[]) array).mapToDouble(Double::valueOf).toArray();
+    }
+    if (sourceType == INT64 || sourceType == TIMESTAMP) {
+      return Arrays.stream((long[]) array).mapToDouble(Double::valueOf).toArray();
+    }
+    if (sourceType != FLOAT) {
+      return UNSUPPORTED_CAST;
+    }
+    float[] values = (float[]) array;
+    double[] result = new double[values.length];
+    for (int i = 0; i < values.length; i++) {
+      result[i] = values[i];
+    }
+    return result;
+  }
+
+  private static Object castToTimestampArray(
+      TSDataType targetType, TSDataType sourceType, Object array) {
+    if (sourceType == TIMESTAMP || sourceType == INT64) {
+      return array;
+    }
+    return sourceType == INT32
+        ? Arrays.stream((int[]) array).mapToLong(Long::valueOf).toArray()
+        : UNSUPPORTED_CAST;
+  }
+
+  private static Object castToBlobArray(
+      TSDataType targetType, TSDataType sourceType, Object array) {
+    return sourceType == BLOB || sourceType == STRING || sourceType == TEXT
+        ? array
+        : UNSUPPORTED_CAST;
+  }
+
+  private static Object castToTextArray(
+      TSDataType targetType, TSDataType sourceType, Object array) {
+    if (sourceType == STRING || sourceType == TEXT || sourceType == BLOB) {
+      return array;
+    }
+    if (sourceType == INT32) {
+      int[] values = (int[]) array;
+      Binary[] result = new Binary[values.length];
+      for (int i = 0; i < values.length; i++) {
+        result[i] = new Binary(String.valueOf(values[i]), StandardCharsets.UTF_8);
+      }
+      return result;
+    }
+    if (sourceType == DATE) {
+      int[] values = (int[]) array;
+      Binary[] result = new Binary[values.length];
+      for (int i = 0; i < values.length; i++) {
+        result[i] = new Binary(getDateStringValue(values[i]), StandardCharsets.UTF_8);
+      }
+      return result;
+    }
+    if (sourceType == INT64 || sourceType == TIMESTAMP) {
+      long[] values = (long[]) array;
+      Binary[] result = new Binary[values.length];
+      for (int i = 0; i < values.length; i++) {
+        result[i] = new Binary(String.valueOf(values[i]), StandardCharsets.UTF_8);
+      }
+      return result;
+    }
+    if (sourceType == FLOAT) {
+      float[] values = (float[]) array;
+      Binary[] result = new Binary[values.length];
+      for (int i = 0; i < values.length; i++) {
+        result[i] = new Binary(String.valueOf(values[i]), StandardCharsets.UTF_8);
+      }
+      return result;
+    }
+    if (sourceType == DOUBLE) {
+      double[] values = (double[]) array;
+      Binary[] result = new Binary[values.length];
+      for (int i = 0; i < values.length; i++) {
+        result[i] = new Binary(String.valueOf(values[i]), StandardCharsets.UTF_8);
+      }
+      return result;
+    }
+    if (sourceType == BOOLEAN) {
+      boolean[] values = (boolean[]) array;
+      Binary[] result = new Binary[values.length];
+      for (int i = 0; i < values.length; i++) {
+        result[i] = new Binary(String.valueOf(values[i]), StandardCharsets.UTF_8);
+      }
+      return result;
+    }
+    return UNSUPPORTED_CAST;
+  }
+
+  private static Object unsupportedArrayCast(
+      TSDataType targetType, TSDataType sourceType, Object array) {
+    return UNSUPPORTED_CAST;
+  }
+
   public static TSDataType deserializeFrom(ByteBuffer buffer) {
     return deserialize(buffer.get());
   }
@@ -501,26 +521,10 @@ public enum TSDataType {
   }
 
   public int getDataTypeSize() {
-    switch (this) {
-      case BOOLEAN:
-        return 1;
-      case INT32:
-      case FLOAT:
-      case DATE:
-        return 4;
-      // For text: return the size of reference here
-      case TEXT:
-      case INT64:
-      case DOUBLE:
-      case VECTOR:
-      case BLOB:
-      case OBJECT:
-      case STRING:
-      case TIMESTAMP:
-        return 8;
-      default:
-        throw new UnSupportedDataTypeException(this.toString());
+    if (dataTypeSize == UNSUPPORTED_DATA_TYPE_SIZE) {
+      throw new UnSupportedDataTypeException(this.toString());
     }
+    return dataTypeSize;
   }
 
   /**
@@ -539,25 +543,10 @@ public enum TSDataType {
    * @throws UnSupportedDataTypeException when meets unSupported DataType
    */
   public boolean isNumeric() {
-    switch (this) {
-      case INT32:
-      case INT64:
-      case FLOAT:
-      case DOUBLE:
-        return true;
-      // For text: return the size of reference here
-      case BLOB:
-      case TIMESTAMP:
-      case DATE:
-      case STRING:
-      case BOOLEAN:
-      case TEXT:
-      case VECTOR:
-      case OBJECT:
-        return false;
-      default:
-        throw new UnSupportedDataTypeException(this.toString());
+    if (this == UNKNOWN) {
+      throw new UnSupportedDataTypeException(this.toString());
     }
+    return numeric;
   }
 
   /**
@@ -567,24 +556,10 @@ public enum TSDataType {
    * @throws UnSupportedDataTypeException when meets unSupported DataType
    */
   public boolean isComparable() {
-    switch (this) {
-      case INT32:
-      case INT64:
-      case FLOAT:
-      case DOUBLE:
-      case TEXT:
-      case BOOLEAN:
-      case TIMESTAMP:
-      case DATE:
-      case STRING:
-        return true;
-      case VECTOR:
-      case BLOB:
-      case OBJECT:
-        return false;
-      default:
-        throw new UnSupportedDataTypeException(this.toString());
+    if (this == UNKNOWN) {
+      throw new UnSupportedDataTypeException(this.toString());
     }
+    return comparable;
   }
 
   public boolean isBinary() {
@@ -603,4 +578,16 @@ public enum TSDataType {
   public static String getDateStringValue(int value) {
     return String.format("%04d-%02d-%02d", value / 10000, (value % 10000) / 100, value % 100);
   }
+
+  @FunctionalInterface
+  private interface SingleValueCaster {
+
+    Object cast(TSDataType targetType, TSDataType sourceType, Object value);
+  }
+
+  @FunctionalInterface
+  private interface ArrayCaster {
+
+    Object cast(TSDataType targetType, TSDataType sourceType, Object array);
+  }
 }
diff --git a/java/common/src/main/java/org/apache/tsfile/utils/TsPrimitiveType.java b/java/common/src/main/java/org/apache/tsfile/utils/TsPrimitiveType.java
index fa88e68c6..4b20ffbab 100644
--- a/java/common/src/main/java/org/apache/tsfile/utils/TsPrimitiveType.java
+++ b/java/common/src/main/java/org/apache/tsfile/utils/TsPrimitiveType.java
@@ -28,73 +28,6 @@ import java.util.Arrays;
 
 public abstract class TsPrimitiveType implements Serializable {
 
-  /**
-   * get tsPrimitiveType by resultDataType.
-   *
-   * @param dataType given TsDataType
-   */
-  public static TsPrimitiveType getByType(TSDataType dataType) {
-    switch (dataType) {
-      case BOOLEAN:
-        return new TsPrimitiveType.TsBoolean();
-      case INT32:
-        return new TsPrimitiveType.TsInt();
-      case DATE:
-        return new TsPrimitiveType.TsInt(TSDataType.DATE);
-      case INT64:
-      case TIMESTAMP:
-        return new TsPrimitiveType.TsLong();
-      case FLOAT:
-        return new TsPrimitiveType.TsFloat();
-      case DOUBLE:
-        return new TsPrimitiveType.TsDouble();
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        return new TsPrimitiveType.TsBinary();
-      case VECTOR:
-        return new TsPrimitiveType.TsVector();
-      default:
-        throw new UnSupportedDataTypeException(
-            Messages.format("error.common.unsupported_data_type", dataType));
-    }
-  }
-
-  /**
-   * get tsPrimitiveType by resultDataType and initial value.
-   *
-   * @param dataType given TsDataType
-   * @param v initial value
-   */
-  public static TsPrimitiveType getByType(TSDataType dataType, Object v) {
-    switch (dataType) {
-      case BOOLEAN:
-        return new TsPrimitiveType.TsBoolean((boolean) v);
-      case INT32:
-        return new TsPrimitiveType.TsInt((int) v);
-      case DATE:
-        return new TsPrimitiveType.TsInt((int) v, TSDataType.DATE);
-      case INT64:
-      case TIMESTAMP:
-        return new TsPrimitiveType.TsLong((long) v);
-      case FLOAT:
-        return new TsPrimitiveType.TsFloat((float) v);
-      case DOUBLE:
-        return new TsPrimitiveType.TsDouble((double) v);
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        return new TsPrimitiveType.TsBinary((Binary) v);
-      case VECTOR:
-        return new TsPrimitiveType.TsVector((TsPrimitiveType[]) v);
-      default:
-        throw new UnSupportedDataTypeException(
-            Messages.format("error.common.unsupported_data_type", dataType));
-    }
-  }
-
   public boolean getBoolean() {
     throw new UnsupportedOperationException(
         Messages.format("error.common.subclass_op_not_supported", "getBoolean()"));
@@ -182,6 +115,36 @@ public abstract class TsPrimitiveType implements Serializable {
 
   public abstract TSDataType getDataType();
 
+  public abstract void copy(TsPrimitiveType value);
+
+  private static TsPrimitiveType copyValue(TsPrimitiveType value) {
+    if (value == null) {
+      return null;
+    }
+    if (value instanceof TsBoolean) {
+      return new TsBoolean((TsBoolean) value);
+    }
+    if (value instanceof TsInt) {
+      return new TsInt((TsInt) value);
+    }
+    if (value instanceof TsLong) {
+      return new TsLong((TsLong) value);
+    }
+    if (value instanceof TsFloat) {
+      return new TsFloat((TsFloat) value);
+    }
+    if (value instanceof TsDouble) {
+      return new TsDouble((TsDouble) value);
+    }
+    if (value instanceof TsBinary) {
+      return new TsBinary((TsBinary) value);
+    }
+    if (value instanceof TsVector) {
+      return new TsVector((TsVector) value);
+    }
+    throw new UnSupportedDataTypeException(String.valueOf(value.getDataType()));
+  }
+
   @Override
   public String toString() {
     return getStringValue();
@@ -208,6 +171,10 @@ public abstract class TsPrimitiveType implements Serializable {
       this.value = value;
     }
 
+    public TsBoolean(TsBoolean other) {
+      this.value = other.value;
+    }
+
     @Override
     public boolean getBoolean() {
       return value;
@@ -233,6 +200,15 @@ public abstract class TsPrimitiveType implements Serializable {
           Messages.format("error.common.tsprimitive_wrong_value_type", "TsBoolean", "Boolean"));
     }
 
+    @Override
+    public void copy(TsPrimitiveType value) {
+      if (value == null) {
+        reset();
+        return;
+      }
+      setBoolean(value.getBoolean());
+    }
+
     @Override
     public void reset() {
       value = false;
@@ -297,6 +273,11 @@ public abstract class TsPrimitiveType implements Serializable {
       this.dataType = dataType;
     }
 
+    public TsInt(TsInt other) {
+      this.value = other.value;
+      this.dataType = other.dataType;
+    }
+
     @Override
     public int getInt() {
       return value;
@@ -304,12 +285,12 @@ public abstract class TsPrimitiveType implements Serializable {
 
     @Override
     public double getDouble() {
-      return (double) value;
+      return value;
     }
 
     @Override
     public long getLong() {
-      return (long) value;
+      return value;
     }
 
     @Override
@@ -319,6 +300,9 @@ public abstract class TsPrimitiveType implements Serializable {
 
     @Override
     public Binary getBinary() {
+      if (dataType == TSDataType.DATE) {
+        return new Binary(TSDataType.getDateStringValue(value), StandardCharsets.UTF_8);
+      }
       return new Binary(String.valueOf(this.value), StandardCharsets.UTF_8);
     }
 
@@ -337,6 +321,16 @@ public abstract class TsPrimitiveType implements Serializable {
           Messages.format("error.common.tsprimitive_wrong_value_type", "TsInt", "Integer"));
     }
 
+    @Override
+    public void copy(TsPrimitiveType value) {
+      if (value == null) {
+        reset();
+        return;
+      }
+      setInt(value.getInt());
+      dataType = value.getDataType();
+    }
+
     @Override
     public void reset() {
       value = 0;
@@ -390,6 +384,10 @@ public abstract class TsPrimitiveType implements Serializable {
       this.value = value;
     }
 
+    public TsLong(TsLong other) {
+      this.value = other.value;
+    }
+
     @Override
     public long getLong() {
       return value;
@@ -420,6 +418,15 @@ public abstract class TsPrimitiveType implements Serializable {
           Messages.format("error.common.tsprimitive_wrong_value_type", "TsLong", "Long"));
     }
 
+    @Override
+    public void copy(TsPrimitiveType value) {
+      if (value == null) {
+        reset();
+        return;
+      }
+      setLong(value.getLong());
+    }
+
     @Override
     public void reset() {
       value = 0;
@@ -473,6 +480,10 @@ public abstract class TsPrimitiveType implements Serializable {
       this.value = value;
     }
 
+    public TsFloat(TsFloat other) {
+      this.value = other.value;
+    }
+
     @Override
     public float getFloat() {
       return value;
@@ -503,6 +514,15 @@ public abstract class TsPrimitiveType implements Serializable {
           Messages.format("error.common.tsprimitive_wrong_value_type", "TsFloat", "float"));
     }
 
+    @Override
+    public void copy(TsPrimitiveType value) {
+      if (value == null) {
+        reset();
+        return;
+      }
+      setFloat(value.getFloat());
+    }
+
     @Override
     public void reset() {
       value = 0;
@@ -556,6 +576,10 @@ public abstract class TsPrimitiveType implements Serializable {
       this.value = value;
     }
 
+    public TsDouble(TsDouble other) {
+      this.value = other.value;
+    }
+
     @Override
     public double getDouble() {
       return value;
@@ -581,6 +605,15 @@ public abstract class TsPrimitiveType implements Serializable {
           Messages.format("error.common.tsprimitive_wrong_value_type", "TsDouble", "Double"));
     }
 
+    @Override
+    public void copy(TsPrimitiveType value) {
+      if (value == null) {
+        reset();
+        return;
+      }
+      setDouble(value.getDouble());
+    }
+
     @Override
     public void reset() {
       value = 0.0;
@@ -634,6 +667,18 @@ public abstract class TsPrimitiveType implements Serializable {
       this.value = value;
     }
 
+    public TsBinary(TsBinary other) {
+      this.value = copyBinary(other.value);
+    }
+
+    private static Binary copyBinary(Binary value) {
+      if (value == null) {
+        return null;
+      }
+      byte[] bytes = value.getValues();
+      return new Binary(bytes == null ? null : Arrays.copyOf(bytes, bytes.length));
+    }
+
     @Override
     public Binary getBinary() {
       return value;
@@ -654,6 +699,15 @@ public abstract class TsPrimitiveType implements Serializable {
           Messages.format("error.common.tsprimitive_wrong_value_type", "TsBinary", "Binary"));
     }
 
+    @Override
+    public void copy(TsPrimitiveType value) {
+      if (value == null) {
+        reset();
+        return;
+      }
+      setBinary(copyBinary(value.getBinary()));
+    }
+
     @Override
     public void reset() {
       value = null;
@@ -707,6 +761,21 @@ public abstract class TsPrimitiveType implements Serializable {
       this.values = values;
     }
 
+    public TsVector(TsVector other) {
+      this.values = copyValues(other.values);
+    }
+
+    private static TsPrimitiveType[] copyValues(TsPrimitiveType[] values) {
+      if (values == null) {
+        return null;
+      }
+      TsPrimitiveType[] copiedValues = new TsPrimitiveType[values.length];
+      for (int i = 0; i < values.length; i++) {
+        copiedValues[i] = copyValue(values[i]);
+      }
+      return copiedValues;
+    }
+
     @Override
     public TsPrimitiveType[] getVector() {
       return values;
@@ -728,6 +797,15 @@ public abstract class TsPrimitiveType implements Serializable {
               "error.common.tsprimitive_wrong_value_type", "TsVector", "TsPrimitiveType[]"));
     }
 
+    @Override
+    public void copy(TsPrimitiveType value) {
+      if (value == null) {
+        reset();
+        return;
+      }
+      setVector(copyValues(value.getVector()));
+    }
+
     @Override
     public void reset() {
       values = null;
diff --git a/java/common/src/main/java/org/apache/tsfile/write/UnSupportedDataTypeException.java b/java/common/src/main/java/org/apache/tsfile/write/UnSupportedDataTypeException.java
index a7ab7dac1..2ec35339c 100644
--- a/java/common/src/main/java/org/apache/tsfile/write/UnSupportedDataTypeException.java
+++ b/java/common/src/main/java/org/apache/tsfile/write/UnSupportedDataTypeException.java
@@ -21,6 +21,10 @@ package org.apache.tsfile.write;
 
 public class UnSupportedDataTypeException extends RuntimeException {
 
+  // true if the exception is raised by a datatype that is known to be unsupported,
+  // otherwise, it is caused by an unknown/uncovered datatype
+  private boolean isChecked = false;
+
   public UnSupportedDataTypeException(String message) {
     super("Unsupported dataType: " + message);
   }
@@ -28,4 +32,13 @@ public class UnSupportedDataTypeException extends RuntimeException {
   public UnSupportedDataTypeException(String message, Throwable e) {
     super(message + e.getMessage());
   }
+
+  public UnSupportedDataTypeException setChecked(boolean checked) {
+    isChecked = checked;
+    return this;
+  }
+
+  public boolean isChecked() {
+    return isChecked;
+  }
 }
diff --git a/java/common/src/main/resources/org/apache/tsfile/i18n/messages.properties b/java/common/src/main/resources/org/apache/tsfile/i18n/messages.properties
index 036b8cb69..2836b8c1a 100644
--- a/java/common/src/main/resources/org/apache/tsfile/i18n/messages.properties
+++ b/java/common/src/main/resources/org/apache/tsfile/i18n/messages.properties
@@ -1326,6 +1326,18 @@ log.utils.bytes_int_to_bytes_error = tsfile-common BytesUtils: cannot convert an
 # BytesUtils.longToBytes — cannot convert long to byte array (3 args: srcNum, pos, width)
 log.utils.bytes_long_to_bytes_error = tsfile-common BytesUtils: cannot convert a long {} to a byte array, pos {}, width {}
 
+# RecordUtils.parseSimpleTupleRecord — invalid timestamp
+log.utils.record_timestamp_illegal = Given timestamp is illegal: {}
+
+# RecordUtils.parseSimpleTupleRecord — measurement type not found
+log.utils.record_measurement_type_not_found = Type not found for measurement ID {}; skipping
+
+# RecordUtils.parseSimpleTupleRecord — failed to parse measurement
+log.utils.record_parse_measurement_error = Failed to parse measurement; omitting it
+
+# RecordUtils.parseSimpleTupleRecord — unsupported data type
+log.utils.record_unsupported_data_type = Unsupported data type: {}
+
 # TsFileSketchTool — cannot load file (filename arg)
 error.utils.sketch_tool_cannot_load = Cannot load file %1$s because the file has crashed.
 
diff --git a/java/common/src/main/resources/org/apache/tsfile/i18n/messages_zh.properties b/java/common/src/main/resources/org/apache/tsfile/i18n/messages_zh.properties
index 5b2eb479c..502df532e 100644
--- a/java/common/src/main/resources/org/apache/tsfile/i18n/messages_zh.properties
+++ b/java/common/src/main/resources/org/apache/tsfile/i18n/messages_zh.properties
@@ -1326,6 +1326,18 @@ log.utils.bytes_int_to_bytes_error = tsfile-common BytesUtils: 无法将 integer
 # BytesUtils.longToBytes — cannot convert long to byte array (3 args: srcNum, pos, width)
 log.utils.bytes_long_to_bytes_error = tsfile-common BytesUtils: 无法将 long {} 转换为 byte 数组,pos {},width {}
 
+# RecordUtils.parseSimpleTupleRecord — 时间戳非法
+log.utils.record_timestamp_illegal = 给定的时间戳非法:{}
+
+# RecordUtils.parseSimpleTupleRecord — 未找到测点类型
+log.utils.record_measurement_type_not_found = 未找到 measurement ID {} 的类型,跳过该测点
+
+# RecordUtils.parseSimpleTupleRecord — 测点解析失败
+log.utils.record_parse_measurement_error = 解析测点时出错,已忽略
+
+# RecordUtils.parseSimpleTupleRecord — 不支持的数据类型
+log.utils.record_unsupported_data_type = 不支持的数据类型:{}
+
 # TsFileSketchTool — cannot load file (filename arg)
 error.utils.sketch_tool_cannot_load = 无法加载文件 %1$s,因为文件已损坏。
 
diff --git a/java/examples/pom.xml b/java/examples/pom.xml
index 075a70e52..a56625c3d 100644
--- a/java/examples/pom.xml
+++ b/java/examples/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-java</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>examples</artifactId>
     <name>TsFile: Java: Examples</name>
@@ -36,7 +36,7 @@
         <dependency>
             <groupId>org.apache.tsfile</groupId>
             <artifactId>tsfile</artifactId>
-            <version>2.3.2-SNAPSHOT</version>
+            <version>2.4.1-SNAPSHOT</version>
         </dependency>
     </dependencies>
     <build>
diff --git a/java/examples/src/main/java/org/apache/tsfile/DataGenerator.java b/java/examples/src/main/java/org/apache/tsfile/DataGenerator.java
index 159e2ea65..d33f822c2 100644
--- a/java/examples/src/main/java/org/apache/tsfile/DataGenerator.java
+++ b/java/examples/src/main/java/org/apache/tsfile/DataGenerator.java
@@ -21,32 +21,38 @@ package org.apache.tsfile;
 
 import org.apache.tsfile.common.conf.TSFileConfig;
 import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.read.common.type.Type;
+import org.apache.tsfile.read.common.type.service.TypeService;
 import org.apache.tsfile.utils.Binary;
 
 import java.time.LocalDate;
 
 public class DataGenerator {
+
+  private static final TypeService<ValueGenerator> GENERATE_VALUE_SERVICE =
+      type ->
+          switch (type.getTypeEnum()) {
+            case BOOLEAN -> index -> index % 2 == 0;
+            case INT32 -> index -> index;
+            case INT64, TIMESTAMP -> index -> (long) index;
+            case FLOAT -> index -> (float) index;
+            case DOUBLE -> index -> (double) index;
+            case DATE -> index -> LocalDate.of(2024, 1, index % 30 + 1);
+            case TEXT, STRING, BLOB ->
+                index -> new Binary(String.valueOf(index), TSFileConfig.STRING_CHARSET);
+            case OBJECT, ROW, UNKNOWN, VECTOR -> index -> null;
+          };
+
+  static {
+    GENERATE_VALUE_SERVICE.check();
+  }
+
   public static Object generate(TSDataType type, int index) {
-    switch (type) {
-      case INT32:
-        return index;
-      case INT64:
-      case TIMESTAMP:
-        return (long) index;
-      case FLOAT:
-        return (float) index;
-      case DOUBLE:
-        return (double) index;
-      case BOOLEAN:
-        return index % 2 == 0;
-      case DATE:
-        return LocalDate.of(2024, 1, index % 30 + 1);
-      case TEXT:
-      case STRING:
-      case BLOB:
-        return new Binary(String.valueOf(index), TSFileConfig.STRING_CHARSET);
-      default:
-        return null;
-    }
+    return GENERATE_VALUE_SERVICE.call(Type.fromTsDataType(type)).generate(index);
+  }
+
+  @FunctionalInterface
+  private interface ValueGenerator {
+    Object generate(int index);
   }
 }
diff --git a/java/examples/src/main/java/org/apache/tsfile/TsFileSequenceRead.java b/java/examples/src/main/java/org/apache/tsfile/TsFileSequenceRead.java
index ecd3fdd27..5873784e7 100644
--- a/java/examples/src/main/java/org/apache/tsfile/TsFileSequenceRead.java
+++ b/java/examples/src/main/java/org/apache/tsfile/TsFileSequenceRead.java
@@ -34,6 +34,8 @@ import org.apache.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.tsfile.fileSystem.FSFactoryProducer;
 import org.apache.tsfile.read.TsFileSequenceReader;
 import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.read.common.type.Type;
+import org.apache.tsfile.read.common.type.service.TypeService;
 import org.apache.tsfile.read.reader.page.PageReader;
 import org.apache.tsfile.utils.ReadWriteIOUtils;
 import org.apache.tsfile.write.UnSupportedDataTypeException;
@@ -51,6 +53,25 @@ public class TsFileSequenceRead {
   public static final String POINT_IN_PAGE = "\t\tpoints in the page: ";
   private static int MASK = 0x80;
 
+  private static final TypeService<PageValueReader> PAGE_VALUE_READER_SERVICE =
+      type ->
+          switch (type.getTypeEnum()) {
+            case BOOLEAN -> Decoder::readBoolean;
+            case INT32, DATE -> Decoder::readInt;
+            case INT64, TIMESTAMP -> Decoder::readLong;
+            case FLOAT -> Decoder::readFloat;
+            case DOUBLE -> Decoder::readDouble;
+            case TEXT, STRING, BLOB -> Decoder::readBinary;
+            case OBJECT, ROW, UNKNOWN, VECTOR ->
+                (decoder, buffer) -> {
+                  throw new UnSupportedDataTypeException(String.valueOf(type.getTypeEnum()));
+                };
+          };
+
+  static {
+    PAGE_VALUE_READER_SERVICE.check();
+  }
+
   @SuppressWarnings({
     "squid:S3776",
     "squid:S106"
@@ -133,6 +154,8 @@ public class TsFileSequenceRead {
                 }
               } else if ((header.getChunkType() & TsFileConstant.VALUE_COLUMN_MASK)
                   == TsFileConstant.VALUE_COLUMN_MASK) { // Value Chunk
+                PageValueReader valueReader =
+                    PAGE_VALUE_READER_SERVICE.call(Type.fromTsDataType(header.getDataType()));
                 int pointNum = 0;
                 byte[] bitmap = null;
                 if (pageData.hasRemaining()) {
@@ -149,33 +172,7 @@ public class TsFileSequenceRead {
                     }
                     continue;
                   }
-                  Object value;
-                  switch (header.getDataType()) {
-                    case BOOLEAN:
-                      value = valueDecoder.readBoolean(pageData);
-                      break;
-                    case INT32:
-                    case DATE:
-                      value = valueDecoder.readInt(pageData);
-                      break;
-                    case INT64:
-                    case TIMESTAMP:
-                      value = valueDecoder.readLong(pageData);
-                      break;
-                    case FLOAT:
-                      value = valueDecoder.readFloat(pageData);
-                      break;
-                    case DOUBLE:
-                      value = valueDecoder.readDouble(pageData);
-                      break;
-                    case TEXT:
-                    case STRING:
-                    case BLOB:
-                      value = valueDecoder.readBinary(pageData);
-                      break;
-                    default:
-                      throw new UnSupportedDataTypeException(String.valueOf(header.getDataType()));
-                  }
+                  Object value = valueReader.read(valueDecoder, pageData);
                   if (printDetail) {
                     System.out.println("\t\t\tvalue: " + value);
                   }
@@ -240,4 +237,9 @@ public class TsFileSequenceRead {
       }
     }
   }
+
+  @FunctionalInterface
+  private interface PageValueReader {
+    Object read(Decoder decoder, ByteBuffer buffer);
+  }
 }
diff --git a/java/pom.xml b/java/pom.xml
index 13c781bea..7768e30fe 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -24,10 +24,10 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-parent</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>tsfile-java</artifactId>
-    <version>2.3.2-SNAPSHOT</version>
+    <version>2.4.1-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>TsFile: Java</name>
     <modules>
@@ -188,7 +188,7 @@
                             <importOrder>
                                 <order>org.apache.tsfile,,javax,java,\#</order>
                             </importOrder>
-                            <removeUnusedImports />
+                            <removeUnusedImports/>
                         </java>
                         <lineEndings>UNIX</lineEndings>
                     </configuration>
diff --git a/java/tools/pom.xml b/java/tools/pom.xml
index df148f652..4d6bc9f71 100644
--- a/java/tools/pom.xml
+++ b/java/tools/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-java</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>tools</artifactId>
     <name>TsFile: Java: Tools</name>
@@ -32,7 +32,7 @@
         <dependency>
             <groupId>org.apache.tsfile</groupId>
             <artifactId>common</artifactId>
-            <version>2.3.2-SNAPSHOT</version>
+            <version>2.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>commons-cli</groupId>
@@ -41,7 +41,7 @@
         <dependency>
             <groupId>org.apache.tsfile</groupId>
             <artifactId>tsfile</artifactId>
-            <version>2.3.2-SNAPSHOT</version>
+            <version>2.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>ch.qos.logback</groupId>
diff --git a/java/tools/src/main/java/org/apache/tsfile/tools/ValueConverter.java b/java/tools/src/main/java/org/apache/tsfile/tools/ValueConverter.java
index a45de52f9..75145f5e0 100644
--- a/java/tools/src/main/java/org/apache/tsfile/tools/ValueConverter.java
+++ b/java/tools/src/main/java/org/apache/tsfile/tools/ValueConverter.java
@@ -19,6 +19,8 @@
 package org.apache.tsfile.tools;
 
 import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.read.common.type.Type;
+import org.apache.tsfile.read.common.type.service.TypeService;
 import org.apache.tsfile.utils.Binary;
 
 import java.nio.charset.StandardCharsets;
@@ -30,6 +32,102 @@ import java.time.format.DateTimeParseException;
 
 public class ValueConverter {
 
+  private static final TypeService<StringConverter> FROM_STRING_SERVICE =
+      type ->
+          switch (type.getTypeEnum()) {
+            case BOOLEAN -> (value, isMeasurement, timePrecision) -> Boolean.valueOf(value);
+            case INT32 -> (value, isMeasurement, timePrecision) -> Integer.valueOf(value);
+            case INT64 -> (value, isMeasurement, timePrecision) -> Long.valueOf(value);
+            case FLOAT -> (value, isMeasurement, timePrecision) -> Float.valueOf(value);
+            case DOUBLE -> (value, isMeasurement, timePrecision) -> Double.valueOf(value);
+            case TEXT, STRING ->
+                (value, isMeasurement, timePrecision) ->
+                    isMeasurement ? new Binary(value, StandardCharsets.UTF_8) : value;
+            case BLOB ->
+                (value, isMeasurement, timePrecision) ->
+                    new Binary(value.getBytes(StandardCharsets.UTF_8));
+            case DATE -> (value, isMeasurement, timePrecision) -> parseDate(value);
+            case TIMESTAMP ->
+                (value, isMeasurement, timePrecision) -> parseTimestamp(value, timePrecision);
+            case OBJECT, ROW, UNKNOWN, VECTOR -> (value, isMeasurement, timePrecision) -> value;
+          };
+
+  private static final TypeService<ObjectConverter> FROM_OBJECT_SERVICE =
+      type ->
+          switch (type.getTypeEnum()) {
+            case BOOLEAN ->
+                (value, isMeasurement, timePrecision) ->
+                    value instanceof Boolean ? value : Boolean.valueOf(value.toString());
+            case INT32 ->
+                (value, isMeasurement, timePrecision) -> {
+                  if (value instanceof Integer) {
+                    return value;
+                  }
+                  if (value instanceof Number) {
+                    return ((Number) value).intValue();
+                  }
+                  return Integer.valueOf(value.toString());
+                };
+            case INT64 ->
+                (value, isMeasurement, timePrecision) -> {
+                  if (value instanceof Long) {
+                    return value;
+                  }
+                  if (value instanceof Number) {
+                    return ((Number) value).longValue();
+                  }
+                  return Long.valueOf(value.toString());
+                };
+            case FLOAT ->
+                (value, isMeasurement, timePrecision) -> {
+                  if (value instanceof Float) {
+                    return value;
+                  }
+                  if (value instanceof Number) {
+                    return ((Number) value).floatValue();
+                  }
+                  return Float.valueOf(value.toString());
+                };
+            case DOUBLE ->
+                (value, isMeasurement, timePrecision) -> {
+                  if (value instanceof Double) {
+                    return value;
+                  }
+                  if (value instanceof Number) {
+                    return ((Number) value).doubleValue();
+                  }
+                  return Double.valueOf(value.toString());
+                };
+            case TEXT, STRING ->
+                (value, isMeasurement, timePrecision) -> {
+                  if (isMeasurement) {
+                    return value instanceof Binary
+                        ? value
+                        : new Binary(value.toString(), StandardCharsets.UTF_8);
+                  }
+                  return value instanceof String ? value : value.toString();
+                };
+            case BLOB ->
+                (value, isMeasurement, timePrecision) -> {
+                  if (value instanceof Binary) {
+                    return value;
+                  }
+                  if (value instanceof byte[]) {
+                    return new Binary((byte[]) value);
+                  }
+                  return new Binary(value.toString().getBytes(StandardCharsets.UTF_8));
+                };
+            case DATE -> (value, isMeasurement, timePrecision) -> toLocalDate(value);
+            case TIMESTAMP ->
+                (value, isMeasurement, timePrecision) -> toEpochLong(value, timePrecision);
+            case OBJECT, ROW, UNKNOWN, VECTOR -> (value, isMeasurement, timePrecision) -> value;
+          };
+
+  static {
+    FROM_STRING_SERVICE.check();
+    FROM_OBJECT_SERVICE.check();
+  }
+
   public static Object convert(Object value, TSDataType targetType, boolean isMeasurement) {
     return convert(value, targetType, isMeasurement, "ms");
   }
@@ -47,101 +145,16 @@ public class ValueConverter {
 
   private static Object fromString(
       String value, TSDataType targetType, boolean isMeasurement, String timePrecision) {
-    switch (targetType) {
-      case BOOLEAN:
-        return Boolean.valueOf(value);
-      case INT32:
-        return Integer.valueOf(value);
-      case INT64:
-        return Long.valueOf(value);
-      case FLOAT:
-        return Float.valueOf(value);
-      case DOUBLE:
-        return Double.valueOf(value);
-      case TEXT:
-      case STRING:
-        if (isMeasurement) {
-          return new Binary(value, StandardCharsets.UTF_8);
-        }
-        return value;
-      case BLOB:
-        return new Binary(value.getBytes(StandardCharsets.UTF_8));
-      case DATE:
-        return parseDate(value);
-      case TIMESTAMP:
-        return parseTimestamp(value, timePrecision);
-      default:
-        return value;
-    }
+    return FROM_STRING_SERVICE
+        .call(Type.fromTsDataType(targetType))
+        .convert(value, isMeasurement, timePrecision);
   }
 
   private static Object fromObject(
       Object value, TSDataType targetType, boolean isMeasurement, String timePrecision) {
-    switch (targetType) {
-      case BOOLEAN:
-        if (value instanceof Boolean) {
-          return value;
-        }
-        return Boolean.valueOf(value.toString());
-      case INT32:
-        if (value instanceof Integer) {
-          return value;
-        }
-        if (value instanceof Number) {
-          return ((Number) value).intValue();
-        }
-        return Integer.valueOf(value.toString());
-      case INT64:
-        if (value instanceof Long) {
-          return value;
-        }
-        if (value instanceof Number) {
-          return ((Number) value).longValue();
-        }
-        return Long.valueOf(value.toString());
-      case FLOAT:
-        if (value instanceof Float) {
-          return value;
-        }
-        if (value instanceof Number) {
-          return ((Number) value).floatValue();
-        }
-        return Float.valueOf(value.toString());
-      case DOUBLE:
-        if (value instanceof Double) {
-          return value;
-        }
-        if (value instanceof Number) {
-          return ((Number) value).doubleValue();
-        }
-        return Double.valueOf(value.toString());
-      case TEXT:
-      case STRING:
-        if (isMeasurement) {
-          if (value instanceof Binary) {
-            return value;
-          }
-          return new Binary(value.toString(), StandardCharsets.UTF_8);
-        }
-        if (value instanceof String) {
-          return value;
-        }
-        return value.toString();
-      case BLOB:
-        if (value instanceof Binary) {
-          return value;
-        }
-        if (value instanceof byte[]) {
-          return new Binary((byte[]) value);
-        }
-        return new Binary(value.toString().getBytes(StandardCharsets.UTF_8));
-      case DATE:
-        return toLocalDate(value);
-      case TIMESTAMP:
-        return toEpochLong(value, timePrecision);
-      default:
-        return value;
-    }
+    return FROM_OBJECT_SERVICE
+        .call(Type.fromTsDataType(targetType))
+        .convert(value, isMeasurement, timePrecision);
   }
 
   private static LocalDate parseDate(String value) {
@@ -220,4 +233,14 @@ public class ValueConverter {
     }
     return parseTimestamp(value.toString(), timePrecision);
   }
+
+  @FunctionalInterface
+  private interface StringConverter {
+    Object convert(String value, boolean isMeasurement, String timePrecision);
+  }
+
+  @FunctionalInterface
+  private interface ObjectConverter {
+    Object convert(Object value, boolean isMeasurement, String timePrecision);
+  }
 }
diff --git a/java/tsfile/pom.xml b/java/tsfile/pom.xml
index ec327381c..0bcca3e4f 100644
--- a/java/tsfile/pom.xml
+++ b/java/tsfile/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.tsfile</groupId>
         <artifactId>tsfile-java</artifactId>
-        <version>2.3.2-SNAPSHOT</version>
+        <version>2.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>tsfile</artifactId>
     <name>TsFile: Java: TsFile</name>
@@ -38,7 +38,7 @@
         <dependency>
             <groupId>org.apache.tsfile</groupId>
             <artifactId>common</artifactId>
-            <version>2.3.2-SNAPSHOT</version>
+            <version>2.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>com.github.luben</groupId>
@@ -145,10 +145,10 @@
                             <goal>shade</goal>
                         </goals>
                         <configuration>
-                            <relocations />
+                            <relocations/>
                             <createDependencyReducedPom>false</createDependencyReducedPom>
                             <transformers>
-                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer" />
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
                             </transformers>
                         </configuration>
                     </execution>
@@ -185,7 +185,7 @@
                         <Export-Package>org.apache.tsfile.*</Export-Package>
                         <Embed-Dependency>common;inline=true</Embed-Dependency>
                         <Embed-Transitive>false</Embed-Transitive>
-                        <Private-Package />
+                        <Private-Package/>
                         <_removeheaders>Bnd-LastModified,Built-By</_removeheaders>
                         <Bundle-SymbolicName>org.apache.tsfile</Bundle-SymbolicName>
                     </instructions>
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/common/conf/TSFileConfig.java b/java/tsfile/src/main/java/org/apache/tsfile/common/conf/TSFileConfig.java
index 764eda5bd..6c79d6567 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/common/conf/TSFileConfig.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/common/conf/TSFileConfig.java
@@ -24,6 +24,7 @@ import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.file.metadata.enums.CompressionType;
 import org.apache.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.tsfile.fileSystem.FSType;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.FSUtils;
 
 import java.io.Serializable;
@@ -370,62 +371,11 @@ public class TSFileConfig implements Serializable {
   }
 
   public TSEncoding getValueEncoder(TSDataType dataType) {
-    switch (dataType) {
-      case BOOLEAN:
-        return booleanEncoding;
-      case INT32:
-      case DATE:
-        return int32Encoding;
-      case INT64:
-      case TIMESTAMP:
-        return int64Encoding;
-      case FLOAT:
-        return floatEncoding;
-      case DOUBLE:
-        return doubleEncoding;
-      case STRING:
-      case BLOB:
-      case TEXT:
-      case OBJECT:
-      default:
-        return textEncoding;
-    }
+    return Type.fromTsDataType(dataType).getDefaultEncoding(this);
   }
 
   public CompressionType getCompressor(TSDataType dataType) {
-    CompressionType compressionType;
-    switch (dataType) {
-      case BOOLEAN:
-        compressionType = booleanCompression;
-        break;
-      case INT32:
-      case DATE:
-        compressionType = int32Compression;
-        break;
-      case INT64:
-      case TIMESTAMP:
-        compressionType = int64Compression;
-        break;
-      case FLOAT:
-        compressionType = floatCompression;
-        break;
-      case DOUBLE:
-        compressionType = doubleCompression;
-        break;
-      case STRING:
-      case BLOB:
-      case TEXT:
-      case OBJECT:
-        compressionType = textCompression;
-        break;
-      default:
-        compressionType = null;
-    }
-
-    if (compressionType == null) {
-      compressionType = compressor;
-    }
-    return compressionType;
+    return Type.fromTsDataType(dataType).getDefaultCompressor(this);
   }
 
   public void setValueEncoder(String valueEncoder) {
@@ -532,6 +482,34 @@ public class TSFileConfig implements Serializable {
     return compressor;
   }
 
+  public CompressionType getBooleanCompressor() {
+    return getCompressorOrDefault(booleanCompression);
+  }
+
+  public CompressionType getInt32Compressor() {
+    return getCompressorOrDefault(int32Compression);
+  }
+
+  public CompressionType getInt64Compressor() {
+    return getCompressorOrDefault(int64Compression);
+  }
+
+  public CompressionType getFloatCompressor() {
+    return getCompressorOrDefault(floatCompression);
+  }
+
+  public CompressionType getDoubleCompressor() {
+    return getCompressorOrDefault(doubleCompression);
+  }
+
+  public CompressionType getTextCompressor() {
+    return getCompressorOrDefault(textCompression);
+  }
+
+  private CompressionType getCompressorOrDefault(CompressionType compressionType) {
+    return compressionType == null ? compressor : compressionType;
+  }
+
   public void setCompressor(String compressor) {
     this.compressor = CompressionType.valueOf(compressor);
   }
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/encoding/decoder/Decoder.java b/java/tsfile/src/main/java/org/apache/tsfile/encoding/decoder/Decoder.java
index 340316bb1..bfa1218ab 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/encoding/decoder/Decoder.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/encoding/decoder/Decoder.java
@@ -23,6 +23,7 @@ import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.exception.encoding.TsFileDecodingException;
 import org.apache.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.Binary;
 
 import java.io.IOException;
@@ -31,8 +32,6 @@ import java.nio.ByteBuffer;
 
 public abstract class Decoder {
 
-  private static final String ERROR_MSG_KEY = "error.encoding.decoder_not_found";
-
   private TSEncoding type;
 
   public Decoder(TSEncoding type) {
@@ -48,146 +47,7 @@ public abstract class Decoder {
   }
 
   public static Decoder getDecoderByType(TSEncoding encoding, TSDataType dataType) {
-    switch (encoding) {
-      case PLAIN:
-        return new PlainDecoder();
-      case RLE:
-        switch (dataType) {
-          case BOOLEAN:
-          case INT32:
-          case DATE:
-            return new IntRleDecoder();
-          case INT64:
-          case VECTOR:
-          case TIMESTAMP:
-            return new LongRleDecoder();
-          case FLOAT:
-          case DOUBLE:
-            return new FloatDecoder(TSEncoding.valueOf(encoding.toString()), dataType);
-          default:
-            throw new TsFileDecodingException(Messages.format(ERROR_MSG_KEY, encoding, dataType));
-        }
-      case TS_2DIFF:
-        switch (dataType) {
-          case INT32:
-          case DATE:
-            return new DeltaBinaryDecoder.IntDeltaDecoder();
-          case INT64:
-          case VECTOR:
-          case TIMESTAMP:
-            return new DeltaBinaryDecoder.LongDeltaDecoder();
-          case FLOAT:
-          case DOUBLE:
-            return new FloatDecoder(TSEncoding.valueOf(encoding.toString()), dataType);
-          default:
-            throw new TsFileDecodingException(Messages.format(ERROR_MSG_KEY, encoding, dataType));
-        }
-      case GORILLA_V1:
-        switch (dataType) {
-          case FLOAT:
-            return new SinglePrecisionDecoderV1();
-          case DOUBLE:
-            return new DoublePrecisionDecoderV1();
-          default:
-            throw new TsFileDecodingException(Messages.format(ERROR_MSG_KEY, encoding, dataType));
-        }
-      case REGULAR:
-        switch (dataType) {
-          case INT32:
-          case DATE:
-            return new RegularDataDecoder.IntRegularDecoder();
-          case INT64:
-          case VECTOR:
-          case TIMESTAMP:
-            return new RegularDataDecoder.LongRegularDecoder();
-          default:
-            throw new TsFileDecodingException(Messages.format(ERROR_MSG_KEY, encoding, dataType));
-        }
-      case GORILLA:
-        switch (dataType) {
-          case FLOAT:
-            return new SinglePrecisionDecoderV2();
-          case DOUBLE:
-            return new DoublePrecisionDecoderV2();
-          case INT32:
-          case DATE:
-            return new IntGorillaDecoder();
-          case INT64:
-          case VECTOR:
-          case TIMESTAMP:
-            return new LongGorillaDecoder();
-          default:
-            throw new TsFileDecodingException(Messages.format(ERROR_MSG_KEY, encoding, dataType));
-        }
-      case DICTIONARY:
-        return new DictionaryDecoder();
-      case ZIGZAG:
-        switch (dataType) {
-          case INT32:
-          case DATE:
-            return new IntZigzagDecoder();
-          case INT64:
-          case TIMESTAMP:
-            return new LongZigzagDecoder();
-          default:
-            throw new TsFileDecodingException(Messages.format(ERROR_MSG_KEY, encoding, dataType));
-        }
-      case CHIMP:
-        switch (dataType) {
-          case FLOAT:
-            return new SinglePrecisionChimpDecoder();
-          case DOUBLE:
-            return new DoublePrecisionChimpDecoder();
-          case INT32:
-          case DATE:
-            return new IntChimpDecoder();
-          case INT64:
-          case VECTOR:
-          case TIMESTAMP:
-            return new LongChimpDecoder();
-          default:
-            throw new TsFileDecodingException(Messages.format(ERROR_MSG_KEY, encoding, dataType));
-        }
-      case SPRINTZ:
-        switch (dataType) {
-          case INT32:
-          case DATE:
-            return new IntSprintzDecoder();
-          case INT64:
-          case TIMESTAMP:
-            return new LongSprintzDecoder();
-          case FLOAT:
-            return new FloatSprintzDecoder();
-          case DOUBLE:
-            return new DoubleSprintzDecoder();
-          default:
-            throw new TsFileDecodingException(Messages.format(ERROR_MSG_KEY, encoding, dataType));
-        }
-      case RLBE:
-        switch (dataType) {
-          case INT32:
-          case DATE:
-            return new IntRLBEDecoder();
-          case INT64:
-          case TIMESTAMP:
-            return new LongRLBEDecoder();
-          case FLOAT:
-            return new FloatRLBEDecoder();
-          case DOUBLE:
-            return new DoubleRLBEDecoder();
-          default:
-            throw new TsFileDecodingException(Messages.format(ERROR_MSG_KEY, encoding, dataType));
-        }
-      case CAMEL:
-        switch (dataType) {
-          case DOUBLE:
-            return new CamelDecoder();
-          default:
-            throw new TsFileDecodingException(Messages.format(ERROR_MSG_KEY, encoding, dataType));
-        }
-      default:
-        throw new TsFileDecodingException(Messages.format(ERROR_MSG_KEY, encoding, dataType));
-    }
+    return Type.fromTsDataType(dataType).getDecoder(encoding);
   }
 
   public int readInt(ByteBuffer buffer) {
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/PlainEncoder.java b/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/PlainEncoder.java
index 0f9fd8206..f2b518c61 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/PlainEncoder.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/PlainEncoder.java
@@ -19,11 +19,11 @@
 
 package org.apache.tsfile.encoding.encoder;
 
-import org.apache.tsfile.common.conf.TSFileConfig;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.exception.encoding.TsFileEncodingException;
 import org.apache.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.ReadWriteForEncodingUtils;
 
@@ -112,28 +112,7 @@ public class PlainEncoder extends Encoder {
 
   @Override
   public int getOneItemMaxSize() {
-    switch (dataType) {
-      case BOOLEAN:
-        return 1;
-      case INT32:
-      case DATE:
-        return 4;
-      case INT64:
-      case TIMESTAMP:
-        return 8;
-      case FLOAT:
-        return 4;
-      case DOUBLE:
-        return 8;
-      case TEXT:
-      case STRING:
-      case BLOB:
-      case OBJECT:
-        // refer to encode(Binary,ByteArrayOutputStream)
-        return 4 + TSFileConfig.BYTE_SIZE_PER_CHAR * maxStringLength;
-      default:
-        throw new UnsupportedOperationException(dataType.toString());
-    }
+    return Type.fromTsDataType(dataType).getOneItemMaxSize(maxStringLength);
   }
 
   @Override
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/TSEncodingBuilder.java b/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/TSEncodingBuilder.java
index 77d6568ee..0db1cc211 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/TSEncodingBuilder.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/TSEncodingBuilder.java
@@ -25,6 +25,8 @@ import org.apache.tsfile.common.constant.JsonFormatConstant;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
+import org.apache.tsfile.utils.EncodingTypeServices;
 import org.apache.tsfile.write.UnSupportedDataTypeException;
 
 import org.slf4j.Logger;
@@ -143,21 +145,9 @@ public abstract class TSEncodingBuilder {
 
     @Override
     public Encoder getEncoder(TSDataType type) {
-      switch (type) {
-        case INT32:
-        case DATE:
-        case BOOLEAN:
-          return new IntRleEncoder();
-        case INT64:
-        case TIMESTAMP:
-          return new LongRleEncoder();
-        case FLOAT:
-        case DOUBLE:
-          return new FloatEncoder(TSEncoding.RLE, type, maxPointNumber);
-        default:
-          throw new UnSupportedDataTypeException(
-              Messages.format(ERROR_MSG_KEY, TSEncoding.RLE, type));
-      }
+      return EncodingTypeServices.RLE_ENCODER_SERVICE
+          .call(Type.fromTsDataType(type))
+          .build(maxPointNumber);
     }
 
     /**
@@ -198,20 +188,9 @@ public abstract class TSEncodingBuilder {
 
     @Override
     public Encoder getEncoder(TSDataType type) {
-      switch (type) {
-        case INT32:
-        case DATE:
-          return new DeltaBinaryEncoder.IntDeltaEncoder();
-        case INT64:
-        case TIMESTAMP:
-          return new DeltaBinaryEncoder.LongDeltaEncoder();
-        case FLOAT:
-        case DOUBLE:
-          return new FloatEncoder(TSEncoding.TS_2DIFF, type, maxPointNumber);
-        default:
-          throw new UnSupportedDataTypeException(
-              Messages.format(ERROR_MSG_KEY, TSEncoding.TS_2DIFF, type));
-      }
+      return EncodingTypeServices.TS_2DIFF_ENCODER_SERVICE
+          .call(Type.fromTsDataType(type))
+          .build(maxPointNumber);
     }
 
     /**
@@ -250,15 +229,7 @@ public abstract class TSEncodingBuilder {
 
     @Override
     public Encoder getEncoder(TSDataType type) {
-      switch (type) {
-        case FLOAT:
-          return new SinglePrecisionEncoderV1();
-        case DOUBLE:
-          return new DoublePrecisionEncoderV1();
-        default:
-          throw new UnSupportedDataTypeException(
-              Messages.format(ERROR_MSG_KEY, TSEncoding.GORILLA_V1, type));
-      }
+      return EncodingTypeServices.GORILLA_V1_ENCODER_SERVICE.call(Type.fromTsDataType(type));
     }
 
     @Override
@@ -290,17 +261,7 @@ public abstract class TSEncodingBuilder {
 
     @Override
     public Encoder getEncoder(TSDataType type) {
-      switch (type) {
-        case INT32:
-        case DATE:
-          return new RegularDataEncoder.IntRegularEncoder();
-        case INT64:
-        case TIMESTAMP:
-          return new RegularDataEncoder.LongRegularEncoder();
-        default:
-          throw new UnSupportedDataTypeException(
-              Messages.format(ERROR_MSG_KEY, TSEncoding.REGULAR, type));
-      }
+      return EncodingTypeServices.REGULAR_ENCODER_SERVICE.call(Type.fromTsDataType(type));
     }
 
     @Override
@@ -314,21 +275,7 @@ public abstract class TSEncodingBuilder {
 
     @Override
     public Encoder getEncoder(TSDataType type) {
-      switch (type) {
-        case FLOAT:
-          return new SinglePrecisionEncoderV2();
-        case DOUBLE:
-          return new DoublePrecisionEncoderV2();
-        case INT32:
-        case DATE:
-          return new IntGorillaEncoder();
-        case INT64:
-        case TIMESTAMP:
-          return new LongGorillaEncoder();
-        default:
-          throw new UnSupportedDataTypeException(
-              Messages.format(ERROR_MSG_KEY, TSEncoding.GORILLA, type));
-      }
+      return EncodingTypeServices.GORILLA_V2_ENCODER_SERVICE.call(Type.fromTsDataType(type));
     }
 
     @Override
@@ -340,21 +287,7 @@ public abstract class TSEncodingBuilder {
   public static class Sprintz extends TSEncodingBuilder {
     @Override
     public Encoder getEncoder(TSDataType type) {
-      switch (type) {
-        case INT32:
-        case DATE:
-          return new IntSprintzEncoder();
-        case INT64:
-        case TIMESTAMP:
-          return new LongSprintzEncoder();
-        case FLOAT:
-          return new FloatSprintzEncoder();
-        case DOUBLE:
-          return new DoubleSprintzEncoder();
-        default:
-          throw new UnSupportedDataTypeException(
-              Messages.format(ERROR_MSG_KEY, TSEncoding.SPRINTZ, type));
-      }
+      return EncodingTypeServices.SPRINTZ_ENCODER_SERVICE.call(Type.fromTsDataType(type));
     }
 
     @Override
@@ -367,21 +300,7 @@ public abstract class TSEncodingBuilder {
 
     @Override
     public Encoder getEncoder(TSDataType type) {
-      switch (type) {
-        case INT32:
-        case DATE:
-          return new IntRLBE();
-        case INT64:
-        case TIMESTAMP:
-          return new LongRLBE();
-        case FLOAT:
-          return new FloatRLBE();
-        case DOUBLE:
-          return new DoubleRLBE();
-        default:
-          throw new UnSupportedDataTypeException(
-              Messages.format(ERROR_MSG_KEY, TSEncoding.RLBE, type));
-      }
+      return EncodingTypeServices.RLBE_ENCODER_SERVICE.call(Type.fromTsDataType(type));
     }
 
     @Override
@@ -411,17 +330,7 @@ public abstract class TSEncodingBuilder {
 
     @Override
     public Encoder getEncoder(TSDataType type) {
-      switch (type) {
-        case INT32:
-        case DATE:
-          return new IntZigzagEncoder();
-        case INT64:
-        case TIMESTAMP:
-          return new LongZigzagEncoder();
-        default:
-          throw new UnSupportedDataTypeException(
-              Messages.format(ERROR_MSG_KEY, TSEncoding.ZIGZAG, type));
-      }
+      return EncodingTypeServices.ZIGZAG_ENCODER_SERVICE.call(Type.fromTsDataType(type));
     }
 
     @Override
@@ -435,21 +344,7 @@ public abstract class TSEncodingBuilder {
 
     @Override
     public Encoder getEncoder(TSDataType type) {
-      switch (type) {
-        case FLOAT:
-          return new SinglePrecisionChimpEncoder();
-        case DOUBLE:
-          return new DoublePrecisionChimpEncoder();
-        case INT32:
-        case DATE:
-          return new IntChimpEncoder();
-        case INT64:
-        case TIMESTAMP:
-          return new LongChimpEncoder();
-        default:
-          throw new UnSupportedDataTypeException(
-              Messages.format(ERROR_MSG_KEY, TSEncoding.CHIMP, type));
-      }
+      return EncodingTypeServices.CHIMP_ENCODER_SERVICE.call(Type.fromTsDataType(type));
     }
 
     @Override
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/statistics/Statistics.java b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/statistics/Statistics.java
index 323115aee..2b9ff6f29 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/statistics/Statistics.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/statistics/Statistics.java
@@ -23,6 +23,7 @@ import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.exception.filter.StatisticsClassException;
 import org.apache.tsfile.exception.write.UnknownColumnTypeException;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.read.filter.basic.Filter;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.Pair;
@@ -104,65 +105,11 @@ public abstract class Statistics<T extends Serializable> {
    * @throws UnknownColumnTypeException if the type is unknown
    */
   public static Statistics<? extends Serializable> getStatsByType(TSDataType type) {
-    switch (type) {
-      case INT32:
-        return new IntegerStatistics();
-      case INT64:
-        return new LongStatistics();
-      case TEXT:
-        return new BinaryStatistics();
-      case BOOLEAN:
-        return new BooleanStatistics();
-      case DOUBLE:
-        return new DoubleStatistics();
-      case FLOAT:
-        return new FloatStatistics();
-      case VECTOR:
-        return new TimeStatistics();
-      case DATE:
-        return new DateStatistics();
-      case TIMESTAMP:
-        return new TimestampStatistics();
-      case STRING:
-        return new StringStatistics();
-      case BLOB:
-        return new BlobStatistics();
-      case OBJECT:
-        return new ObjectStatistics();
-      default:
-        throw new UnknownColumnTypeException(type.toString());
-    }
+    return Type.fromTsDataType(type).createStatistics();
   }
 
   public static long getSizeByType(TSDataType type) {
-    switch (type) {
-      case INT32:
-        return IntegerStatistics.INSTANCE_SIZE;
-      case INT64:
-        return LongStatistics.INSTANCE_SIZE;
-      case TEXT:
-        return BinaryStatistics.INSTANCE_SIZE;
-      case BOOLEAN:
-        return BooleanStatistics.INSTANCE_SIZE;
-      case DOUBLE:
-        return DoubleStatistics.INSTANCE_SIZE;
-      case FLOAT:
-        return FloatStatistics.INSTANCE_SIZE;
-      case VECTOR:
-        return TimeStatistics.INSTANCE_SIZE;
-      case DATE:
-        return DateStatistics.INSTANCE_SIZE;
-      case TIMESTAMP:
-        return TimestampStatistics.INSTANCE_SIZE;
-      case STRING:
-        return StringStatistics.INSTANCE_SIZE;
-      case BLOB:
-        return BlobStatistics.INSTANCE_SIZE;
-      case OBJECT:
-        return ObjectStatistics.INSTANCE_SIZE;
-      default:
-        throw new UnknownColumnTypeException(type.toString());
-    }
+    return Type.fromTsDataType(type).getStatisticsInstanceSize();
   }
 
   public abstract TSDataType getType();
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/TsFileSequenceReader.java b/java/tsfile/src/main/java/org/apache/tsfile/read/TsFileSequenceReader.java
index 9407eda65..2eea4089f 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/TsFileSequenceReader.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/TsFileSequenceReader.java
@@ -66,6 +66,7 @@ import org.apache.tsfile.i18n.Messages;
 import org.apache.tsfile.read.common.BatchData;
 import org.apache.tsfile.read.common.Chunk;
 import org.apache.tsfile.read.common.Path;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.read.controller.CachedChunkLoaderImpl;
 import org.apache.tsfile.read.controller.MetadataQuerierByFileImpl;
 import org.apache.tsfile.read.reader.TsFileInput;
@@ -2486,6 +2487,7 @@ public class TsFileSequenceReader implements AutoCloseable {
                     chunkHeader.getCompressionType());
             measurementSchemaList.add(measurementSchema);
             dataType = chunkHeader.getDataType();
+            Type valueType = Type.fromTsDataType(dataType);
 
             Statistics<? extends Serializable> chunkStatistics =
                 Statistics.getStatsByType(dataType);
@@ -2563,34 +2565,7 @@ public class TsFileSequenceReader implements AutoCloseable {
                         continue;
                       }
                       long timeStamp = timeBatch.get(timeBatchIndex)[i];
-                      switch (dataType) {
-                        case INT32:
-                        case DATE:
-                          chunkStatistics.update(timeStamp, value.getInt());
-                          break;
-                        case INT64:
-                        case TIMESTAMP:
-                          chunkStatistics.update(timeStamp, value.getLong());
-                          break;
-                        case FLOAT:
-                          chunkStatistics.update(timeStamp, value.getFloat());
-                          break;
-                        case DOUBLE:
-                          chunkStatistics.update(timeStamp, value.getDouble());
-                          break;
-                        case BOOLEAN:
-                          chunkStatistics.update(timeStamp, value.getBoolean());
-                          break;
-                        case TEXT:
-                        case BLOB:
-                        case STRING:
-                        case OBJECT:
-                          chunkStatistics.update(timeStamp, value.getBinary());
-                          break;
-                        default:
-                          throw new IOException(
-                              Messages.format("error.read.unexpected_type", dataType));
-                      }
+                      valueType.update(chunkStatistics, timeStamp, value);
                     }
                   }
 
@@ -2604,34 +2579,7 @@ public class TsFileSequenceReader implements AutoCloseable {
                           timeDecoder);
                   BatchData batchData = reader.getAllSatisfiedPageData();
                   while (batchData.hasCurrent()) {
-                    switch (dataType) {
-                      case INT32:
-                      case DATE:
-                        chunkStatistics.update(batchData.currentTime(), batchData.getInt());
-                        break;
-                      case INT64:
-                      case TIMESTAMP:
-                        chunkStatistics.update(batchData.currentTime(), batchData.getLong());
-                        break;
-                      case FLOAT:
-                        chunkStatistics.update(batchData.currentTime(), batchData.getFloat());
-                        break;
-                      case DOUBLE:
-                        chunkStatistics.update(batchData.currentTime(), batchData.getDouble());
-                        break;
-                      case BOOLEAN:
-                        chunkStatistics.update(batchData.currentTime(), batchData.getBoolean());
-                        break;
-                      case TEXT:
-                      case BLOB:
-                      case STRING:
-                      case OBJECT:
-                        chunkStatistics.update(batchData.currentTime(), batchData.getBinary());
-                        break;
-                      default:
-                        throw new IOException(
-                            Messages.format("error.read.unexpected_type", dataType));
-                    }
+                    valueType.update(chunkStatistics, batchData);
                     batchData.next();
                   }
                 }
@@ -2810,6 +2758,7 @@ public class TsFileSequenceReader implements AutoCloseable {
     byte marker = this.readMarker();
     ChunkHeader chunkHeader = this.readChunkHeader(marker);
     TSDataType dataType = chunkHeader.getDataType();
+    Type valueType = Type.fromTsDataType(dataType);
     Statistics<? extends Serializable> chunkStatistics = Statistics.getStatsByType(dataType);
     int dataSize = chunkHeader.getDataSize();
     if (((byte) (chunkHeader.getChunkType() & 0x3F)) == MetaMarker.CHUNK_HEADER) {
@@ -2837,33 +2786,7 @@ public class TsFileSequenceReader implements AutoCloseable {
               pageHeader, pageData, chunkHeader.getDataType(), valueDecoder, timeDecoder);
       BatchData batchData = reader.getAllSatisfiedPageData();
       while (batchData.hasCurrent()) {
-        switch (dataType) {
-          case INT32:
-          case DATE:
-            chunkStatistics.update(batchData.currentTime(), batchData.getInt());
-            break;
-          case INT64:
-          case TIMESTAMP:
-            chunkStatistics.update(batchData.currentTime(), batchData.getLong());
-            break;
-          case FLOAT:
-            chunkStatistics.update(batchData.currentTime(), batchData.getFloat());
-            break;
-          case DOUBLE:
-            chunkStatistics.update(batchData.currentTime(), batchData.getDouble());
-            break;
-          case BOOLEAN:
-            chunkStatistics.update(batchData.currentTime(), batchData.getBoolean());
-            break;
-          case TEXT:
-          case BLOB:
-          case STRING:
-          case OBJECT:
-            chunkStatistics.update(batchData.currentTime(), batchData.getBinary());
-            break;
-          default:
-            throw new IOException(Messages.format("error.read.unexpected_type", dataType));
-        }
+        valueType.update(chunkStatistics, batchData);
         batchData.next();
       }
       chunkHeader.increasePageNums(1);
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/BatchData.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/BatchData.java
index 9fbda97f1..6f2bb28c0 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/BatchData.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/BatchData.java
@@ -23,17 +23,10 @@ import org.apache.tsfile.common.conf.TSFileConfig;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
 import org.apache.tsfile.read.TimeValuePair;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.read.reader.IPointReader;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.TsPrimitiveType;
-import org.apache.tsfile.utils.TsPrimitiveType.TsBinary;
-import org.apache.tsfile.utils.TsPrimitiveType.TsBoolean;
-import org.apache.tsfile.utils.TsPrimitiveType.TsDouble;
-import org.apache.tsfile.utils.TsPrimitiveType.TsFloat;
-import org.apache.tsfile.utils.TsPrimitiveType.TsInt;
-import org.apache.tsfile.utils.TsPrimitiveType.TsLong;
-import org.apache.tsfile.utils.TsPrimitiveType.TsVector;
-import org.apache.tsfile.write.UnSupportedDataTypeException;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -129,55 +122,12 @@ public class BatchData {
    * @return current value
    */
   public Object currentValue() {
-    switch (dataType) {
-      case INT32:
-      case DATE:
-        return getInt();
-      case INT64:
-      case TIMESTAMP:
-        return getLong();
-      case FLOAT:
-        return getFloat();
-      case DOUBLE:
-        return getDouble();
-      case BOOLEAN:
-        return getBoolean();
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        return getBinary();
-      case VECTOR:
-        return getVector();
-      default:
-        return null;
-    }
+    return Type.fromTsDataType(dataType).getCurrentValue(this);
   }
 
   public TsPrimitiveType currentTsPrimitiveType() {
-    switch (dataType) {
-      case INT32:
-      case DATE:
-        return new TsInt(getInt());
-      case INT64:
-      case TIMESTAMP:
-        return new TsLong(getLong());
-      case FLOAT:
-        return new TsFloat(getFloat());
-      case DOUBLE:
-        return new TsDouble(getDouble());
-      case BOOLEAN:
-        return new TsBoolean(getBoolean());
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        return new TsBinary(getBinary());
-      case VECTOR:
-        return new TsVector(getVector());
-      default:
-        return null;
-    }
+    Type type = Type.fromTsDataType(dataType);
+    return type.getTsPrimitiveType(type.getCurrentValue(this));
   }
 
   public TSDataType getDataType() {
@@ -208,43 +158,46 @@ public class BatchData {
     timeRet.add(new long[capacity]);
     count = 0;
 
-    switch (dataType) {
-      case BOOLEAN:
-        booleanRet = new ArrayList<>();
-        booleanRet.add(new boolean[capacity]);
-        break;
-      case INT32:
-      case DATE:
-        intRet = new ArrayList<>();
-        intRet.add(new int[capacity]);
-        break;
-      case INT64:
-      case TIMESTAMP:
-        longRet = new ArrayList<>();
-        longRet.add(new long[capacity]);
-        break;
-      case FLOAT:
-        floatRet = new ArrayList<>();
-        floatRet.add(new float[capacity]);
-        break;
-      case DOUBLE:
-        doubleRet = new ArrayList<>();
-        doubleRet.add(new double[capacity]);
-        break;
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        binaryRet = new ArrayList<>();
-        binaryRet.add(new Binary[capacity]);
-        break;
-      case VECTOR:
-        vectorRet = new ArrayList<>();
-        vectorRet.add(new TsPrimitiveType[capacity][]);
-        break;
-      default:
-        throw new UnSupportedDataTypeException(String.valueOf(dataType));
-    }
+    Type.fromTsDataType(dataType).init(this);
+  }
+
+  protected <T> List<T> createValueList() {
+    return new ArrayList<>();
+  }
+
+  public void initBooleanValues() {
+    booleanRet = createValueList();
+    booleanRet.add(new boolean[capacity]);
+  }
+
+  public void initIntValues() {
+    intRet = createValueList();
+    intRet.add(new int[capacity]);
+  }
+
+  public void initLongValues() {
+    longRet = createValueList();
+    longRet.add(new long[capacity]);
+  }
+
+  public void initFloatValues() {
+    floatRet = createValueList();
+    floatRet.add(new float[capacity]);
+  }
+
+  public void initDoubleValues() {
+    doubleRet = createValueList();
+    doubleRet.add(new double[capacity]);
+  }
+
+  public void initBinaryValues() {
+    binaryRet = createValueList();
+    binaryRet.add(new Binary[capacity]);
+  }
+
+  public void initVectorValues() {
+    vectorRet = createValueList();
+    vectorRet.add(new TsPrimitiveType[capacity][]);
   }
 
   /**
@@ -558,36 +511,7 @@ public class BatchData {
    * @param v object
    */
   public void putAnObject(long t, Object v) {
-    switch (dataType) {
-      case BOOLEAN:
-        putBoolean(t, (boolean) v);
-        break;
-      case INT32:
-      case DATE:
-        putInt(t, (int) v);
-        break;
-      case INT64:
-      case TIMESTAMP:
-        putLong(t, (long) v);
-        break;
-      case FLOAT:
-        putFloat(t, (float) v);
-        break;
-      case DOUBLE:
-        putDouble(t, (double) v);
-        break;
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        putBinary(t, (Binary) v);
-        break;
-      case VECTOR:
-        putVector(t, (TsPrimitiveType[]) v);
-        break;
-      default:
-        throw new UnSupportedDataTypeException(String.valueOf(dataType));
-    }
+    Type.fromTsDataType(dataType).put(this, t, v);
   }
 
   public int length() {
@@ -682,99 +606,7 @@ public class BatchData {
    * writing, otherwise after deserializing the sequence will be reversed
    */
   public void serializeData(DataOutputStream outputStream) throws IOException {
-    switch (dataType) {
-      case BOOLEAN:
-        for (int i = 0; i < length(); i++) {
-          outputStream.writeLong(getTimeByIndex(i));
-          outputStream.writeBoolean(getBooleanByIndex(i));
-        }
-        break;
-      case DOUBLE:
-        for (int i = 0; i < length(); i++) {
-          outputStream.writeLong(getTimeByIndex(i));
-          outputStream.writeDouble(getDoubleByIndex(i));
-        }
-        break;
-      case FLOAT:
-        for (int i = 0; i < length(); i++) {
-          outputStream.writeLong(getTimeByIndex(i));
-          outputStream.writeFloat(getFloatByIndex(i));
-        }
-        break;
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        for (int i = 0; i < length(); i++) {
-          outputStream.writeLong(getTimeByIndex(i));
-          Binary binary = getBinaryByIndex(i);
-          outputStream.writeInt(binary.getLength());
-          outputStream.write(binary.getValues());
-        }
-        break;
-      case INT64:
-      case TIMESTAMP:
-        for (int i = 0; i < length(); i++) {
-          outputStream.writeLong(getTimeByIndex(i));
-          outputStream.writeLong(getLongByIndex(i));
-        }
-        break;
-      case INT32:
-      case DATE:
-        for (int i = 0; i < length(); i++) {
-          outputStream.writeLong(getTimeByIndex(i));
-          outputStream.writeInt(getIntByIndex(i));
-        }
-        break;
-      case VECTOR:
-        for (int i = 0; i < length(); i++) {
-          outputStream.writeLong(getTimeByIndex(i));
-          TsPrimitiveType[] values = getVectorByIndex(i);
-          outputStream.writeInt(values.length);
-          for (TsPrimitiveType value : values) {
-            if (value == null) {
-              outputStream.write(0);
-            } else {
-              outputStream.write(1);
-              outputStream.write(value.getDataType().serialize());
-              switch (value.getDataType()) {
-                case BOOLEAN:
-                  outputStream.writeBoolean(value.getBoolean());
-                  break;
-                case DOUBLE:
-                  outputStream.writeDouble(value.getDouble());
-                  break;
-                case FLOAT:
-                  outputStream.writeFloat(value.getFloat());
-                  break;
-                case TEXT:
-                case BLOB:
-                case STRING:
-                case OBJECT:
-                  Binary binary = value.getBinary();
-                  outputStream.writeInt(binary.getLength());
-                  outputStream.write(binary.getValues());
-                  break;
-                case INT64:
-                case TIMESTAMP:
-                  outputStream.writeLong(value.getLong());
-                  break;
-                case INT32:
-                case DATE:
-                  outputStream.writeInt(value.getInt());
-                  break;
-                default:
-                  throw new IllegalArgumentException(
-                      Messages.format("error.read.batch_data_unknown_type", dataType));
-              }
-            }
-          }
-        }
-        break;
-      default:
-        throw new IllegalArgumentException(
-            Messages.format("error.read.batch_data_unknown_type", dataType));
-    }
+    Type.fromTsDataType(dataType).serialize(this, outputStream, false);
   }
 
   /**
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/Chunk.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/Chunk.java
index bf83a4539..d41ad14a3 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/Chunk.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/Chunk.java
@@ -29,11 +29,11 @@ import org.apache.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.tsfile.file.metadata.statistics.Statistics;
 import org.apache.tsfile.i18n.Messages;
 import org.apache.tsfile.read.TimeValuePair;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.read.reader.IPageReader;
 import org.apache.tsfile.read.reader.IPointReader;
 import org.apache.tsfile.read.reader.chunk.ChunkReader;
 import org.apache.tsfile.read.reader.chunk.TableChunkReader;
-import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.PublicBAOS;
 import org.apache.tsfile.utils.RamUsageEstimator;
 import org.apache.tsfile.utils.ReadWriteForEncodingUtils;
@@ -257,51 +257,8 @@ public class Chunk {
                   chunkHeader.getDataType(), point.getValue().getVector()[0].getValue());
         }
         long timestamp = point.getTimestamp();
-        switch (newType) {
-          case BOOLEAN:
-            chunkWriter.write(
-                timestamp,
-                convertedValue == null ? true : (boolean) convertedValue,
-                convertedValue == null);
-            break;
-          case DATE:
-          case INT32:
-            chunkWriter.write(
-                timestamp,
-                convertedValue == null ? Integer.MAX_VALUE : (int) convertedValue,
-                convertedValue == null);
-            break;
-          case TIMESTAMP:
-          case INT64:
-            chunkWriter.write(
-                timestamp,
-                convertedValue == null ? (long) Integer.MAX_VALUE : (long) convertedValue,
-                convertedValue == null);
-            break;
-          case FLOAT:
-            chunkWriter.write(
-                timestamp,
-                convertedValue == null ? (float) Integer.MAX_VALUE : (float) convertedValue,
-                convertedValue == null);
-            break;
-          case DOUBLE:
-            chunkWriter.write(
-                timestamp,
-                convertedValue == null ? (double) Integer.MAX_VALUE : (double) convertedValue,
-                convertedValue == null);
-            break;
-          case TEXT:
-          case STRING:
-          case BLOB:
-          case OBJECT:
-            chunkWriter.write(
-                timestamp,
-                convertedValue == null ? Binary.EMPTY_VALUE : (Binary) convertedValue,
-                convertedValue == null);
-            break;
-          default:
-            throw new IOException(Messages.format("error.read.chunk_unsupported_type", newType));
-        }
+        Type.fromTsDataType(newType)
+            .write(chunkWriter, timestamp, convertedValue, convertedValue == null);
       }
       chunkWriter.sealCurrentPage();
     }
@@ -346,33 +303,7 @@ public class Chunk {
         if (convertedValue == null) {
           throw new IOException(Messages.format("error.read.chunk_non_aligned_null", timestamp));
         }
-        switch (newType) {
-          case BOOLEAN:
-            chunkWriter.write(timestamp, (boolean) convertedValue);
-            break;
-          case DATE:
-          case INT32:
-            chunkWriter.write(timestamp, (int) convertedValue);
-            break;
-          case TIMESTAMP:
-          case INT64:
-            chunkWriter.write(timestamp, (long) convertedValue);
-            break;
-          case FLOAT:
-            chunkWriter.write(timestamp, (float) convertedValue);
-            break;
-          case DOUBLE:
-            chunkWriter.write(timestamp, (double) convertedValue);
-            break;
-          case TEXT:
-          case STRING:
-          case BLOB:
-          case OBJECT:
-            chunkWriter.write(timestamp, (Binary) convertedValue);
-            break;
-          default:
-            throw new IOException(Messages.format("error.read.chunk_unsupported_type", newType));
-        }
+        Type.fromTsDataType(newType).write(chunkWriter, timestamp, convertedValue);
       }
       chunkWriter.sealCurrentPage();
     }
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/DescReadWriteBatchData.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/DescReadWriteBatchData.java
index b667c537d..7830a1ecb 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/DescReadWriteBatchData.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/DescReadWriteBatchData.java
@@ -20,9 +20,9 @@
 package org.apache.tsfile.read.common;
 
 import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.TsPrimitiveType;
-import org.apache.tsfile.write.UnSupportedDataTypeException;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -49,43 +49,13 @@ public class DescReadWriteBatchData extends DescReadBatchData {
     timeRet.add(new long[capacity]);
     count = 0;
 
-    switch (dataType) {
-      case BOOLEAN:
-        booleanRet = new LinkedList<>();
-        booleanRet.add(new boolean[capacity]);
-        break;
-      case INT32:
-      case DATE:
-        intRet = new LinkedList<>();
-        intRet.add(new int[capacity]);
-        break;
-      case INT64:
-      case TIMESTAMP:
-        longRet = new LinkedList<>();
-        longRet.add(new long[capacity]);
-        break;
-      case FLOAT:
-        floatRet = new LinkedList<>();
-        floatRet.add(new float[capacity]);
-        break;
-      case DOUBLE:
-        doubleRet = new LinkedList<>();
-        doubleRet.add(new double[capacity]);
-        break;
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        binaryRet = new LinkedList<>();
-        binaryRet.add(new Binary[capacity]);
-        break;
-      case VECTOR:
-        vectorRet = new LinkedList<>();
-        vectorRet.add(new TsPrimitiveType[capacity][]);
-        break;
-      default:
-        throw new UnSupportedDataTypeException(String.valueOf(dataType));
-    }
+    Type.fromTsDataType(dataType).init(this);
+  }
+
+  @Override
+  protected <T> LinkedList<T> createValueList() {
+    // Reverse writes prepend value blocks when the array capacity threshold is reached.
+    return new LinkedList<>();
   }
 
   /**
@@ -419,97 +389,7 @@ public class DescReadWriteBatchData extends DescReadBatchData {
 
   @Override
   public void serializeData(DataOutputStream outputStream) throws IOException {
-    switch (dataType) {
-      case BOOLEAN:
-        for (int i = length() - 1; i >= 0; i--) {
-          outputStream.writeLong(getTimeByIndex(i));
-          outputStream.writeBoolean(getBooleanByIndex(i));
-        }
-        break;
-      case DOUBLE:
-        for (int i = length() - 1; i >= 0; i--) {
-          outputStream.writeLong(getTimeByIndex(i));
-          outputStream.writeDouble(getDoubleByIndex(i));
-        }
-        break;
-      case FLOAT:
-        for (int i = length() - 1; i >= 0; i--) {
-          outputStream.writeLong(getTimeByIndex(i));
-          outputStream.writeFloat(getFloatByIndex(i));
-        }
-        break;
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        for (int i = length() - 1; i >= 0; i--) {
-          outputStream.writeLong(getTimeByIndex(i));
-          Binary binary = getBinaryByIndex(i);
-          outputStream.writeInt(binary.getLength());
-          outputStream.write(binary.getValues());
-        }
-        break;
-      case INT64:
-      case TIMESTAMP:
-        for (int i = length() - 1; i >= 0; i--) {
-          outputStream.writeLong(getTimeByIndex(i));
-          outputStream.writeLong(getLongByIndex(i));
-        }
-        break;
-      case INT32:
-      case DATE:
-        for (int i = length() - 1; i >= 0; i--) {
-          outputStream.writeLong(getTimeByIndex(i));
-          outputStream.writeInt(getIntByIndex(i));
-        }
-        break;
-      case VECTOR:
-        for (int i = length() - 1; i >= 0; i--) {
-          outputStream.writeLong(getTimeByIndex(i));
-          TsPrimitiveType[] values = getVectorByIndex(i);
-          outputStream.writeInt(values.length);
-          for (TsPrimitiveType value : values) {
-            if (value == null) {
-              outputStream.write(0);
-            } else {
-              outputStream.write(1);
-              outputStream.write(value.getDataType().serialize());
-              switch (value.getDataType()) {
-                case BOOLEAN:
-                  outputStream.writeBoolean(value.getBoolean());
-                  break;
-                case DOUBLE:
-                  outputStream.writeDouble(value.getDouble());
-                  break;
-                case FLOAT:
-                  outputStream.writeFloat(value.getFloat());
-                  break;
-                case TEXT:
-                case BLOB:
-                case STRING:
-                case OBJECT:
-                  Binary binary = value.getBinary();
-                  outputStream.writeInt(binary.getLength());
-                  outputStream.write(binary.getValues());
-                  break;
-                case INT64:
-                case TIMESTAMP:
-                  outputStream.writeLong(value.getLong());
-                  break;
-                case INT32:
-                case DATE:
-                  outputStream.writeInt(value.getInt());
-                  break;
-                default:
-                  throw new UnSupportedDataTypeException(String.valueOf(dataType));
-              }
-            }
-          }
-        }
-        break;
-      default:
-        throw new UnSupportedDataTypeException(String.valueOf(dataType));
-    }
+    Type.fromTsDataType(dataType).serialize(this, outputStream, true);
   }
 
   /**
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/Field.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/Field.java
index 1e8a3afcc..21e192a07 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/Field.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/Field.java
@@ -21,17 +21,13 @@ package org.apache.tsfile.read.common;
 
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.exception.NullFieldException;
-import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.Binary;
-import org.apache.tsfile.utils.BytesUtils;
 import org.apache.tsfile.utils.DateUtils;
 import org.apache.tsfile.utils.TsPrimitiveType;
-import org.apache.tsfile.write.UnSupportedDataTypeException;
 
 import java.time.LocalDate;
 
-import static org.apache.tsfile.utils.BytesUtils.parseObjectByteArrayToString;
-
 /**
  * Field is component of one {@code RowRecord} which stores a value in specific data type. The value
  * type of Field is primitive(int long, float, double, binary, boolean).
@@ -53,33 +49,7 @@ public class Field {
   public static Field copy(Field field) {
     Field out = new Field(field.dataType);
     if (out.dataType != null) {
-      switch (out.dataType) {
-        case DOUBLE:
-          out.setDoubleV(field.getDoubleV());
-          break;
-        case FLOAT:
-          out.setFloatV(field.getFloatV());
-          break;
-        case INT64:
-        case TIMESTAMP:
-          out.setLongV(field.getLongV());
-          break;
-        case INT32:
-        case DATE:
-          out.setIntV(field.getIntV());
-          break;
-        case BOOLEAN:
-          out.setBoolV(field.getBoolV());
-          break;
-        case TEXT:
-        case BLOB:
-        case STRING:
-        case OBJECT:
-          out.setBinaryV(field.getBinaryV());
-          break;
-        default:
-          throw new UnSupportedDataTypeException(out.dataType.toString());
-      }
+      Type.fromTsDataType(out.dataType).setTo(field, out);
     }
 
     return out;
@@ -147,9 +117,6 @@ public class Field {
   public Binary getBinaryV() {
     if (dataType == null) {
       throw new NullFieldException();
-    } else if (dataType == TSDataType.OBJECT) {
-      throw new UnsupportedOperationException(
-          Messages.get("error.read.field_object_type_no_binary"));
     }
     return binaryV;
   }
@@ -174,29 +141,7 @@ public class Field {
     if (dataType == null) {
       return "null";
     }
-    switch (dataType) {
-      case BOOLEAN:
-        return String.valueOf(boolV);
-      case INT32:
-      case DATE:
-        return String.valueOf(intV);
-      case INT64:
-      case TIMESTAMP:
-        return String.valueOf(longV);
-      case FLOAT:
-        return String.valueOf(floatV);
-      case DOUBLE:
-        return String.valueOf(doubleV);
-      case TEXT:
-      case STRING:
-        return binaryV.toString();
-      case OBJECT:
-        return parseObjectByteArrayToString(binaryV.getValues());
-      case BLOB:
-        return BytesUtils.parseBlobByteArrayToString(binaryV.getValues());
-      default:
-        throw new UnSupportedDataTypeException(dataType.toString());
-    }
+    return Type.fromTsDataType(dataType).toString(this);
   }
 
   @Override
@@ -208,94 +153,17 @@ public class Field {
     if (this.dataType == null) {
       return null;
     }
-    switch (dataType) {
-      case DOUBLE:
-        return getDoubleV();
-      case FLOAT:
-        return getFloatV();
-      case INT64:
-      case TIMESTAMP:
-        return getLongV();
-      case INT32:
-        return getIntV();
-      case DATE:
-        return getDateV();
-      case BOOLEAN:
-        return getBoolV();
-      case TEXT:
-      case BLOB:
-      case STRING:
-        return getBinaryV();
-      case OBJECT:
-        return getStringValue();
-      default:
-        throw new UnSupportedDataTypeException(dataType.toString());
-    }
+    return Type.fromTsDataType(dataType).getValue(this);
   }
 
   public static Field getField(Object value, TSDataType dataType) {
     if (value == null) {
       return null;
     }
-    Field field = new Field(dataType);
-    switch (dataType) {
-      case INT32:
-      case DATE:
-        field.setIntV((int) value);
-        break;
-      case INT64:
-      case TIMESTAMP:
-        field.setLongV((long) value);
-        break;
-      case FLOAT:
-        field.setFloatV((float) value);
-        break;
-      case DOUBLE:
-        field.setDoubleV((double) value);
-        break;
-      case BOOLEAN:
-        field.setBoolV((boolean) value);
-        break;
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        field.setBinaryV((Binary) value);
-        break;
-      default:
-        throw new UnSupportedDataTypeException(dataType.toString());
-    }
-    return field;
+    return Type.fromTsDataType(dataType).getField(value);
   }
 
   public static void setTsPrimitiveValue(TsPrimitiveType value, Field field) {
-    switch (value.getDataType()) {
-      case BOOLEAN:
-        field.setBoolV(value.getBoolean());
-        break;
-      case INT32:
-      case DATE:
-        field.setIntV(value.getInt());
-        break;
-      case INT64:
-      case TIMESTAMP:
-        field.setLongV(value.getLong());
-        break;
-      case FLOAT:
-        field.setFloatV(value.getFloat());
-        break;
-      case DOUBLE:
-        field.setDoubleV(value.getDouble());
-        break;
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        field.setBinaryV(value.getBinary());
-        break;
-      default:
-        throw new UnSupportedDataTypeException(
-            Messages.format("error.common.unsupported_data_type", value.getDataType()));
-    }
+    Type.fromTsDataType(value.getDataType()).setTo(value, field);
   }
 }
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlock.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlock.java
index 658024c14..de6158409 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlock.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlock.java
@@ -26,10 +26,10 @@ import org.apache.tsfile.read.TimeValuePair;
 import org.apache.tsfile.read.common.IBatchDataIterator;
 import org.apache.tsfile.read.common.block.column.ColumnFactory;
 import org.apache.tsfile.read.common.block.column.TimeColumn;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.read.reader.IPointReader;
 import org.apache.tsfile.utils.RamUsageEstimator;
 import org.apache.tsfile.utils.TsPrimitiveType;
-import org.apache.tsfile.write.UnSupportedDataTypeException;
 import org.apache.tsfile.write.schema.IMeasurementSchema;
 
 import java.util.Arrays;
@@ -560,47 +560,9 @@ public class TsBlock {
         valueColumns[i].isNull()[updateIdx] = true;
         continue;
       }
-      switch (valueColumns[i].getDataType()) {
-        case BOOLEAN:
-          valueColumns[i].isNull()[updateIdx] = false;
-          valueColumns[i].getBooleans()[updateIdx] =
-              sourceTsBlock.getValueColumns()[i].getBoolean(sourceIndex);
-          break;
-        case INT32:
-        case DATE:
-          valueColumns[i].isNull()[updateIdx] = false;
-          valueColumns[i].getInts()[updateIdx] =
-              sourceTsBlock.getValueColumns()[i].getInt(sourceIndex);
-          break;
-        case INT64:
-        case TIMESTAMP:
-          valueColumns[i].isNull()[updateIdx] = false;
-          valueColumns[i].getLongs()[updateIdx] =
-              sourceTsBlock.getValueColumns()[i].getLong(sourceIndex);
-          break;
-        case FLOAT:
-          valueColumns[i].isNull()[updateIdx] = false;
-          valueColumns[i].getFloats()[updateIdx] =
-              sourceTsBlock.getValueColumns()[i].getFloat(sourceIndex);
-          break;
-        case DOUBLE:
-          valueColumns[i].isNull()[updateIdx] = false;
-          valueColumns[i].getDoubles()[updateIdx] =
-              sourceTsBlock.getValueColumns()[i].getDouble(sourceIndex);
-          break;
-        case TEXT:
-        case BLOB:
-        case STRING:
-        case OBJECT:
-          valueColumns[i].isNull()[updateIdx] = false;
-          valueColumns[i].getBinaries()[updateIdx] =
-              sourceTsBlock.getValueColumns()[i].getBinary(sourceIndex);
-          break;
-        default:
-          throw new UnSupportedDataTypeException(
-              Messages.format(
-                  "error.read.tsblock_unknown_datatype", valueColumns[i].getDataType()));
-      }
+      valueColumns[i].isNull()[updateIdx] = false;
+      Type.fromTsDataType(valueColumns[i].getDataType())
+          .setTo(sourceTsBlock.getValueColumns()[i], sourceIndex, valueColumns[i], updateIdx);
     }
   }
 
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlockBuilder.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlockBuilder.java
index 456167304..e8868d04b 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlockBuilder.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlockBuilder.java
@@ -26,14 +26,9 @@ import org.apache.tsfile.common.conf.TSFileConfig;
 import org.apache.tsfile.common.conf.TSFileDescriptor;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
-import org.apache.tsfile.read.common.block.column.BinaryColumnBuilder;
-import org.apache.tsfile.read.common.block.column.BooleanColumnBuilder;
-import org.apache.tsfile.read.common.block.column.DoubleColumnBuilder;
-import org.apache.tsfile.read.common.block.column.FloatColumnBuilder;
-import org.apache.tsfile.read.common.block.column.IntColumnBuilder;
-import org.apache.tsfile.read.common.block.column.LongColumnBuilder;
 import org.apache.tsfile.read.common.block.column.TimeColumn;
 import org.apache.tsfile.read.common.block.column.TimeColumnBuilder;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.Binary;
 
 import java.util.List;
@@ -104,54 +99,10 @@ public class TsBlockBuilder {
     valueColumnBuilders = new ColumnBuilder[types.size()];
 
     for (int i = 0; i < valueColumnBuilders.length; i++) {
-      switch (types.get(i)) {
-        case BOOLEAN:
-          valueColumnBuilders[i] =
-              new BooleanColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(), initialExpectedEntries);
-          break;
-        case INT32:
-          valueColumnBuilders[i] =
-              new IntColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(),
-                  initialExpectedEntries,
-                  TSDataType.INT32);
-          break;
-        case DATE:
-          valueColumnBuilders[i] =
-              new IntColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(),
-                  initialExpectedEntries,
-                  TSDataType.DATE);
-          break;
-        case INT64:
-        case TIMESTAMP:
-          valueColumnBuilders[i] =
-              new LongColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(), initialExpectedEntries);
-          break;
-        case FLOAT:
-          valueColumnBuilders[i] =
-              new FloatColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(), initialExpectedEntries);
-          break;
-        case DOUBLE:
-          valueColumnBuilders[i] =
-              new DoubleColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(), initialExpectedEntries);
-          break;
-        case TEXT:
-        case BLOB:
-        case STRING:
-        case OBJECT:
-          valueColumnBuilders[i] =
-              new BinaryColumnBuilder(
+      valueColumnBuilders[i] =
+          Type.fromTsDataType(types.get(i))
+              .createColumnBuilder(
                   tsBlockBuilderStatus.createColumnBuilderStatus(), initialExpectedEntries);
-          break;
-        default:
-          throw new IllegalArgumentException(
-              Messages.format("error.read.tsblock_builder_unknown_type", types.get(i)));
-      }
     }
   }
 
@@ -184,54 +135,10 @@ public class TsBlockBuilder {
     valueColumnBuilders = new ColumnBuilder[types.size()];
     int initialExpectedEntries = timeColumnBuilder.getPositionCount();
     for (int i = 0; i < valueColumnBuilders.length; i++) {
-      switch (types.get(i)) {
-        case BOOLEAN:
-          valueColumnBuilders[i] =
-              new BooleanColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(), initialExpectedEntries);
-          break;
-        case INT32:
-          valueColumnBuilders[i] =
-              new IntColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(),
-                  initialExpectedEntries,
-                  TSDataType.INT32);
-          break;
-        case DATE:
-          valueColumnBuilders[i] =
-              new IntColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(),
-                  initialExpectedEntries,
-                  TSDataType.DATE);
-          break;
-        case INT64:
-        case TIMESTAMP:
-          valueColumnBuilders[i] =
-              new LongColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(), initialExpectedEntries);
-          break;
-        case FLOAT:
-          valueColumnBuilders[i] =
-              new FloatColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(), initialExpectedEntries);
-          break;
-        case DOUBLE:
-          valueColumnBuilders[i] =
-              new DoubleColumnBuilder(
-                  tsBlockBuilderStatus.createColumnBuilderStatus(), initialExpectedEntries);
-          break;
-        case TEXT:
-        case BLOB:
-        case STRING:
-        case OBJECT:
-          valueColumnBuilders[i] =
-              new BinaryColumnBuilder(
+      valueColumnBuilders[i] =
+          Type.fromTsDataType(types.get(i))
+              .createColumnBuilder(
                   tsBlockBuilderStatus.createColumnBuilderStatus(), initialExpectedEntries);
-          break;
-        default:
-          throw new IllegalArgumentException(
-              Messages.format("error.read.tsblock_builder_unknown_type", types.get(i)));
-      }
     }
   }
 
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/BinaryColumn.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/BinaryColumn.java
index 88f010381..6b67f87fb 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/BinaryColumn.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/BinaryColumn.java
@@ -20,13 +20,18 @@
 package org.apache.tsfile.read.common.block.column;
 
 import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.block.column.ColumnBuilder;
 import org.apache.tsfile.block.column.ColumnEncoding;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.RamUsageEstimator;
 import org.apache.tsfile.utils.TsPrimitiveType;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Optional;
 
@@ -60,7 +65,7 @@ public class BinaryColumn implements Column {
     this(0, positionCount, valueIsNull.orElse(null), values);
   }
 
-  BinaryColumn(int arrayOffset, int positionCount, boolean[] valueIsNull, Binary[] values) {
+  public BinaryColumn(int arrayOffset, int positionCount, boolean[] valueIsNull, Binary[] values) {
     if (arrayOffset < 0) {
       throw new IllegalArgumentException(Messages.get("error.read.col_array_offset_negative"));
     }
@@ -123,6 +128,24 @@ public class BinaryColumn implements Column {
     return ColumnEncoding.BINARY_ARRAY;
   }
 
+  @Override
+  public Column convertTo(TSDataType type) {
+    if (type == TSDataType.TEXT) {
+      return this;
+    }
+    ColumnUtil.checkConversion(TSDataType.TEXT, type);
+
+    ColumnBuilder builder = Type.fromTsDataType(type).createColumnBuilder(positionCount);
+    for (int position = 0; position < positionCount; position++) {
+      if (isNull(position)) {
+        builder.appendNull();
+      } else {
+        builder.writeBinary(getBinary(position));
+      }
+    }
+    return builder.build();
+  }
+
   @Override
   public Binary getBinary(int position) {
     return values[position + arrayOffset];
@@ -143,6 +166,40 @@ public class BinaryColumn implements Column {
     return new TsPrimitiveType.TsBinary(getBinary(position));
   }
 
+  @Override
+  public void writeTo(int index, ByteBuffer buffer) {
+    Binary value = values[index + arrayOffset];
+    buffer.putInt(value.getLength());
+    buffer.put(value.getValues());
+  }
+
+  @Override
+  public void writeTo(int index, DataOutputStream stream) throws IOException {
+    Binary value = values[index + arrayOffset];
+    stream.writeInt(value.getLength());
+    stream.write(value.getValues());
+  }
+
+  @Override
+  public void serializeWithoutNulls(DataOutputStream output) throws IOException {
+    for (int i = 0; i < positionCount; i++) {
+      if (!isNull(i)) {
+        Binary value = values[i + arrayOffset];
+        output.writeInt(value.getLength());
+        output.write(value.getValues());
+      }
+    }
+  }
+
+  @Override
+  public boolean arePositionsEqual(int thisPos, Column that, int thatPos) {
+    boolean thisIsNull = isNull(thisPos);
+    if (thisIsNull) {
+      return that.isNull(thatPos);
+    }
+    return !that.isNull(thatPos) && getBinary(thisPos).equals(that.getBinary(thatPos));
+  }
+
   @Override
   public boolean mayHaveNull() {
     return valueIsNull != null;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/BooleanColumn.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/BooleanColumn.java
index 318c450f7..38c6a8720 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/BooleanColumn.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/BooleanColumn.java
@@ -20,13 +20,18 @@
 package org.apache.tsfile.read.common.block.column;
 
 import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.block.column.ColumnBuilder;
 import org.apache.tsfile.block.column.ColumnEncoding;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.RamUsageEstimator;
 import org.apache.tsfile.utils.TsPrimitiveType;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Optional;
@@ -91,6 +96,24 @@ public class BooleanColumn implements Column {
     return ColumnEncoding.BYTE_ARRAY;
   }
 
+  @Override
+  public Column convertTo(TSDataType type) {
+    if (type == TSDataType.BOOLEAN) {
+      return this;
+    }
+    ColumnUtil.checkConversion(TSDataType.BOOLEAN, type);
+
+    ColumnBuilder builder = Type.fromTsDataType(type).createColumnBuilder(positionCount);
+    for (int position = 0; position < positionCount; position++) {
+      if (isNull(position)) {
+        builder.appendNull();
+      } else {
+        builder.writeBoolean(getBoolean(position));
+      }
+    }
+    return builder.build();
+  }
+
   @Override
   public boolean getBoolean(int position) {
     return values[position + arrayOffset];
@@ -125,6 +148,48 @@ public class BooleanColumn implements Column {
     return new TsPrimitiveType.TsBoolean(getBoolean(position));
   }
 
+  @Override
+  public void writeTo(int index, ByteBuffer buffer) {
+    buffer.put(values[index + arrayOffset] ? (byte) 1 : (byte) 0);
+  }
+
+  @Override
+  public void writeTo(int index, DataOutputStream stream) throws IOException {
+    stream.writeBoolean(values[index + arrayOffset]);
+  }
+
+  @Override
+  public void serializeWithoutNulls(DataOutputStream output) throws IOException {
+    int nonNullCount = 0;
+    for (int i = 0; i < positionCount; i++) {
+      if (!isNull(i)) {
+        nonNullCount++;
+      }
+    }
+
+    byte[] packedValues = new byte[(nonNullCount + 7) / 8];
+    int nonNullIndex = 0;
+    for (int i = 0; i < positionCount; i++) {
+      if (isNull(i)) {
+        continue;
+      }
+      if (values[i + arrayOffset]) {
+        packedValues[nonNullIndex / 8] |= (byte) (0b1000_0000 >>> (nonNullIndex % 8));
+      }
+      nonNullIndex++;
+    }
+    output.write(packedValues);
+  }
+
+  @Override
+  public boolean arePositionsEqual(int thisPos, Column that, int thatPos) {
+    boolean thisIsNull = isNull(thisPos);
+    if (thisIsNull) {
+      return that.isNull(thatPos);
+    }
+    return !that.isNull(thatPos) && getBoolean(thisPos) == that.getBoolean(thatPos);
+  }
+
   @Override
   public boolean mayHaveNull() {
     return valueIsNull != null;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnFactory.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnFactory.java
index ed5b853ff..0f73c9b0e 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnFactory.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnFactory.java
@@ -21,32 +21,11 @@ package org.apache.tsfile.read.common.block.column;
 
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.enums.TSDataType;
-import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 
 public class ColumnFactory {
   public static Column create(TSDataType dataType, int initialCapacity) {
-    switch (dataType) {
-      case INT64:
-      case TIMESTAMP:
-        return new LongColumn(initialCapacity);
-      case DOUBLE:
-        return new DoubleColumn(initialCapacity);
-      case FLOAT:
-        return new FloatColumn(initialCapacity);
-      case TEXT:
-      case STRING:
-      case BLOB:
-      case OBJECT:
-        return new BinaryColumn(initialCapacity);
-      case INT32:
-        return new IntColumn(initialCapacity, TSDataType.INT32);
-      case DATE:
-        return new IntColumn(initialCapacity, TSDataType.DATE);
-      case BOOLEAN:
-        return new BooleanColumn(initialCapacity);
-      default:
-        throw new IllegalArgumentException(
-            Messages.format("error.read.column_factory_unsupported_type", dataType));
-    }
+    Type type = Type.fromTsDataType(dataType);
+    return type.createColumnWithZeroPosition(initialCapacity);
   }
 }
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnUtil.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnUtil.java
index 3c741db46..77b5746f6 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnUtil.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnUtil.java
@@ -20,6 +20,7 @@
 package org.apache.tsfile.read.common.block.column;
 
 import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
 
 import java.util.Arrays;
@@ -37,6 +38,14 @@ public class ColumnUtil {
 
   private ColumnUtil() {}
 
+  static void checkConversion(TSDataType sourceType, TSDataType targetType) {
+    requireNonNull(targetType, "type is null");
+    if (!targetType.isCompatible(sourceType)) {
+      throw new ClassCastException(
+          Messages.format("error.common.unsupported_cast", sourceType, targetType));
+    }
+  }
+
   static void checkArrayRange(int[] array, int offset, int length) {
     requireNonNull(array, "array is null");
     if (offset < 0 || length < 0 || offset + length > array.length) {
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/DictionaryColumn.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/DictionaryColumn.java
index af7f22bef..7ce598483 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/DictionaryColumn.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/DictionaryColumn.java
@@ -27,6 +27,9 @@ import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.RamUsageEstimator;
 import org.apache.tsfile.utils.TsPrimitiveType;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -249,6 +252,24 @@ public final class DictionaryColumn implements Column {
     return ColumnEncoding.DICTIONARY;
   }
 
+  @Override
+  public Column convertTo(TSDataType type) {
+    TSDataType sourceType = getDataType();
+    if (type == sourceType) {
+      return this;
+    }
+    ColumnUtil.checkConversion(sourceType, type);
+    // Transform dictionary values only, preserving the ids and dictionary encoding.
+    return new DictionaryColumn(
+        idsOffset,
+        positionCount,
+        dictionary.convertTo(type),
+        ids,
+        isCompact(),
+        isSequentialIds,
+        randomDictionaryId());
+  }
+
   @Override
   public boolean mayHaveNull() {
     return mayHaveNull && dictionary.mayHaveNull();
@@ -427,6 +448,21 @@ public final class DictionaryColumn implements Column {
     return dictionary.getTsPrimitiveType(position);
   }
 
+  @Override
+  public void writeTo(int index, ByteBuffer buffer) {
+    dictionary.writeTo(getId(index), buffer);
+  }
+
+  @Override
+  public void writeTo(int index, DataOutputStream stream) throws IOException {
+    dictionary.writeTo(getId(index), stream);
+  }
+
+  @Override
+  public boolean arePositionsEqual(int thisPos, Column that, int thatPos) {
+    return dictionary.arePositionsEqual(getId(thisPos), that, thatPos);
+  }
+
   @Override
   public void reset() {
     throw new UnsupportedOperationException(getClass().getSimpleName());
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/DoubleColumn.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/DoubleColumn.java
index 4ac8d08ae..953f13730 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/DoubleColumn.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/DoubleColumn.java
@@ -20,13 +20,18 @@
 package org.apache.tsfile.read.common.block.column;
 
 import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.block.column.ColumnBuilder;
 import org.apache.tsfile.block.column.ColumnEncoding;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.RamUsageEstimator;
 import org.apache.tsfile.utils.TsPrimitiveType;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Optional;
@@ -92,6 +97,24 @@ public class DoubleColumn implements Column {
     return ColumnEncoding.INT64_ARRAY;
   }
 
+  @Override
+  public Column convertTo(TSDataType type) {
+    if (type == TSDataType.DOUBLE) {
+      return this;
+    }
+    ColumnUtil.checkConversion(TSDataType.DOUBLE, type);
+
+    ColumnBuilder builder = Type.fromTsDataType(type).createColumnBuilder(positionCount);
+    for (int position = 0; position < positionCount; position++) {
+      if (isNull(position)) {
+        builder.appendNull();
+      } else {
+        builder.writeDouble(getDouble(position));
+      }
+    }
+    return builder.build();
+  }
+
   @Override
   public double getDouble(int position) {
     return values[position + arrayOffset];
@@ -126,6 +149,34 @@ public class DoubleColumn implements Column {
     return new TsPrimitiveType.TsDouble(getDouble(position));
   }
 
+  @Override
+  public void writeTo(int index, ByteBuffer buffer) {
+    buffer.putDouble(values[index + arrayOffset]);
+  }
+
+  @Override
+  public void writeTo(int index, DataOutputStream stream) throws IOException {
+    stream.writeDouble(values[index + arrayOffset]);
+  }
+
+  @Override
+  public void serializeWithoutNulls(DataOutputStream output) throws IOException {
+    for (int i = 0; i < positionCount; i++) {
+      if (!isNull(i)) {
+        output.writeLong(Double.doubleToLongBits(values[i + arrayOffset]));
+      }
+    }
+  }
+
+  @Override
+  public boolean arePositionsEqual(int thisPos, Column that, int thatPos) {
+    boolean thisIsNull = isNull(thisPos);
+    if (thisIsNull) {
+      return that.isNull(thatPos);
+    }
+    return !that.isNull(thatPos) && getDouble(thisPos) == that.getDouble(thatPos);
+  }
+
   @Override
   public boolean mayHaveNull() {
     return valueIsNull != null;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/FloatColumn.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/FloatColumn.java
index d8a31f110..77326c91d 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/FloatColumn.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/FloatColumn.java
@@ -20,13 +20,18 @@
 package org.apache.tsfile.read.common.block.column;
 
 import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.block.column.ColumnBuilder;
 import org.apache.tsfile.block.column.ColumnEncoding;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.RamUsageEstimator;
 import org.apache.tsfile.utils.TsPrimitiveType;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Optional;
@@ -93,6 +98,24 @@ public class FloatColumn implements Column {
     return ColumnEncoding.INT32_ARRAY;
   }
 
+  @Override
+  public Column convertTo(TSDataType type) {
+    if (type == TSDataType.FLOAT) {
+      return this;
+    }
+    ColumnUtil.checkConversion(TSDataType.FLOAT, type);
+
+    ColumnBuilder builder = Type.fromTsDataType(type).createColumnBuilder(positionCount);
+    for (int position = 0; position < positionCount; position++) {
+      if (isNull(position)) {
+        builder.appendNull();
+      } else {
+        builder.writeFloat(getFloat(position));
+      }
+    }
+    return builder.build();
+  }
+
   @Override
   public float getFloat(int position) {
     return values[position + arrayOffset];
@@ -141,6 +164,34 @@ public class FloatColumn implements Column {
     return new TsPrimitiveType.TsFloat(getFloat(position));
   }
 
+  @Override
+  public void writeTo(int index, ByteBuffer buffer) {
+    buffer.putFloat(values[index + arrayOffset]);
+  }
+
+  @Override
+  public void writeTo(int index, DataOutputStream stream) throws IOException {
+    stream.writeFloat(values[index + arrayOffset]);
+  }
+
+  @Override
+  public void serializeWithoutNulls(DataOutputStream output) throws IOException {
+    for (int i = 0; i < positionCount; i++) {
+      if (!isNull(i)) {
+        output.writeInt(Float.floatToIntBits(values[i + arrayOffset]));
+      }
+    }
+  }
+
+  @Override
+  public boolean arePositionsEqual(int thisPos, Column that, int thatPos) {
+    boolean thisIsNull = isNull(thisPos);
+    if (thisIsNull) {
+      return that.isNull(thatPos);
+    }
+    return !that.isNull(thatPos) && getFloat(thisPos) == that.getFloat(thatPos);
+  }
+
   @Override
   public boolean mayHaveNull() {
     return valueIsNull != null;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/Int32ArrayColumnEncoder.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/Int32ArrayColumnEncoder.java
index 3c6e9b1af..4e49502cd 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/Int32ArrayColumnEncoder.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/Int32ArrayColumnEncoder.java
@@ -22,6 +22,7 @@ package org.apache.tsfile.read.common.block.column;
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -39,42 +40,16 @@ public class Int32ArrayColumnEncoder implements ColumnEncoder {
     //    | byte          | list[byte]      | list[int32] |
     //    +---------------+-----------------+-------------+
 
-    boolean[] nullIndicators = ColumnEncoder.deserializeNullIndicators(input, positionCount);
-
-    switch (dataType) {
-      case INT32:
-      case DATE:
-        int[] intValues = new int[positionCount];
-        if (nullIndicators == null) {
-          for (int i = 0; i < positionCount; i++) {
-            intValues[i] = input.getInt();
-          }
-        } else {
-          for (int i = 0; i < positionCount; i++) {
-            if (!nullIndicators[i]) {
-              intValues[i] = input.getInt();
-            }
-          }
-        }
-        return new IntColumn(0, positionCount, nullIndicators, intValues);
-      case FLOAT:
-        float[] floatValues = new float[positionCount];
-        if (nullIndicators == null) {
-          for (int i = 0; i < positionCount; i++) {
-            floatValues[i] = Float.intBitsToFloat(input.getInt());
-          }
-        } else {
-          for (int i = 0; i < positionCount; i++) {
-            if (!nullIndicators[i]) {
-              floatValues[i] = Float.intBitsToFloat(input.getInt());
-            }
-          }
-        }
-        return new FloatColumn(0, positionCount, nullIndicators, floatValues);
-      default:
-        throw new IllegalArgumentException(
-            Messages.format("error.read.col_encoder_invalid_type", dataType));
+    if (dataType != TSDataType.INT32
+        && dataType != TSDataType.DATE
+        && dataType != TSDataType.FLOAT) {
+      throw new IllegalArgumentException(
+          Messages.format("error.read.col_encoder_invalid_type", dataType));
     }
+
+    boolean[] nullIndicators = ColumnEncoder.deserializeNullIndicators(input, positionCount);
+    return (Column)
+        Type.fromTsDataType(dataType).deserializeColumn(input, positionCount, nullIndicators);
   }
 
   @Override
@@ -83,38 +58,12 @@ public class Int32ArrayColumnEncoder implements ColumnEncoder {
     ColumnEncoder.serializeNullIndicators(output, column);
 
     TSDataType dataType = column.getDataType();
-    int positionCount = column.getPositionCount();
-    switch (dataType) {
-      case INT32:
-      case DATE:
-        if (column.mayHaveNull()) {
-          for (int i = 0; i < positionCount; i++) {
-            if (!column.isNull(i)) {
-              output.writeInt(column.getInt(i));
-            }
-          }
-        } else {
-          for (int i = 0; i < positionCount; i++) {
-            output.writeInt(column.getInt(i));
-          }
-        }
-        break;
-      case FLOAT:
-        if (column.mayHaveNull()) {
-          for (int i = 0; i < positionCount; i++) {
-            if (!column.isNull(i)) {
-              output.writeInt(Float.floatToIntBits(column.getFloat(i)));
-            }
-          }
-        } else {
-          for (int i = 0; i < positionCount; i++) {
-            output.writeInt(Float.floatToIntBits(column.getFloat(i)));
-          }
-        }
-        break;
-      default:
-        throw new IllegalArgumentException(
-            Messages.format("error.read.col_encoder_invalid_type", dataType));
+    if (dataType != TSDataType.INT32
+        && dataType != TSDataType.DATE
+        && dataType != TSDataType.FLOAT) {
+      throw new IllegalArgumentException(
+          Messages.format("error.read.col_encoder_invalid_type", dataType));
     }
+    column.serializeWithoutNulls(output);
   }
 }
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/Int64ArrayColumnEncoder.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/Int64ArrayColumnEncoder.java
index 0076c88f0..e7e3272c1 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/Int64ArrayColumnEncoder.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/Int64ArrayColumnEncoder.java
@@ -22,6 +22,7 @@ package org.apache.tsfile.read.common.block.column;
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -39,41 +40,16 @@ public class Int64ArrayColumnEncoder implements ColumnEncoder {
     //    | byte          | list[byte]      | list[int64] |
     //    +---------------+-----------------+-------------+
 
-    boolean[] nullIndicators = ColumnEncoder.deserializeNullIndicators(input, positionCount);
-    switch (dataType) {
-      case INT64:
-      case TIMESTAMP:
-        long[] values = new long[positionCount];
-        if (nullIndicators == null) {
-          for (int i = 0; i < positionCount; i++) {
-            values[i] = input.getLong();
-          }
-        } else {
-          for (int i = 0; i < positionCount; i++) {
-            if (!nullIndicators[i]) {
-              values[i] = input.getLong();
-            }
-          }
-        }
-        return new LongColumn(0, positionCount, nullIndicators, values);
-      case DOUBLE:
-        double[] doubleValues = new double[positionCount];
-        if (nullIndicators == null) {
-          for (int i = 0; i < positionCount; i++) {
-            doubleValues[i] = Double.longBitsToDouble(input.getLong());
-          }
-        } else {
-          for (int i = 0; i < positionCount; i++) {
-            if (!nullIndicators[i]) {
-              doubleValues[i] = Double.longBitsToDouble(input.getLong());
-            }
-          }
-        }
-        return new DoubleColumn(0, positionCount, nullIndicators, doubleValues);
-      default:
-        throw new IllegalArgumentException(
-            Messages.format("error.read.col_encoder_invalid_type", dataType));
+    if (dataType != TSDataType.INT64
+        && dataType != TSDataType.TIMESTAMP
+        && dataType != TSDataType.DOUBLE) {
+      throw new IllegalArgumentException(
+          Messages.format("error.read.col_encoder_invalid_type", dataType));
     }
+
+    boolean[] nullIndicators = ColumnEncoder.deserializeNullIndicators(input, positionCount);
+    return (Column)
+        Type.fromTsDataType(dataType).deserializeColumn(input, positionCount, nullIndicators);
   }
 
   @Override
@@ -82,26 +58,12 @@ public class Int64ArrayColumnEncoder implements ColumnEncoder {
     ColumnEncoder.serializeNullIndicators(output, column);
 
     TSDataType dataType = column.getDataType();
-    int positionCount = column.getPositionCount();
-    switch (dataType) {
-      case INT64:
-      case TIMESTAMP:
-        for (int i = 0; i < positionCount; i++) {
-          if (!column.isNull(i)) {
-            output.writeLong(column.getLong(i));
-          }
-        }
-        break;
-      case DOUBLE:
-        for (int i = 0; i < positionCount; i++) {
-          if (!column.isNull(i)) {
-            output.writeLong(Double.doubleToLongBits(column.getDouble(i)));
-          }
-        }
-        break;
-      default:
-        throw new IllegalArgumentException(
-            Messages.format("error.read.col_encoder_invalid_type", dataType));
+    if (dataType != TSDataType.INT64
+        && dataType != TSDataType.TIMESTAMP
+        && dataType != TSDataType.DOUBLE) {
+      throw new IllegalArgumentException(
+          Messages.format("error.read.col_encoder_invalid_type", dataType));
     }
+    column.serializeWithoutNulls(output);
   }
 }
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/IntColumn.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/IntColumn.java
index fbea95799..810450605 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/IntColumn.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/IntColumn.java
@@ -20,13 +20,18 @@
 package org.apache.tsfile.read.common.block.column;
 
 import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.block.column.ColumnBuilder;
 import org.apache.tsfile.block.column.ColumnEncoding;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.RamUsageEstimator;
 import org.apache.tsfile.utils.TsPrimitiveType;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Optional;
@@ -72,7 +77,7 @@ public class IntColumn implements Column {
     this.dataType = dataType;
   }
 
-  IntColumn(int arrayOffset, int positionCount, boolean[] valueIsNull, int[] values) {
+  public IntColumn(int arrayOffset, int positionCount, boolean[] valueIsNull, int[] values) {
     if (arrayOffset < 0) {
       throw new IllegalArgumentException(Messages.get("error.read.col_array_offset_negative"));
     }
@@ -111,8 +116,9 @@ public class IntColumn implements Column {
     return dataType;
   }
 
-  public void modifyDataType(TSDataType dataType) {
+  public IntColumn modifyDataType(TSDataType dataType) {
     this.dataType = dataType;
+    return this;
   }
 
   @Override
@@ -120,6 +126,28 @@ public class IntColumn implements Column {
     return ColumnEncoding.INT32_ARRAY;
   }
 
+  @Override
+  public Column convertTo(TSDataType type) {
+    if (type == dataType) {
+      return this;
+    }
+    ColumnUtil.checkConversion(dataType, type);
+
+    ColumnBuilder builder = Type.fromTsDataType(type).createColumnBuilder(positionCount);
+    for (int position = 0; position < positionCount; position++) {
+      if (isNull(position)) {
+        builder.appendNull();
+      } else if (dataType == TSDataType.DATE) {
+        // DATE has an int physical representation but a formatted text cast.
+        builder.writeBinary(
+            new Binary(TSDataType.getDateStringValue(getInt(position)), StandardCharsets.UTF_8));
+      } else {
+        builder.writeInt(getInt(position));
+      }
+    }
+    return builder.build();
+  }
+
   @Override
   public int getInt(int position) {
     return values[position + arrayOffset];
@@ -196,6 +224,34 @@ public class IntColumn implements Column {
     return new TsPrimitiveType.TsInt(getInt(position), dataType);
   }
 
+  @Override
+  public void writeTo(int index, ByteBuffer buffer) {
+    buffer.putInt(values[index + arrayOffset]);
+  }
+
+  @Override
+  public void writeTo(int index, DataOutputStream stream) throws IOException {
+    stream.writeInt(values[index + arrayOffset]);
+  }
+
+  @Override
+  public void serializeWithoutNulls(DataOutputStream output) throws IOException {
+    for (int i = 0; i < positionCount; i++) {
+      if (!isNull(i)) {
+        output.writeInt(values[i + arrayOffset]);
+      }
+    }
+  }
+
+  @Override
+  public boolean arePositionsEqual(int thisPos, Column that, int thatPos) {
+    boolean thisIsNull = isNull(thisPos);
+    if (thisIsNull) {
+      return that.isNull(thatPos);
+    }
+    return !that.isNull(thatPos) && getInt(thisPos) == that.getInt(thatPos);
+  }
+
   @Override
   public boolean mayHaveNull() {
     return valueIsNull != null;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/LongColumn.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/LongColumn.java
index 5bf01c752..7abedf523 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/LongColumn.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/LongColumn.java
@@ -20,13 +20,18 @@
 package org.apache.tsfile.read.common.block.column;
 
 import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.block.column.ColumnBuilder;
 import org.apache.tsfile.block.column.ColumnEncoding;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.RamUsageEstimator;
 import org.apache.tsfile.utils.TsPrimitiveType;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Optional;
@@ -59,7 +64,7 @@ public class LongColumn implements Column {
     this(0, positionCount, valueIsNull.orElse(null), values);
   }
 
-  LongColumn(int arrayOffset, int positionCount, boolean[] valueIsNull, long[] values) {
+  public LongColumn(int arrayOffset, int positionCount, boolean[] valueIsNull, long[] values) {
     if (arrayOffset < 0) {
       throw new IllegalArgumentException(Messages.get("error.read.col_array_offset_negative"));
     }
@@ -93,6 +98,24 @@ public class LongColumn implements Column {
     return ColumnEncoding.INT64_ARRAY;
   }
 
+  @Override
+  public Column convertTo(TSDataType type) {
+    if (type == TSDataType.INT64) {
+      return this;
+    }
+    ColumnUtil.checkConversion(TSDataType.INT64, type);
+
+    ColumnBuilder builder = Type.fromTsDataType(type).createColumnBuilder(positionCount);
+    for (int position = 0; position < positionCount; position++) {
+      if (isNull(position)) {
+        builder.appendNull();
+      } else {
+        builder.writeLong(getLong(position));
+      }
+    }
+    return builder.build();
+  }
+
   @Override
   public long getLong(int position) {
     return values[position + arrayOffset];
@@ -141,6 +164,34 @@ public class LongColumn implements Column {
     return new TsPrimitiveType.TsLong(getLong(position));
   }
 
+  @Override
+  public void writeTo(int index, ByteBuffer buffer) {
+    buffer.putLong(values[index + arrayOffset]);
+  }
+
+  @Override
+  public void writeTo(int index, DataOutputStream stream) throws IOException {
+    stream.writeLong(values[index + arrayOffset]);
+  }
+
+  @Override
+  public void serializeWithoutNulls(DataOutputStream output) throws IOException {
+    for (int i = 0; i < positionCount; i++) {
+      if (!isNull(i)) {
+        output.writeLong(values[i + arrayOffset]);
+      }
+    }
+  }
+
+  @Override
+  public boolean arePositionsEqual(int thisPos, Column that, int thatPos) {
+    boolean thisIsNull = isNull(thisPos);
+    if (thisIsNull) {
+      return that.isNull(thatPos);
+    }
+    return !that.isNull(thatPos) && getLong(thisPos) == that.getLong(thatPos);
+  }
+
   @Override
   public boolean mayHaveNull() {
     return valueIsNull != null;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/NullColumn.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/NullColumn.java
index 75c32ad61..75fea0ed5 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/NullColumn.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/NullColumn.java
@@ -23,8 +23,12 @@ import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.block.column.ColumnEncoding;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.RamUsageEstimator;
 
+import java.io.DataOutputStream;
+import java.nio.ByteBuffer;
+
 import static java.util.Objects.requireNonNull;
 import static org.apache.tsfile.read.common.block.column.ColumnUtil.checkArrayRange;
 import static org.apache.tsfile.read.common.block.column.ColumnUtil.checkReadablePosition;
@@ -61,6 +65,11 @@ public class NullColumn implements Column {
     throw new UnsupportedOperationException(getClass().getName());
   }
 
+  @Override
+  public Column convertTo(TSDataType type) {
+    return create(type, positionCount);
+  }
+
   @Override
   public boolean mayHaveNull() {
     return true;
@@ -71,11 +80,31 @@ public class NullColumn implements Column {
     return true;
   }
 
+  @Override
+  public boolean arePositionsEqual(int thisPos, Column that, int thatPos) {
+    return that.isNull(thatPos);
+  }
+
   @Override
   public boolean[] isNull() {
     throw new UnsupportedOperationException(getClass().getName());
   }
 
+  @Override
+  public void serializeWithoutNulls(DataOutputStream output) {
+    // There are no non-null values to serialize.
+  }
+
+  @Override
+  public void writeTo(int index, ByteBuffer buffer) {
+    // There is no value to serialize.
+  }
+
+  @Override
+  public void writeTo(int index, DataOutputStream stream) {
+    // There is no value to serialize.
+  }
+
   @Override
   public int getPositionCount() {
     return positionCount;
@@ -139,28 +168,7 @@ public class NullColumn implements Column {
 
   public static Column create(TSDataType dataType, int positionCount) {
     requireNonNull(dataType, "dataType is null");
-    switch (dataType) {
-      case BOOLEAN:
-        return new RunLengthEncodedColumn(BooleanColumnBuilder.NULL_VALUE_BLOCK, positionCount);
-      case INT32:
-      case DATE:
-        return new RunLengthEncodedColumn(IntColumnBuilder.NULL_VALUE_BLOCK, positionCount);
-      case INT64:
-      case TIMESTAMP:
-        return new RunLengthEncodedColumn(LongColumnBuilder.NULL_VALUE_BLOCK, positionCount);
-      case FLOAT:
-        return new RunLengthEncodedColumn(FloatColumnBuilder.NULL_VALUE_BLOCK, positionCount);
-      case DOUBLE:
-        return new RunLengthEncodedColumn(DoubleColumnBuilder.NULL_VALUE_BLOCK, positionCount);
-      case TEXT:
-      case BLOB:
-      case STRING:
-      case OBJECT:
-        return new RunLengthEncodedColumn(BinaryColumnBuilder.NULL_VALUE_BLOCK, positionCount);
-      default:
-        throw new IllegalArgumentException(
-            Messages.format("error.read.null_col_unknown_type", dataType));
-    }
+    return Type.fromTsDataType(dataType).createNullColumn(positionCount);
   }
 
   @Override
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/RunLengthEncodedColumn.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/RunLengthEncodedColumn.java
index 4414e24de..8c39c9549 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/RunLengthEncodedColumn.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/RunLengthEncodedColumn.java
@@ -27,6 +27,9 @@ import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.RamUsageEstimator;
 import org.apache.tsfile.utils.TsPrimitiveType;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.Arrays;
 
 import static java.util.Objects.requireNonNull;
@@ -76,6 +79,17 @@ public class RunLengthEncodedColumn implements Column {
     return ColumnEncoding.RLE;
   }
 
+  @Override
+  public Column convertTo(TSDataType type) {
+    TSDataType sourceType = getDataType();
+    if (type == sourceType) {
+      return this;
+    }
+    ColumnUtil.checkConversion(sourceType, type);
+    // Transform the single stored value and keep the run-length representation.
+    return new RunLengthEncodedColumn(value.convertTo(type), positionCount);
+  }
+
   @Override
   public boolean getBoolean(int position) {
     return value.getBoolean(0);
@@ -165,6 +179,21 @@ public class RunLengthEncodedColumn implements Column {
     return value.getTsPrimitiveType(0);
   }
 
+  @Override
+  public void writeTo(int index, ByteBuffer buffer) {
+    value.writeTo(0, buffer);
+  }
+
+  @Override
+  public void writeTo(int index, DataOutputStream stream) throws IOException {
+    value.writeTo(0, stream);
+  }
+
+  @Override
+  public boolean arePositionsEqual(int thisPos, Column that, int thatPos) {
+    return value.arePositionsEqual(0, that, thatPos);
+  }
+
   @Override
   public boolean mayHaveNull() {
     return value.mayHaveNull();
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/TimeColumn.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/TimeColumn.java
index 45053b971..d0dc19377 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/TimeColumn.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/TimeColumn.java
@@ -20,11 +20,16 @@
 package org.apache.tsfile.read.common.block.column;
 
 import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.block.column.ColumnBuilder;
 import org.apache.tsfile.block.column.ColumnEncoding;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.utils.RamUsageEstimator;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.Arrays;
 
 import static org.apache.tsfile.read.common.block.column.ColumnUtil.checkArrayRange;
@@ -80,6 +85,20 @@ public class TimeColumn implements Column {
     return ColumnEncoding.INT64_ARRAY;
   }
 
+  @Override
+  public Column convertTo(TSDataType type) {
+    if (type == TSDataType.INT64) {
+      return this;
+    }
+    ColumnUtil.checkConversion(TSDataType.INT64, type);
+
+    ColumnBuilder builder = Type.fromTsDataType(type).createColumnBuilder(positionCount);
+    for (int position = 0; position < positionCount; position++) {
+      builder.writeLong(getLong(position));
+    }
+    return builder.build();
+  }
+
   @Override
   public long getLong(int position) {
     return values[position + arrayOffset];
@@ -90,6 +109,28 @@ public class TimeColumn implements Column {
     return getLong(position);
   }
 
+  @Override
+  public void writeTo(int index, ByteBuffer buffer) {
+    buffer.putLong(values[index + arrayOffset]);
+  }
+
+  @Override
+  public void writeTo(int index, DataOutputStream stream) throws IOException {
+    stream.writeLong(values[index + arrayOffset]);
+  }
+
+  @Override
+  public void serializeWithoutNulls(DataOutputStream output) throws IOException {
+    for (int i = 0; i < positionCount; i++) {
+      output.writeLong(values[i + arrayOffset]);
+    }
+  }
+
+  @Override
+  public boolean arePositionsEqual(int thisPos, Column that, int thatPos) {
+    return !that.isNull(thatPos) && getLong(thisPos) == that.getLong(thatPos);
+  }
+
   public boolean mayHaveNull() {
     return false;
   }
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractIntType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractIntType.java
index 8425a8793..e4a811741 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractIntType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractIntType.java
@@ -21,13 +21,311 @@ package org.apache.tsfile.read.common.type;
 
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.block.column.ColumnBuilderStatus;
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.encoding.decoder.Decoder;
+import org.apache.tsfile.encoding.decoder.DeltaBinaryDecoder;
+import org.apache.tsfile.encoding.decoder.IntChimpDecoder;
+import org.apache.tsfile.encoding.decoder.IntGorillaDecoder;
+import org.apache.tsfile.encoding.decoder.IntRLBEDecoder;
+import org.apache.tsfile.encoding.decoder.IntRleDecoder;
+import org.apache.tsfile.encoding.decoder.IntSprintzDecoder;
+import org.apache.tsfile.encoding.decoder.IntZigzagDecoder;
+import org.apache.tsfile.encoding.decoder.RegularDataDecoder;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.file.metadata.statistics.IntegerStatistics;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.read.common.block.column.IntColumn;
 import org.apache.tsfile.read.common.block.column.IntColumnBuilder;
+import org.apache.tsfile.read.common.block.column.RunLengthEncodedColumn;
+import org.apache.tsfile.read.query.dataset.ResultSet;
+import org.apache.tsfile.utils.BytesUtils;
+import org.apache.tsfile.utils.RamUsageEstimator;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.apache.tsfile.utils.TsPrimitiveType;
+import org.apache.tsfile.write.chunk.ChunkWriterImpl;
+import org.apache.tsfile.write.chunk.ValueChunkWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.IntDataPoint;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 public abstract class AbstractIntType extends AbstractType {
 
+  @Override
+  public void toBytes(TsPrimitiveType value, byte[] valueBytes, int offset) {
+    BytesUtils.intToBytes(value.getInt(), valueBytes, offset);
+  }
+
+  @Override
+  public int calcTypeSize(TsPrimitiveType value) {
+    return Integer.BYTES;
+  }
+
+  @Override
+  public int calcTypeSize(Object value) {
+    return Integer.BYTES;
+  }
+
+  @Override
+  public void init(BatchData batchData) {
+    batchData.initIntValues();
+  }
+
+  @Override
+  public void put(BatchData batchData, long timestamp, Object value) {
+    batchData.putInt(timestamp, (int) value);
+  }
+
+  @Override
+  public int serialize(BatchData batchData, DataOutputStream outputStream, boolean isDesc)
+      throws IOException {
+    for (int i = 0; i < batchData.length(); i++) {
+      int index = isDesc ? batchData.length() - 1 - i : i;
+      outputStream.writeLong(batchData.getTimeByIndex(index));
+      outputStream.writeInt(batchData.getIntByIndex(index));
+    }
+    return Math.multiplyExact(Long.BYTES + Integer.BYTES, batchData.length());
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer, BatchData batchData, int length) {
+    for (int i = 0; i < length; i++) {
+      batchData.putInt(buffer.getLong(), buffer.getInt());
+    }
+  }
+
+  @Override
+  public TsPrimitiveType deserialize(ByteBuffer buffer) {
+    return new TsPrimitiveType.TsInt(ReadWriteIOUtils.readInt(buffer));
+  }
+
+  @Override
+  public int serialize(TsPrimitiveType value, DataOutputStream stream) throws IOException {
+    stream.writeInt(value.getInt());
+    return Integer.BYTES;
+  }
+
+  @Override
+  public int serializeValue(Object value, ByteBuffer buffer) {
+    buffer.putInt((int) value);
+    return Integer.BYTES;
+  }
+
+  @Override
+  public int serializeValue(Object value, DataOutputStream stream) throws IOException {
+    stream.writeInt((int) value);
+    return Integer.BYTES;
+  }
+
+  @Override
+  public TSEncoding getDefaultEncoding(TSFileConfig config) {
+    return TSEncoding.valueOf(config.getInt32Encoding());
+  }
+
+  @Override
+  public CompressionType getDefaultCompressor(TSFileConfig config) {
+    return config.getInt32Compressor();
+  }
+
+  @Override
+  public Decoder getDecoder(TSEncoding encoding) {
+    return switch (encoding) {
+      case PLAIN, DICTIONARY -> super.getDecoder(encoding);
+      case RLE -> new IntRleDecoder();
+      case TS_2DIFF -> new DeltaBinaryDecoder.IntDeltaDecoder();
+      case REGULAR -> new RegularDataDecoder.IntRegularDecoder();
+      case GORILLA -> new IntGorillaDecoder();
+      case ZIGZAG -> new IntZigzagDecoder();
+      case CHIMP -> new IntChimpDecoder();
+      case SPRINTZ -> new IntSprintzDecoder();
+      case RLBE -> new IntRLBEDecoder();
+      default -> throw decoderNotFound(encoding);
+    };
+  }
+
+  @Override
+  public int getOneItemMaxSize(int valveLength) {
+    return Integer.BYTES;
+  }
+
+  @Override
+  public Statistics<?> createStatistics() {
+    return new IntegerStatistics();
+  }
+
+  @Override
+  public long getStatisticsInstanceSize() {
+    return IntegerStatistics.INSTANCE_SIZE;
+  }
+
+  @Override
+  public void update(Statistics<?> stats, long timestamp, TsPrimitiveType value) {
+    stats.update(timestamp, value.getInt());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, BatchData batchData) {
+    stats.update(batchData.currentTime(), batchData.getInt());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, TsBlock block, int columnIndex, int rowIndex) {
+    stats.update(block.getTimeByIndex(rowIndex), block.getColumn(columnIndex).getInt(rowIndex));
+  }
+
+  @Override
+  public Object getCurrentValue(BatchData batchData) {
+    return batchData.getInt();
+  }
+
+  @Override
+  public String toString(Field field) {
+    return String.valueOf(field.getIntV());
+  }
+
+  @Override
+  public Object getValue(Field field) {
+    return field.getIntV();
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Field to) {
+    to.setIntV(from.getInt());
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Column to, int index) {
+    to.getInts()[index] = from.getInt();
+  }
+
+  @Override
+  public void setTo(Object value, Column to, int startIndex, int endIndex) {
+    Arrays.fill(to.getInts(), startIndex, endIndex, (int) value);
+  }
+
+  @Override
+  public void setTo(Field from, Field to) {
+    to.setIntV(from.getIntV());
+  }
+
+  @Override
+  public void setTo(BatchData from, Field to) {
+    to.setIntV(from.getInt());
+  }
+
+  @Override
+  public void setTo(BatchData from, Column to, int index) {
+    to.getInts()[index] = from.getInt();
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Column to, int toIndex) {
+    to.getInts()[toIndex] = from.getInt(fromIndex);
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Object toArray, int toIndex) {
+    ((int[]) toArray)[toIndex] = from.getInt(fromIndex);
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, Field field) {
+    record.addPoint(columnName, field.getIntV());
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, ResultSet resultSet) {
+    record.addPoint(columnName, resultSet.getInt(columnName));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, String value) {
+    return new IntDataPoint(measurementId, Integer.parseInt(value));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, long value) {
+    return new IntDataPoint(measurementId, (int) value);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, Object value, boolean isNull) {
+    writer.write(time, isNull ? 0 : (int) value, isNull);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, TsPrimitiveType value) {
+    writer.write(time, value != null ? value.getInt() : Integer.MAX_VALUE, value == null);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Object array, int rowIndex, boolean isNull) {
+    writer.write(time, ((int[]) array)[rowIndex], isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Column column, int rowIndex, boolean isNull) {
+    writer.write(time, isNull ? 0 : column.getInt(rowIndex), isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long[] times, Column column, int batchSize, int arrayOffset) {
+    writer.write(times, column.getInts(), column.isNull(), batchSize, arrayOffset);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object column, int rowIndex) {
+    writer.write(time, ((int[]) column)[rowIndex]);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, TsPrimitiveType value) {
+    writer.write(time, value.getInt());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, BatchData data) {
+    writer.write(time, data.getInt());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object value) {
+    writer.write(time, (int) value);
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType() {
+    return new TsPrimitiveType.TsInt();
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType(Object value) {
+    return new TsPrimitiveType.TsInt((int) value);
+  }
+
+  @Override
+  public TsPrimitiveType getValueAsTsPrimitiveType(Object array, int rowIndex) {
+    return new TsPrimitiveType.TsInt(((int[]) array)[rowIndex]);
+  }
+
   @Override
   public int getInt(Column c, int position) {
     return c.getInt(position);
@@ -48,6 +346,31 @@ public abstract class AbstractIntType extends AbstractType {
     return c.getInt(position);
   }
 
+  @Override
+  public void write(ColumnBuilder builder, TsPrimitiveType value) {
+    builder.writeInt(value.getInt());
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, byte[] bytes, int offset) {
+    builder.writeInt(BytesUtils.bytesToInt(bytes, offset));
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, Column column, int index) {
+    builder.writeInt(column.getInt(index));
+  }
+
+  @Override
+  public void write(TsPrimitiveType from, Object toArray, int index) {
+    ((int[]) toArray)[index] = from.getInt();
+  }
+
+  @Override
+  public void write(BatchData from, Object toArray, int index) {
+    ((int[]) toArray)[index] = from.getInt();
+  }
+
   @Override
   public void writeInt(ColumnBuilder builder, int value) {
     builder.writeInt(value);
@@ -68,11 +391,145 @@ public abstract class AbstractIntType extends AbstractType {
     builder.writeInt((int) value);
   }
 
+  @Override
+  public void addValue(int rowIndex, Object value, Object array) {
+    checkValueType(value, Integer.class, "Integer");
+    ((int[]) array)[rowIndex] = value != null ? (int) value : Integer.MIN_VALUE;
+  }
+
+  @Override
+  public void copyArrayElement(Object source, int sourceIndex, Object target, int targetIndex) {
+    ((int[]) target)[targetIndex] = ((int[]) source)[sourceIndex];
+  }
+
+  @Override
+  public Object arrayCopyOf(Object array, int newLength) {
+    return Arrays.copyOf((int[]) array, newLength);
+  }
+
+  @Override
+  public Object createArray(int capacity) {
+    return new int[capacity];
+  }
+
+  @Override
+  public long estimateArraySize(int size) {
+    return RamUsageEstimator.sizeOfIntArray(size);
+  }
+
+  @Override
+  public long estimateValueSize() {
+    return Integer.BYTES;
+  }
+
+  @Override
+  public int serializedSize(Object array, int rowSize) {
+    return Math.multiplyExact(Integer.BYTES, rowSize);
+  }
+
+  @Override
+  public void serializeArray(Object array, int rowSize, DataOutputStream stream)
+      throws IOException {
+    int[] values = (int[]) array;
+    for (int i = 0; i < rowSize; i++) {
+      ReadWriteIOUtils.write(values[i], stream);
+    }
+  }
+
+  @Override
+  public void serializeArray(Object array, int length, ByteBuffer buffer) {
+    int[] values = (int[]) array;
+    for (int i = 0; i < length; i++) {
+      buffer.putInt(values[i]);
+    }
+  }
+
+  @Override
+  public Object deserializeArray(ByteBuffer buffer, int rowSize) {
+    int[] values = new int[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = ReadWriteIOUtils.readInt(buffer);
+    }
+    return values;
+  }
+
+  @Override
+  public Object deserializeArray(DataInputStream stream, int rowSize) throws IOException {
+    int[] values = new int[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = ReadWriteIOUtils.readInt(stream);
+    }
+    return values;
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, ByteBuffer buffer) {
+    array[index] = ReadWriteIOUtils.readInt(buffer);
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, InputStream stream) throws IOException {
+    array[index] = ReadWriteIOUtils.readInt(stream);
+  }
+
+  @Override
+  public Object deserializeColumn(ByteBuffer buffer, int rowSize, boolean[] nullIndicators) {
+    int[] intValues = new int[rowSize];
+    if (nullIndicators == null) {
+      for (int i = 0; i < rowSize; i++) {
+        intValues[i] = buffer.getInt();
+      }
+    } else {
+      for (int i = 0; i < rowSize; i++) {
+        if (!nullIndicators[i]) {
+          intValues[i] = buffer.getInt();
+        }
+      }
+    }
+    return new IntColumn(0, rowSize, nullIndicators, intValues);
+  }
+
+  @Override
+  public boolean arrayEquals(Object left, Object right, int rowSize) {
+    return hasEnoughLength(left, right, rowSize)
+        && Arrays.equals((int[]) left, 0, rowSize, (int[]) right, 0, rowSize);
+  }
+
+  @Override
+  public long estimateArraySize(Object array) {
+    return RamUsageEstimator.sizeOf((int[]) array);
+  }
+
+  @Override
+  public Column createColumnWithMaxPosition(int positionCount) {
+    return new IntColumn(
+        positionCount,
+        Optional.of(new boolean[positionCount]),
+        new int[positionCount],
+        TSDataType.INT32);
+  }
+
+  @Override
+  public Column createColumnWithZeroPosition(int positionCount) {
+    return new IntColumn(positionCount);
+  }
+
+  @Override
+  public Column createNullColumn(int positionCount) {
+    return new RunLengthEncodedColumn(IntColumnBuilder.NULL_VALUE_BLOCK, positionCount);
+  }
+
   @Override
   public ColumnBuilder createColumnBuilder(int expectedEntries) {
     return new IntColumnBuilder(null, expectedEntries);
   }
 
+  @Override
+  public ColumnBuilder createColumnBuilder(
+      ColumnBuilderStatus columnBuilderStatus, int expectedEntries) {
+    return new IntColumnBuilder(columnBuilderStatus, expectedEntries);
+  }
+
   @Override
   public boolean isComparable() {
     return true;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractLongType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractLongType.java
index e8e1ecbc3..5e2aedf2f 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractLongType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractLongType.java
@@ -21,13 +21,310 @@ package org.apache.tsfile.read.common.type;
 
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.block.column.ColumnBuilderStatus;
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.encoding.decoder.Decoder;
+import org.apache.tsfile.encoding.decoder.DeltaBinaryDecoder;
+import org.apache.tsfile.encoding.decoder.LongChimpDecoder;
+import org.apache.tsfile.encoding.decoder.LongGorillaDecoder;
+import org.apache.tsfile.encoding.decoder.LongRLBEDecoder;
+import org.apache.tsfile.encoding.decoder.LongRleDecoder;
+import org.apache.tsfile.encoding.decoder.LongSprintzDecoder;
+import org.apache.tsfile.encoding.decoder.LongZigzagDecoder;
+import org.apache.tsfile.encoding.decoder.RegularDataDecoder;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.file.metadata.statistics.LongStatistics;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.read.common.block.column.LongColumn;
 import org.apache.tsfile.read.common.block.column.LongColumnBuilder;
+import org.apache.tsfile.read.common.block.column.RunLengthEncodedColumn;
+import org.apache.tsfile.read.query.dataset.ResultSet;
+import org.apache.tsfile.utils.BytesUtils;
+import org.apache.tsfile.utils.RamUsageEstimator;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.apache.tsfile.utils.TsPrimitiveType;
+import org.apache.tsfile.write.chunk.ChunkWriterImpl;
+import org.apache.tsfile.write.chunk.ValueChunkWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.LongDataPoint;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 public abstract class AbstractLongType extends AbstractType {
 
+  @Override
+  public void toBytes(TsPrimitiveType value, byte[] valueBytes, int offset) {
+    BytesUtils.longToBytes(value.getLong(), valueBytes, offset);
+  }
+
+  @Override
+  public int calcTypeSize(TsPrimitiveType value) {
+    return Long.BYTES;
+  }
+
+  @Override
+  public int calcTypeSize(Object value) {
+    return Long.BYTES;
+  }
+
+  @Override
+  public void init(BatchData batchData) {
+    batchData.initLongValues();
+  }
+
+  @Override
+  public void put(BatchData batchData, long timestamp, Object value) {
+    batchData.putLong(timestamp, (long) value);
+  }
+
+  @Override
+  public int serialize(BatchData batchData, DataOutputStream outputStream, boolean isDesc)
+      throws IOException {
+    for (int i = 0; i < batchData.length(); i++) {
+      int index = isDesc ? batchData.length() - 1 - i : i;
+      outputStream.writeLong(batchData.getTimeByIndex(index));
+      outputStream.writeLong(batchData.getLongByIndex(index));
+    }
+    return Math.multiplyExact(Long.BYTES + Long.BYTES, batchData.length());
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer, BatchData batchData, int length) {
+    for (int i = 0; i < length; i++) {
+      batchData.putLong(buffer.getLong(), buffer.getLong());
+    }
+  }
+
+  @Override
+  public TsPrimitiveType deserialize(ByteBuffer buffer) {
+    return new TsPrimitiveType.TsLong(ReadWriteIOUtils.readLong(buffer));
+  }
+
+  @Override
+  public int serialize(TsPrimitiveType value, DataOutputStream stream) throws IOException {
+    stream.writeLong(value.getLong());
+    return Long.BYTES;
+  }
+
+  @Override
+  public int serializeValue(Object value, ByteBuffer buffer) {
+    buffer.putLong((long) value);
+    return Long.BYTES;
+  }
+
+  @Override
+  public int serializeValue(Object value, DataOutputStream stream) throws IOException {
+    stream.writeLong((long) value);
+    return Long.BYTES;
+  }
+
+  @Override
+  public TSEncoding getDefaultEncoding(TSFileConfig config) {
+    return TSEncoding.valueOf(config.getInt64Encoding());
+  }
+
+  @Override
+  public CompressionType getDefaultCompressor(TSFileConfig config) {
+    return config.getInt64Compressor();
+  }
+
+  @Override
+  public Decoder getDecoder(TSEncoding encoding) {
+    return switch (encoding) {
+      case PLAIN, DICTIONARY -> super.getDecoder(encoding);
+      case RLE -> new LongRleDecoder();
+      case TS_2DIFF -> new DeltaBinaryDecoder.LongDeltaDecoder();
+      case REGULAR -> new RegularDataDecoder.LongRegularDecoder();
+      case GORILLA -> new LongGorillaDecoder();
+      case ZIGZAG -> new LongZigzagDecoder();
+      case CHIMP -> new LongChimpDecoder();
+      case SPRINTZ -> new LongSprintzDecoder();
+      case RLBE -> new LongRLBEDecoder();
+      default -> throw decoderNotFound(encoding);
+    };
+  }
+
+  @Override
+  public int getOneItemMaxSize(int valveLength) {
+    return Long.BYTES;
+  }
+
+  @Override
+  public Statistics<?> createStatistics() {
+    return new LongStatistics();
+  }
+
+  @Override
+  public long getStatisticsInstanceSize() {
+    return LongStatistics.INSTANCE_SIZE;
+  }
+
+  @Override
+  public void update(Statistics<?> stats, long timestamp, TsPrimitiveType value) {
+    stats.update(timestamp, value.getLong());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, BatchData batchData) {
+    stats.update(batchData.currentTime(), batchData.getLong());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, TsBlock block, int columnIndex, int rowIndex) {
+    stats.update(block.getTimeByIndex(rowIndex), block.getColumn(columnIndex).getLong(rowIndex));
+  }
+
+  @Override
+  public Object getCurrentValue(BatchData batchData) {
+    return batchData.getLong();
+  }
+
+  @Override
+  public String toString(Field field) {
+    return String.valueOf(field.getLongV());
+  }
+
+  @Override
+  public Object getValue(Field field) {
+    return field.getLongV();
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Field to) {
+    to.setLongV(from.getLong());
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Column to, int index) {
+    to.getLongs()[index] = from.getLong();
+  }
+
+  @Override
+  public void setTo(Object value, Column to, int startIndex, int endIndex) {
+    Arrays.fill(to.getLongs(), startIndex, endIndex, (long) value);
+  }
+
+  @Override
+  public void setTo(Field from, Field to) {
+    to.setLongV(from.getLongV());
+  }
+
+  @Override
+  public void setTo(BatchData from, Field to) {
+    to.setLongV(from.getLong());
+  }
+
+  @Override
+  public void setTo(BatchData from, Column to, int index) {
+    to.getLongs()[index] = from.getLong();
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Column to, int toIndex) {
+    to.getLongs()[toIndex] = from.getLong(fromIndex);
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Object toArray, int toIndex) {
+    ((long[]) toArray)[toIndex] = from.getLong(fromIndex);
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, Field field) {
+    record.addPoint(columnName, field.getLongV());
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, ResultSet resultSet) {
+    record.addPoint(columnName, resultSet.getLong(columnName));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, String value) {
+    return new LongDataPoint(measurementId, Long.parseLong(value));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, long value) {
+    return new LongDataPoint(measurementId, value);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, Object value, boolean isNull) {
+    writer.write(time, isNull ? 0L : (long) value, isNull);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, TsPrimitiveType value) {
+    writer.write(time, value != null ? value.getLong() : Long.MAX_VALUE, value == null);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Object array, int rowIndex, boolean isNull) {
+    writer.write(time, ((long[]) array)[rowIndex], isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Column column, int rowIndex, boolean isNull) {
+    writer.write(time, isNull ? 0 : column.getLong(rowIndex), isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long[] times, Column column, int batchSize, int arrayOffset) {
+    writer.write(times, column.getLongs(), column.isNull(), batchSize, arrayOffset);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object column, int rowIndex) {
+    writer.write(time, ((long[]) column)[rowIndex]);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, TsPrimitiveType value) {
+    writer.write(time, value.getLong());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, BatchData data) {
+    writer.write(time, data.getLong());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object value) {
+    writer.write(time, (long) value);
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType() {
+    return new TsPrimitiveType.TsLong();
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType(Object value) {
+    return new TsPrimitiveType.TsLong((long) value);
+  }
+
+  @Override
+  public TsPrimitiveType getValueAsTsPrimitiveType(Object array, int rowIndex) {
+    return new TsPrimitiveType.TsLong(((long[]) array)[rowIndex]);
+  }
+
   @Override
   public int getInt(Column c, int position) {
     return (int) c.getLong(position);
@@ -48,6 +345,31 @@ public abstract class AbstractLongType extends AbstractType {
     return c.getLong(position);
   }
 
+  @Override
+  public void write(ColumnBuilder builder, TsPrimitiveType value) {
+    builder.writeLong(value.getLong());
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, byte[] bytes, int offset) {
+    builder.writeLong(BytesUtils.bytesToLongFromOffset(bytes, Long.BYTES, offset));
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, Column column, int index) {
+    builder.writeLong(column.getLong(index));
+  }
+
+  @Override
+  public void write(TsPrimitiveType from, Object toArray, int index) {
+    ((long[]) toArray)[index] = from.getLong();
+  }
+
+  @Override
+  public void write(BatchData from, Object toArray, int index) {
+    ((long[]) toArray)[index] = from.getLong();
+  }
+
   @Override
   public void writeInt(ColumnBuilder builder, int value) {
     builder.writeLong(value);
@@ -68,11 +390,142 @@ public abstract class AbstractLongType extends AbstractType {
     builder.writeLong((long) value);
   }
 
+  @Override
+  public void addValue(int rowIndex, Object value, Object array) {
+    checkValueType(value, Long.class, "Long");
+    ((long[]) array)[rowIndex] = value != null ? (long) value : Long.MIN_VALUE;
+  }
+
+  @Override
+  public void copyArrayElement(Object source, int sourceIndex, Object target, int targetIndex) {
+    ((long[]) target)[targetIndex] = ((long[]) source)[sourceIndex];
+  }
+
+  @Override
+  public Object arrayCopyOf(Object array, int newLength) {
+    return Arrays.copyOf((long[]) array, newLength);
+  }
+
+  @Override
+  public Object createArray(int capacity) {
+    return new long[capacity];
+  }
+
+  @Override
+  public long estimateArraySize(int size) {
+    return RamUsageEstimator.sizeOfLongArray(size);
+  }
+
+  @Override
+  public long estimateValueSize() {
+    return Long.BYTES;
+  }
+
+  @Override
+  public int serializedSize(Object array, int rowSize) {
+    return Math.multiplyExact(Long.BYTES, rowSize);
+  }
+
+  @Override
+  public void serializeArray(Object array, int rowSize, DataOutputStream stream)
+      throws IOException {
+    long[] values = (long[]) array;
+    for (int i = 0; i < rowSize; i++) {
+      ReadWriteIOUtils.write(values[i], stream);
+    }
+  }
+
+  @Override
+  public void serializeArray(Object array, int length, ByteBuffer buffer) {
+    long[] values = (long[]) array;
+    for (int i = 0; i < length; i++) {
+      buffer.putLong(values[i]);
+    }
+  }
+
+  @Override
+  public Object deserializeArray(ByteBuffer buffer, int rowSize) {
+    long[] values = new long[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = ReadWriteIOUtils.readLong(buffer);
+    }
+    return values;
+  }
+
+  @Override
+  public Object deserializeArray(DataInputStream stream, int rowSize) throws IOException {
+    long[] values = new long[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = ReadWriteIOUtils.readLong(stream);
+    }
+    return values;
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, ByteBuffer buffer) {
+    array[index] = ReadWriteIOUtils.readLong(buffer);
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, InputStream stream) throws IOException {
+    array[index] = ReadWriteIOUtils.readLong(stream);
+  }
+
+  @Override
+  public Object deserializeColumn(ByteBuffer buffer, int rowSize, boolean[] nullIndicators) {
+    long[] intValues = new long[rowSize];
+    if (nullIndicators == null) {
+      for (int i = 0; i < rowSize; i++) {
+        intValues[i] = buffer.getLong();
+      }
+    } else {
+      for (int i = 0; i < rowSize; i++) {
+        if (!nullIndicators[i]) {
+          intValues[i] = buffer.getLong();
+        }
+      }
+    }
+    return new LongColumn(0, rowSize, nullIndicators, intValues);
+  }
+
+  @Override
+  public boolean arrayEquals(Object left, Object right, int rowSize) {
+    return hasEnoughLength(left, right, rowSize)
+        && Arrays.equals((long[]) left, 0, rowSize, (long[]) right, 0, rowSize);
+  }
+
+  @Override
+  public long estimateArraySize(Object array) {
+    return RamUsageEstimator.sizeOf((long[]) array);
+  }
+
+  @Override
+  public Column createColumnWithMaxPosition(int positionCount) {
+    return new LongColumn(
+        positionCount, Optional.of(new boolean[positionCount]), new long[positionCount]);
+  }
+
+  @Override
+  public Column createColumnWithZeroPosition(int positionCount) {
+    return new LongColumn(positionCount);
+  }
+
+  @Override
+  public Column createNullColumn(int positionCount) {
+    return new RunLengthEncodedColumn(LongColumnBuilder.NULL_VALUE_BLOCK, positionCount);
+  }
+
   @Override
   public ColumnBuilder createColumnBuilder(int expectedEntries) {
     return new LongColumnBuilder(null, expectedEntries);
   }
 
+  @Override
+  public ColumnBuilder createColumnBuilder(
+      ColumnBuilderStatus columnBuilderStatus, int expectedEntries) {
+    return new LongColumnBuilder(columnBuilderStatus, expectedEntries);
+  }
+
   @Override
   public boolean isComparable() {
     return true;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractType.java
index 937b7fdcc..2afe06758 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractType.java
@@ -19,8 +19,162 @@
 
 package org.apache.tsfile.read.common.type;
 
+import org.apache.tsfile.encoding.decoder.Decoder;
+import org.apache.tsfile.encoding.decoder.DictionaryDecoder;
+import org.apache.tsfile.encoding.decoder.PlainDecoder;
+import org.apache.tsfile.exception.encoding.TsFileDecodingException;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.utils.Binary;
+import org.apache.tsfile.utils.BytesUtils;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.apache.tsfile.utils.TsPrimitiveType;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
 public abstract class AbstractType implements Type {
 
+  private static final String DECODER_NOT_FOUND_ERROR_KEY = "error.encoding.decoder_not_found";
+
+  @Override
+  public Decoder getDecoder(TSEncoding encoding) {
+    return switch (encoding) {
+      case PLAIN -> new PlainDecoder();
+      case DICTIONARY -> new DictionaryDecoder();
+      default -> throw decoderNotFound(encoding);
+    };
+  }
+
+  protected TsFileDecodingException decoderNotFound(TSEncoding encoding) {
+    return new TsFileDecodingException(
+        Messages.format(DECODER_NOT_FOUND_ERROR_KEY, encoding, getTypeEnum()));
+  }
+
+  protected void binaryToBytes(TsPrimitiveType value, byte[] valueBytes, int offset) {
+    Binary binary = value.getBinary();
+    BytesUtils.intToBytes(binary.getLength(), valueBytes, offset);
+    System.arraycopy(binary.getValues(), 0, valueBytes, offset + Integer.BYTES, binary.getLength());
+  }
+
+  protected int binaryTypeSize(TsPrimitiveType value) {
+    return Integer.BYTES + value.getBinary().getLength();
+  }
+
+  protected int binaryTypeSize(Object value) {
+    return Integer.BYTES + ((Binary) value).getLength();
+  }
+
+  protected void checkValueType(Object value, Class<?> expectedClass, String expectedType) {
+    if (value != null && !expectedClass.isInstance(value)) {
+      throw new IllegalArgumentException(
+          Messages.format(
+              "error.write.tablet_expected_type",
+              expectedType,
+              getDisplayName(),
+              value.getClass().getName()));
+    }
+  }
+
+  protected int serializedSizeOfBinaryValues(Object array, int rowSize) {
+    return serializedSizeOfBinaryValues(array, 0, rowSize);
+  }
+
+  protected int serializedSizeOfBinaryValues(Object array, int startRow, int endRow) {
+    Binary[] binaryValues = (Binary[]) array;
+    int size = 0;
+    for (int i = startRow; i < endRow; i++) {
+      size = Math.addExact(size, Byte.BYTES);
+      if (binaryValues[i] != null) {
+        size = Math.addExact(size, ReadWriteIOUtils.sizeToWrite(binaryValues[i]));
+      }
+    }
+    return size;
+  }
+
+  protected void serializeBinaryValues(Object array, int rowSize, DataOutputStream stream)
+      throws IOException {
+    Binary[] binaryValues = (Binary[]) array;
+    for (int i = 0; i < rowSize; i++) {
+      ReadWriteIOUtils.write(BytesUtils.boolToByte(binaryValues[i] != null), stream);
+      if (binaryValues[i] != null) {
+        ReadWriteIOUtils.write(binaryValues[i], stream);
+      }
+    }
+  }
+
+  protected void serializeBinaryValues(Object array, int length, ByteBuffer buffer) {
+    Binary[] binaryValues = (Binary[]) array;
+    for (int i = 0; i < length; i++) {
+      ReadWriteIOUtils.write(BytesUtils.boolToByte(binaryValues[i] != null), buffer);
+      if (binaryValues[i] != null) {
+        ReadWriteIOUtils.write(binaryValues[i], buffer);
+      }
+    }
+  }
+
+  protected Binary[] deserializeBinaryValues(ByteBuffer buffer, int rowSize) {
+    Binary[] values = new Binary[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      boolean isNotNull = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(buffer));
+      values[i] = isNotNull ? ReadWriteIOUtils.readBinary(buffer) : Binary.EMPTY_VALUE;
+    }
+    return values;
+  }
+
+  protected Binary[] deserializeBinaryValues(DataInputStream stream, int rowSize)
+      throws IOException {
+    Binary[] values = new Binary[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = stream.readBoolean() ? ReadWriteIOUtils.readBinary(stream) : Binary.EMPTY_VALUE;
+    }
+    return values;
+  }
+
+  protected Binary[] deserializeBinaryValues(
+      ByteBuffer buffer, int rowSize, boolean[] nullIndicators) {
+    Binary[] values = new Binary[rowSize];
+    if (nullIndicators == null) {
+      for (int i = 0; i < rowSize; i++) {
+        values[i] = ReadWriteIOUtils.readBinary(buffer);
+      }
+    } else {
+      for (int i = 0; i < rowSize; i++) {
+        if (!nullIndicators[i]) {
+          values[i] = ReadWriteIOUtils.readBinary(buffer);
+        }
+      }
+    }
+    return values;
+  }
+
+  protected boolean hasEnoughLength(Object left, Object right, int rowSize) {
+    return Array.getLength(left) >= rowSize && Array.getLength(right) >= rowSize;
+  }
+
+  protected boolean binaryArrayEquals(Object left, Object right, int rowSize) {
+    if (!hasEnoughLength(left, right, rowSize)) {
+      return false;
+    }
+    Binary[] leftValues = (Binary[]) left;
+    Binary[] rightValues = (Binary[]) right;
+    for (int i = 0; i < rowSize; i++) {
+      if (!Objects.equals(leftValues[i], rightValues[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @Override
+  public Object getValue(Object array, int rowIndex) {
+    return Array.get(array, rowIndex);
+  }
+
   @Override
   public String toString() {
     return getDisplayName();
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractVarcharType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractVarcharType.java
index d09ed07c6..0072a8148 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractVarcharType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/AbstractVarcharType.java
@@ -21,28 +21,457 @@ package org.apache.tsfile.read.common.type;
 
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.block.column.ColumnBuilderStatus;
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.file.metadata.statistics.BinaryStatistics;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.read.common.block.column.BinaryColumn;
 import org.apache.tsfile.read.common.block.column.BinaryColumnBuilder;
+import org.apache.tsfile.read.common.block.column.RunLengthEncodedColumn;
+import org.apache.tsfile.read.query.dataset.ResultSet;
 import org.apache.tsfile.utils.Binary;
+import org.apache.tsfile.utils.BytesUtils;
+import org.apache.tsfile.utils.RamUsageEstimator;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.apache.tsfile.utils.TsPrimitiveType;
+import org.apache.tsfile.write.chunk.ChunkWriterImpl;
+import org.apache.tsfile.write.chunk.ValueChunkWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.StringDataPoint;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 public abstract class AbstractVarcharType extends AbstractType {
+
+  @Override
+  public void toBytes(TsPrimitiveType value, byte[] valueBytes, int offset) {
+    binaryToBytes(value, valueBytes, offset);
+  }
+
+  @Override
+  public int calcTypeSize(TsPrimitiveType value) {
+    return binaryTypeSize(value);
+  }
+
+  @Override
+  public int calcTypeSize(Object value) {
+    return binaryTypeSize(value);
+  }
+
+  @Override
+  public void init(BatchData batchData) {
+    batchData.initBinaryValues();
+  }
+
+  @Override
+  public void put(BatchData batchData, long timestamp, Object value) {
+    batchData.putBinary(timestamp, (Binary) value);
+  }
+
+  @Override
+  public int serialize(BatchData batchData, DataOutputStream outputStream, boolean isDesc)
+      throws IOException {
+    int size = 0;
+    for (int i = 0; i < batchData.length(); i++) {
+      int index = isDesc ? batchData.length() - 1 - i : i;
+      outputStream.writeLong(batchData.getTimeByIndex(index));
+      Binary binary = batchData.getBinaryByIndex(index);
+      outputStream.writeInt(binary.getLength());
+      outputStream.write(binary.getValues());
+      size = Math.addExact(size, Long.BYTES + Integer.BYTES);
+      size = Math.addExact(size, binary.getLength());
+    }
+    return size;
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer, BatchData batchData, int length) {
+    for (int i = 0; i < length; i++) {
+      batchData.putBinary(buffer.getLong(), ReadWriteIOUtils.readBinary(buffer));
+    }
+  }
+
+  @Override
+  public TsPrimitiveType deserialize(ByteBuffer buffer) {
+    return new TsPrimitiveType.TsBinary(ReadWriteIOUtils.readBinary(buffer));
+  }
+
+  @Override
+  public int serialize(TsPrimitiveType value, DataOutputStream stream) throws IOException {
+    Binary binary = value.getBinary();
+    stream.writeInt(binary.getLength());
+    stream.write(binary.getValues());
+    return Math.addExact(Integer.BYTES, binary.getLength());
+  }
+
+  @Override
+  public int serializeValue(Object value, ByteBuffer buffer) {
+    return ReadWriteIOUtils.write((Binary) value, buffer);
+  }
+
+  @Override
+  public int serializeValue(Object value, DataOutputStream stream) throws IOException {
+    return ReadWriteIOUtils.write((Binary) value, stream);
+  }
+
+  @Override
+  public TSEncoding getDefaultEncoding(TSFileConfig config) {
+    return TSEncoding.valueOf(config.getTextEncoding());
+  }
+
+  @Override
+  public CompressionType getDefaultCompressor(TSFileConfig config) {
+    return config.getTextCompressor();
+  }
+
+  @Override
+  public int getOneItemMaxSize(int valveLength) {
+    return Integer.BYTES + TSFileConfig.BYTE_SIZE_PER_CHAR * valveLength;
+  }
+
+  @Override
+  public Statistics<?> createStatistics() {
+    return new BinaryStatistics();
+  }
+
+  @Override
+  public long getStatisticsInstanceSize() {
+    return BinaryStatistics.INSTANCE_SIZE;
+  }
+
+  @Override
+  public void update(Statistics<?> stats, long timestamp, TsPrimitiveType value) {
+    stats.update(timestamp, value.getBinary());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, BatchData batchData) {
+    stats.update(batchData.currentTime(), batchData.getBinary());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, TsBlock block, int columnIndex, int rowIndex) {
+    stats.update(block.getTimeByIndex(rowIndex), block.getColumn(columnIndex).getBinary(rowIndex));
+  }
+
+  @Override
+  public Object getCurrentValue(BatchData batchData) {
+    return batchData.getBinary();
+  }
+
+  @Override
+  public String toString(Field field) {
+    return field.getBinaryV().toString();
+  }
+
+  @Override
+  public Object getValue(Field field) {
+    return field.getBinaryV();
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Field to) {
+    to.setBinaryV(from.getBinary());
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Column to, int index) {
+    to.getBinaries()[index] = from.getBinary();
+  }
+
+  @Override
+  public void setTo(Object value, Column to, int startIndex, int endIndex) {
+    Arrays.fill(
+        to.getBinaries(), startIndex, endIndex, value == null ? null : toBinaryValue(value));
+  }
+
+  @Override
+  public void setTo(Field from, Field to) {
+    to.setBinaryV(from.getBinaryV());
+  }
+
+  @Override
+  public void setTo(BatchData from, Field to) {
+    to.setBinaryV(from.getBinary());
+  }
+
+  @Override
+  public void setTo(BatchData from, Column to, int index) {
+    to.getBinaries()[index] = from.getBinary();
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Column to, int toIndex) {
+    to.getBinaries()[toIndex] = from.getBinary(fromIndex);
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Object toArray, int toIndex) {
+    ((Binary[]) toArray)[toIndex] = from.getBinary(fromIndex);
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, Field field) {
+    record.addPoint(columnName, field.getStringValue());
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, ResultSet resultSet) {
+    record.addPoint(columnName, resultSet.getString(columnName));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, String value) {
+    return new StringDataPoint(measurementId, new Binary(value, TSFileConfig.STRING_CHARSET));
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, Object value, boolean isNull) {
+    writer.write(time, isNull ? Binary.EMPTY_VALUE : (Binary) value, isNull);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, TsPrimitiveType value) {
+    writer.write(time, value != null ? value.getBinary() : Binary.EMPTY_VALUE, value == null);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Object array, int rowIndex, boolean isNull) {
+    writer.write(time, ((Binary[]) array)[rowIndex], isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Column column, int rowIndex, boolean isNull) {
+    writer.write(time, isNull ? null : column.getBinary(rowIndex), isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long[] times, Column column, int batchSize, int arrayOffset) {
+    writer.write(times, column.getBinaries(), column.isNull(), batchSize, arrayOffset);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object column, int rowIndex) {
+    writer.write(time, ((Binary[]) column)[rowIndex]);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, TsPrimitiveType value) {
+    writer.write(time, value.getBinary());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, BatchData data) {
+    writer.write(time, data.getBinary());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object value) {
+    writer.write(time, (Binary) value);
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType() {
+    return new TsPrimitiveType.TsBinary();
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType(Object value) {
+    return new TsPrimitiveType.TsBinary((Binary) value);
+  }
+
+  @Override
+  public TsPrimitiveType getValueAsTsPrimitiveType(Object array, int rowIndex) {
+    return new TsPrimitiveType.TsBinary(((Binary[]) array)[rowIndex]);
+  }
+
   @Override
   public Binary getBinary(Column c, int position) {
     return c.getBinary(position);
   }
 
+  @Override
+  public void write(ColumnBuilder builder, TsPrimitiveType value) {
+    builder.writeBinary(value.getBinary());
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, byte[] bytes, int offset) {
+    int length = BytesUtils.bytesToInt(bytes, offset);
+    builder.writeBinary(
+        new Binary(
+            Arrays.copyOfRange(bytes, offset + Integer.BYTES, offset + Integer.BYTES + length)));
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, Column column, int index) {
+    builder.writeBinary(column.getBinary(index));
+  }
+
+  @Override
+  public void write(TsPrimitiveType from, Object toArray, int index) {
+    ((Binary[]) toArray)[index] = from.getBinary();
+  }
+
+  @Override
+  public void write(BatchData from, Object toArray, int index) {
+    ((Binary[]) toArray)[index] = from.getBinary();
+  }
+
   @Override
   public void writeBinary(ColumnBuilder builder, Binary value) {
     builder.writeBinary(value);
   }
 
+  @Override
+  public void addValue(int rowIndex, Object value, Object array) {
+    ((Binary[]) array)[rowIndex] = toBinaryValue(value);
+  }
+
+  @Override
+  public void copyArrayElement(Object source, int sourceIndex, Object target, int targetIndex) {
+    ((Binary[]) target)[targetIndex] = ((Binary[]) source)[sourceIndex];
+  }
+
+  @Override
+  public Object arrayCopyOf(Object array, int newLength) {
+    return Arrays.copyOf((Binary[]) array, newLength);
+  }
+
+  protected Binary toBinaryValue(Object value) {
+    if (value != null && !(value instanceof Binary) && !(value instanceof String)) {
+      throw new IllegalArgumentException(
+          Messages.format(
+              "error.write.tablet_expected_type",
+              "Binary or String",
+              getDisplayName(),
+              value.getClass().getName()));
+    }
+    if (value instanceof Binary) {
+      return (Binary) value;
+    }
+    return value != null
+        ? new Binary(((String) value).getBytes(TSFileConfig.STRING_CHARSET))
+        : Binary.EMPTY_VALUE;
+  }
+
+  @Override
+  public Object createArray(int capacity) {
+    return new Binary[capacity];
+  }
+
+  @Override
+  public long estimateArraySize(int size) {
+    return RamUsageEstimator.sizeOfObjectArray(size);
+  }
+
+  @Override
+  public long estimateValueSize() {
+    return RamUsageEstimator.NUM_BYTES_OBJECT_REF;
+  }
+
+  @Override
+  public int serializedSize(Object array, int rowSize) {
+    return serializedSizeOfBinaryValues(array, rowSize);
+  }
+
+  @Override
+  public int serializedSize(Object array, int startRow, int endRow) {
+    return serializedSizeOfBinaryValues(array, startRow, endRow);
+  }
+
+  @Override
+  public void serializeArray(Object array, int rowSize, DataOutputStream stream)
+      throws IOException {
+    serializeBinaryValues(array, rowSize, stream);
+  }
+
+  @Override
+  public void serializeArray(Object array, int length, ByteBuffer buffer) {
+    serializeBinaryValues(array, length, buffer);
+  }
+
+  @Override
+  public Object deserializeArray(ByteBuffer buffer, int rowSize) {
+    return deserializeBinaryValues(buffer, rowSize);
+  }
+
+  @Override
+  public Object deserializeArray(DataInputStream stream, int rowSize) throws IOException {
+    return deserializeBinaryValues(stream, rowSize);
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, ByteBuffer buffer) {
+    array[index] = ReadWriteIOUtils.readBinary(buffer);
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, InputStream stream) throws IOException {
+    array[index] = ReadWriteIOUtils.readBinary(stream);
+  }
+
+  @Override
+  public Object deserializeColumn(ByteBuffer buffer, int rowSize, boolean[] nullIndicators) {
+    Binary[] values = deserializeBinaryValues(buffer, rowSize, nullIndicators);
+    return new BinaryColumn(0, rowSize, nullIndicators, values);
+  }
+
+  @Override
+  public boolean arrayEquals(Object left, Object right, int rowSize) {
+    return binaryArrayEquals(left, right, rowSize);
+  }
+
+  @Override
+  public long estimateArraySize(Object array) {
+    return RamUsageEstimator.sizeOf((Binary[]) array);
+  }
+
+  @Override
+  public Column createColumnWithMaxPosition(int positionCount) {
+    return new BinaryColumn(
+        positionCount, Optional.of(new boolean[positionCount]), new Binary[positionCount]);
+  }
+
+  @Override
+  public Column createColumnWithZeroPosition(int positionCount) {
+    return new BinaryColumn(positionCount);
+  }
+
+  @Override
+  public Column createNullColumn(int positionCount) {
+    return new RunLengthEncodedColumn(BinaryColumnBuilder.NULL_VALUE_BLOCK, positionCount);
+  }
+
   @Override
   public ColumnBuilder createColumnBuilder(int expectedEntries) {
     return new BinaryColumnBuilder(null, expectedEntries);
   }
 
+  @Override
+  public ColumnBuilder createColumnBuilder(
+      ColumnBuilderStatus columnBuilderStatus, int expectedEntries) {
+    return new BinaryColumnBuilder(columnBuilderStatus, expectedEntries);
+  }
+
   @Override
   public boolean isComparable() {
     return true;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BinaryType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BinaryType.java
index 68c874998..ece9ba52b 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BinaryType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BinaryType.java
@@ -19,11 +19,22 @@
 
 package org.apache.tsfile.read.common.type;
 
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.utils.Binary;
+
 public class BinaryType extends AbstractVarcharType {
   public static final BinaryType TEXT = new BinaryType();
 
   private BinaryType() {}
 
+  @Override
+  public Field getField(Object value) {
+    Field field = new Field(TSDataType.TEXT);
+    field.setBinaryV((Binary) value);
+    return field;
+  }
+
   @Override
   public TypeEnum getTypeEnum() {
     return TypeEnum.TEXT;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BlobType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BlobType.java
index d02ca7168..7cd6b53f2 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BlobType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BlobType.java
@@ -21,11 +21,41 @@ package org.apache.tsfile.read.common.type;
 
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.block.column.ColumnBuilderStatus;
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.file.metadata.statistics.BlobStatistics;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.read.common.block.column.BinaryColumn;
 import org.apache.tsfile.read.common.block.column.BinaryColumnBuilder;
+import org.apache.tsfile.read.common.block.column.RunLengthEncodedColumn;
+import org.apache.tsfile.read.query.dataset.ResultSet;
 import org.apache.tsfile.utils.Binary;
+import org.apache.tsfile.utils.BytesUtils;
+import org.apache.tsfile.utils.RamUsageEstimator;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.apache.tsfile.utils.TsPrimitiveType;
+import org.apache.tsfile.write.chunk.ChunkWriterImpl;
+import org.apache.tsfile.write.chunk.ValueChunkWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.StringDataPoint;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 public class BlobType extends AbstractType {
 
@@ -33,21 +63,430 @@ public class BlobType extends AbstractType {
 
   private BlobType() {}
 
+  @Override
+  public void toBytes(TsPrimitiveType value, byte[] valueBytes, int offset) {
+    binaryToBytes(value, valueBytes, offset);
+  }
+
+  @Override
+  public int calcTypeSize(TsPrimitiveType value) {
+    return binaryTypeSize(value);
+  }
+
+  @Override
+  public int calcTypeSize(Object value) {
+    return binaryTypeSize(value);
+  }
+
+  @Override
+  public void init(BatchData batchData) {
+    batchData.initBinaryValues();
+  }
+
+  @Override
+  public void put(BatchData batchData, long timestamp, Object value) {
+    batchData.putBinary(timestamp, (Binary) value);
+  }
+
+  @Override
+  public int serialize(BatchData batchData, DataOutputStream outputStream, boolean isDesc)
+      throws IOException {
+    int size = 0;
+    for (int i = 0; i < batchData.length(); i++) {
+      int index = isDesc ? batchData.length() - 1 - i : i;
+      outputStream.writeLong(batchData.getTimeByIndex(index));
+      Binary binary = batchData.getBinaryByIndex(index);
+      outputStream.writeInt(binary.getLength());
+      outputStream.write(binary.getValues());
+      size = Math.addExact(size, Long.BYTES + Integer.BYTES);
+      size = Math.addExact(size, binary.getLength());
+    }
+    return size;
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer, BatchData batchData, int length) {
+    for (int i = 0; i < length; i++) {
+      batchData.putBinary(buffer.getLong(), ReadWriteIOUtils.readBinary(buffer));
+    }
+  }
+
+  @Override
+  public TsPrimitiveType deserialize(ByteBuffer buffer) {
+    return new TsPrimitiveType.TsBinary(ReadWriteIOUtils.readBinary(buffer));
+  }
+
+  @Override
+  public int serialize(TsPrimitiveType value, DataOutputStream stream) throws IOException {
+    Binary binary = value.getBinary();
+    stream.writeInt(binary.getLength());
+    stream.write(binary.getValues());
+    return Math.addExact(Integer.BYTES, binary.getLength());
+  }
+
+  @Override
+  public int serializeValue(Object value, ByteBuffer buffer) {
+    return ReadWriteIOUtils.write((Binary) value, buffer);
+  }
+
+  @Override
+  public int serializeValue(Object value, DataOutputStream stream) throws IOException {
+    return ReadWriteIOUtils.write((Binary) value, stream);
+  }
+
+  @Override
+  public TSEncoding getDefaultEncoding(TSFileConfig config) {
+    return TSEncoding.valueOf(config.getTextEncoding());
+  }
+
+  @Override
+  public CompressionType getDefaultCompressor(TSFileConfig config) {
+    return config.getTextCompressor();
+  }
+
+  @Override
+  public int getOneItemMaxSize(int valveLength) {
+    return Integer.BYTES + TSFileConfig.BYTE_SIZE_PER_CHAR * valveLength;
+  }
+
+  @Override
+  public Statistics<?> createStatistics() {
+    return new BlobStatistics();
+  }
+
+  @Override
+  public long getStatisticsInstanceSize() {
+    return BlobStatistics.INSTANCE_SIZE;
+  }
+
+  @Override
+  public void update(Statistics<?> stats, long timestamp, TsPrimitiveType value) {
+    stats.update(timestamp, value.getBinary());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, BatchData batchData) {
+    stats.update(batchData.currentTime(), batchData.getBinary());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, TsBlock block, int columnIndex, int rowIndex) {
+    stats.update(block.getTimeByIndex(rowIndex), block.getColumn(columnIndex).getBinary(rowIndex));
+  }
+
+  @Override
+  public Object getCurrentValue(BatchData batchData) {
+    return batchData.getBinary();
+  }
+
+  @Override
+  public String toString(Field field) {
+    return BytesUtils.parseBlobByteArrayToString(field.getBinaryV().getValues());
+  }
+
+  @Override
+  public Object getValue(Field field) {
+    return field.getBinaryV();
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Field to) {
+    to.setBinaryV(from.getBinary());
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Column to, int index) {
+    to.getBinaries()[index] = from.getBinary();
+  }
+
+  @Override
+  public void setTo(Object value, Column to, int startIndex, int endIndex) {
+    if (value == null) {
+      Arrays.fill(to.getBinaries(), startIndex, endIndex, null);
+      return;
+    }
+    Binary[] values = new Binary[1];
+    addValue(0, value, values);
+    Arrays.fill(to.getBinaries(), startIndex, endIndex, values[0]);
+  }
+
+  @Override
+  public void setTo(Field from, Field to) {
+    to.setBinaryV(from.getBinaryV());
+  }
+
+  @Override
+  public void setTo(BatchData from, Field to) {
+    to.setBinaryV(from.getBinary());
+  }
+
+  @Override
+  public void setTo(BatchData from, Column to, int index) {
+    to.getBinaries()[index] = from.getBinary();
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Column to, int toIndex) {
+    to.getBinaries()[toIndex] = from.getBinary(fromIndex);
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Object toArray, int toIndex) {
+    ((Binary[]) toArray)[toIndex] = from.getBinary(fromIndex);
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, Field field) {
+    record.addPoint(columnName, field.getBinaryV().getValues());
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, ResultSet resultSet) {
+    record.addPoint(columnName, resultSet.getBinary(columnName));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, String value) {
+    return new StringDataPoint(measurementId, new Binary(value, TSFileConfig.STRING_CHARSET));
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, Object value, boolean isNull) {
+    writer.write(time, isNull ? Binary.EMPTY_VALUE : (Binary) value, isNull);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, TsPrimitiveType value) {
+    writer.write(time, value != null ? value.getBinary() : Binary.EMPTY_VALUE, value == null);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Object array, int rowIndex, boolean isNull) {
+    writer.write(time, ((Binary[]) array)[rowIndex], isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Column column, int rowIndex, boolean isNull) {
+    writer.write(time, isNull ? null : column.getBinary(rowIndex), isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long[] times, Column column, int batchSize, int arrayOffset) {
+    writer.write(times, column.getBinaries(), column.isNull(), batchSize, arrayOffset);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object column, int rowIndex) {
+    writer.write(time, ((Binary[]) column)[rowIndex]);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, TsPrimitiveType value) {
+    writer.write(time, value.getBinary());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, BatchData data) {
+    writer.write(time, data.getBinary());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object value) {
+    writer.write(time, (Binary) value);
+  }
+
+  @Override
+  public Field getField(Object value) {
+    Field field = new Field(TSDataType.BLOB);
+    field.setBinaryV((Binary) value);
+    return field;
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType() {
+    return new TsPrimitiveType.TsBinary();
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType(Object value) {
+    return new TsPrimitiveType.TsBinary((Binary) value);
+  }
+
+  @Override
+  public TsPrimitiveType getValueAsTsPrimitiveType(Object array, int rowIndex) {
+    return new TsPrimitiveType.TsBinary(((Binary[]) array)[rowIndex]);
+  }
+
   @Override
   public Binary getBinary(Column c, int position) {
     return c.getBinary(position);
   }
 
+  @Override
+  public void write(ColumnBuilder builder, TsPrimitiveType value) {
+    builder.writeBinary(value.getBinary());
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, byte[] bytes, int offset) {
+    int length = BytesUtils.bytesToInt(bytes, offset);
+    builder.writeBinary(
+        new Binary(
+            Arrays.copyOfRange(bytes, offset + Integer.BYTES, offset + Integer.BYTES + length)));
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, Column column, int index) {
+    builder.writeBinary(column.getBinary(index));
+  }
+
+  @Override
+  public void write(TsPrimitiveType from, Object toArray, int index) {
+    ((Binary[]) toArray)[index] = from.getBinary();
+  }
+
+  @Override
+  public void write(BatchData from, Object toArray, int index) {
+    ((Binary[]) toArray)[index] = from.getBinary();
+  }
+
   @Override
   public void writeBinary(ColumnBuilder builder, Binary value) {
     builder.writeBinary(value);
   }
 
+  @Override
+  public void addValue(int rowIndex, Object value, Object array) {
+    if (value != null && !(value instanceof Binary) && !(value instanceof String)) {
+      throw new IllegalArgumentException(
+          Messages.format(
+              "error.write.tablet_expected_type",
+              "Binary or String",
+              getDisplayName(),
+              value.getClass().getName()));
+    }
+    if (value instanceof Binary) {
+      ((Binary[]) array)[rowIndex] = (Binary) value;
+    } else {
+      ((Binary[]) array)[rowIndex] =
+          value != null
+              ? new Binary(((String) value).getBytes(TSFileConfig.STRING_CHARSET))
+              : Binary.EMPTY_VALUE;
+    }
+  }
+
+  @Override
+  public void copyArrayElement(Object source, int sourceIndex, Object target, int targetIndex) {
+    ((Binary[]) target)[targetIndex] = ((Binary[]) source)[sourceIndex];
+  }
+
+  @Override
+  public Object arrayCopyOf(Object array, int newLength) {
+    return Arrays.copyOf((Binary[]) array, newLength);
+  }
+
+  @Override
+  public Object createArray(int capacity) {
+    return new Binary[capacity];
+  }
+
+  @Override
+  public long estimateArraySize(int size) {
+    return RamUsageEstimator.sizeOfObjectArray(size);
+  }
+
+  @Override
+  public long estimateValueSize() {
+    return RamUsageEstimator.NUM_BYTES_OBJECT_REF;
+  }
+
+  @Override
+  public int serializedSize(Object array, int rowSize) {
+    return serializedSizeOfBinaryValues(array, rowSize);
+  }
+
+  @Override
+  public int serializedSize(Object array, int startRow, int endRow) {
+    return serializedSizeOfBinaryValues(array, startRow, endRow);
+  }
+
+  @Override
+  public void serializeArray(Object array, int rowSize, DataOutputStream stream)
+      throws IOException {
+    serializeBinaryValues(array, rowSize, stream);
+  }
+
+  @Override
+  public void serializeArray(Object array, int length, ByteBuffer buffer) {
+    serializeBinaryValues(array, length, buffer);
+  }
+
+  @Override
+  public Object deserializeArray(ByteBuffer buffer, int rowSize) {
+    return deserializeBinaryValues(buffer, rowSize);
+  }
+
+  @Override
+  public Object deserializeArray(DataInputStream stream, int rowSize) throws IOException {
+    return deserializeBinaryValues(stream, rowSize);
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, ByteBuffer buffer) {
+    array[index] = ReadWriteIOUtils.readBinary(buffer);
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, InputStream stream) throws IOException {
+    array[index] = ReadWriteIOUtils.readBinary(stream);
+  }
+
+  @Override
+  public Object deserializeColumn(ByteBuffer buffer, int rowSize, boolean[] nullIndicators) {
+    Binary[] binaries = deserializeBinaryValues(buffer, rowSize, nullIndicators);
+    return new BinaryColumn(0, rowSize, nullIndicators, binaries);
+  }
+
+  @Override
+  public boolean arrayEquals(Object left, Object right, int rowSize) {
+    return binaryArrayEquals(left, right, rowSize);
+  }
+
+  @Override
+  public long estimateArraySize(Object array) {
+    return RamUsageEstimator.sizeOf((Binary[]) array);
+  }
+
+  @Override
+  public Column createColumnWithMaxPosition(int positionCount) {
+    return new BinaryColumn(
+        positionCount, Optional.of(new boolean[positionCount]), new Binary[positionCount]);
+  }
+
+  @Override
+  public Column createColumnWithZeroPosition(int positionCount) {
+    return new BinaryColumn(positionCount);
+  }
+
+  @Override
+  public Column createNullColumn(int positionCount) {
+    return new RunLengthEncodedColumn(BinaryColumnBuilder.NULL_VALUE_BLOCK, positionCount);
+  }
+
   @Override
   public ColumnBuilder createColumnBuilder(int expectedEntries) {
     return new BinaryColumnBuilder(null, expectedEntries);
   }
 
+  @Override
+  public ColumnBuilder createColumnBuilder(
+      ColumnBuilderStatus columnBuilderStatus, int expectedEntries) {
+    return new BinaryColumnBuilder(columnBuilderStatus, expectedEntries);
+  }
+
   @Override
   public TypeEnum getTypeEnum() {
     return TypeEnum.BLOB;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BooleanType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BooleanType.java
index e00d7ecb8..a890303e1 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BooleanType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/BooleanType.java
@@ -21,10 +21,42 @@ package org.apache.tsfile.read.common.type;
 
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.block.column.ColumnBuilderStatus;
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.encoding.decoder.Decoder;
+import org.apache.tsfile.encoding.decoder.IntRleDecoder;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.file.metadata.statistics.BooleanStatistics;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.read.common.block.column.BooleanColumn;
 import org.apache.tsfile.read.common.block.column.BooleanColumnBuilder;
+import org.apache.tsfile.read.common.block.column.ColumnEncoder;
+import org.apache.tsfile.read.common.block.column.RunLengthEncodedColumn;
+import org.apache.tsfile.read.query.dataset.ResultSet;
+import org.apache.tsfile.utils.BytesUtils;
+import org.apache.tsfile.utils.RamUsageEstimator;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.apache.tsfile.utils.TsPrimitiveType;
+import org.apache.tsfile.write.chunk.ChunkWriterImpl;
+import org.apache.tsfile.write.chunk.ValueChunkWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.BooleanDataPoint;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 public class BooleanType extends AbstractType {
 
@@ -32,21 +64,445 @@ public class BooleanType extends AbstractType {
 
   private BooleanType() {}
 
+  @Override
+  public void toBytes(TsPrimitiveType value, byte[] valueBytes, int offset) {
+    BytesUtils.boolToBytes(value.getBoolean(), valueBytes, offset);
+  }
+
+  @Override
+  public int calcTypeSize(TsPrimitiveType value) {
+    return Byte.BYTES;
+  }
+
+  @Override
+  public int calcTypeSize(Object value) {
+    return Byte.BYTES;
+  }
+
+  @Override
+  public void init(BatchData batchData) {
+    batchData.initBooleanValues();
+  }
+
+  @Override
+  public void put(BatchData batchData, long timestamp, Object value) {
+    batchData.putBoolean(timestamp, (boolean) value);
+  }
+
+  @Override
+  public int serialize(BatchData batchData, DataOutputStream outputStream, boolean isDesc)
+      throws IOException {
+    for (int i = 0; i < batchData.length(); i++) {
+      int index = isDesc ? batchData.length() - 1 - i : i;
+      outputStream.writeLong(batchData.getTimeByIndex(index));
+      outputStream.writeBoolean(batchData.getBooleanByIndex(index));
+    }
+    return Math.multiplyExact(Long.BYTES + Byte.BYTES, batchData.length());
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer, BatchData batchData, int length) {
+    for (int i = 0; i < length; i++) {
+      batchData.putBoolean(buffer.getLong(), ReadWriteIOUtils.readBoolean(buffer));
+    }
+  }
+
+  @Override
+  public TsPrimitiveType deserialize(ByteBuffer buffer) {
+    return new TsPrimitiveType.TsBoolean(ReadWriteIOUtils.readBoolean(buffer));
+  }
+
+  @Override
+  public int serialize(TsPrimitiveType value, DataOutputStream stream) throws IOException {
+    stream.writeBoolean(value.getBoolean());
+    return Byte.BYTES;
+  }
+
+  @Override
+  public int serializeValue(Object value, ByteBuffer buffer) {
+    buffer.put((boolean) value ? (byte) 1 : (byte) 0);
+    return Byte.BYTES;
+  }
+
+  @Override
+  public int serializeValue(Object value, DataOutputStream stream) throws IOException {
+    stream.writeBoolean((boolean) value);
+    return Byte.BYTES;
+  }
+
+  @Override
+  public TSEncoding getDefaultEncoding(TSFileConfig config) {
+    return TSEncoding.valueOf(config.getBooleanEncoding());
+  }
+
+  @Override
+  public CompressionType getDefaultCompressor(TSFileConfig config) {
+    return config.getBooleanCompressor();
+  }
+
+  @Override
+  public Decoder getDecoder(TSEncoding encoding) {
+    return switch (encoding) {
+      case PLAIN, DICTIONARY -> super.getDecoder(encoding);
+      case RLE -> new IntRleDecoder();
+      default -> throw decoderNotFound(encoding);
+    };
+  }
+
+  @Override
+  public int getOneItemMaxSize(int valveLength) {
+    return Byte.BYTES;
+  }
+
+  @Override
+  public Statistics<?> createStatistics() {
+    return new BooleanStatistics();
+  }
+
+  @Override
+  public long getStatisticsInstanceSize() {
+    return BooleanStatistics.INSTANCE_SIZE;
+  }
+
+  @Override
+  public void update(Statistics<?> stats, long timestamp, TsPrimitiveType value) {
+    stats.update(timestamp, value.getBoolean());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, BatchData batchData) {
+    stats.update(batchData.currentTime(), batchData.getBoolean());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, TsBlock block, int columnIndex, int rowIndex) {
+    stats.update(block.getTimeByIndex(rowIndex), block.getColumn(columnIndex).getBoolean(rowIndex));
+  }
+
+  @Override
+  public Object getCurrentValue(BatchData batchData) {
+    return batchData.getBoolean();
+  }
+
+  @Override
+  public String toString(Field field) {
+    return String.valueOf(field.getBoolV());
+  }
+
+  @Override
+  public Object getValue(Field field) {
+    return field.getBoolV();
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Field to) {
+    to.setBoolV(from.getBoolean());
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Column to, int index) {
+    to.getBooleans()[index] = from.getBoolean();
+  }
+
+  @Override
+  public void setTo(Object value, Column to, int startIndex, int endIndex) {
+    Arrays.fill(to.getBooleans(), startIndex, endIndex, (boolean) value);
+  }
+
+  @Override
+  public void setTo(Field from, Field to) {
+    to.setBoolV(from.getBoolV());
+  }
+
+  @Override
+  public void setTo(BatchData from, Field to) {
+    to.setBoolV(from.getBoolean());
+  }
+
+  @Override
+  public void setTo(BatchData from, Column to, int index) {
+    to.getBooleans()[index] = from.getBoolean();
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Column to, int toIndex) {
+    to.getBooleans()[toIndex] = from.getBoolean(fromIndex);
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Object toArray, int toIndex) {
+    ((boolean[]) toArray)[toIndex] = from.getBoolean(fromIndex);
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, Field field) {
+    record.addPoint(columnName, field.getBoolV());
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, ResultSet resultSet) {
+    record.addPoint(columnName, resultSet.getBoolean(columnName));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, String value) {
+    return new BooleanDataPoint(measurementId, Boolean.parseBoolean(value));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, long value) {
+    return new BooleanDataPoint(measurementId, true);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, Object value, boolean isNull) {
+    writer.write(time, !isNull && (boolean) value, isNull);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, TsPrimitiveType value) {
+    writer.write(time, value != null && value.getBoolean(), value == null);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Object array, int rowIndex, boolean isNull) {
+    writer.write(time, ((boolean[]) array)[rowIndex], isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Column column, int rowIndex, boolean isNull) {
+    writer.write(time, isNull ? false : column.getBoolean(rowIndex), isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long[] times, Column column, int batchSize, int arrayOffset) {
+    writer.write(times, column.getBooleans(), column.isNull(), batchSize, arrayOffset);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object column, int rowIndex) {
+    writer.write(time, ((boolean[]) column)[rowIndex]);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, TsPrimitiveType value) {
+    writer.write(time, value.getBoolean());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, BatchData data) {
+    writer.write(time, data.getBoolean());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object value) {
+    writer.write(time, (boolean) value);
+  }
+
+  @Override
+  public Field getField(Object value) {
+    Field field = new Field(TSDataType.BOOLEAN);
+    field.setBoolV((boolean) value);
+    return field;
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType() {
+    return new TsPrimitiveType.TsBoolean();
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType(Object value) {
+    return new TsPrimitiveType.TsBoolean((boolean) value);
+  }
+
+  @Override
+  public TsPrimitiveType getValueAsTsPrimitiveType(Object array, int rowIndex) {
+    return new TsPrimitiveType.TsBoolean(((boolean[]) array)[rowIndex]);
+  }
+
   @Override
   public boolean getBoolean(Column c, int position) {
     return c.getBoolean(position);
   }
 
+  @Override
+  public void write(ColumnBuilder builder, TsPrimitiveType value) {
+    builder.writeBoolean(value.getBoolean());
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, byte[] bytes, int offset) {
+    builder.writeBoolean(BytesUtils.bytesToBool(bytes, offset));
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, Column column, int index) {
+    builder.writeBoolean(column.getBoolean(index));
+  }
+
+  @Override
+  public void write(TsPrimitiveType from, Object toArray, int index) {
+    ((boolean[]) toArray)[index] = from.getBoolean();
+  }
+
+  @Override
+  public void write(BatchData from, Object toArray, int index) {
+    ((boolean[]) toArray)[index] = from.getBoolean();
+  }
+
   @Override
   public void writeBoolean(ColumnBuilder builder, boolean value) {
     builder.writeBoolean(value);
   }
 
+  @Override
+  public void addValue(int rowIndex, Object value, Object array) {
+    checkValueType(value, Boolean.class, "Boolean");
+    ((boolean[]) array)[rowIndex] = value != null && (boolean) value;
+  }
+
+  @Override
+  public void copyArrayElement(Object source, int sourceIndex, Object target, int targetIndex) {
+    ((boolean[]) target)[targetIndex] = ((boolean[]) source)[sourceIndex];
+  }
+
+  @Override
+  public Object arrayCopyOf(Object array, int newLength) {
+    return Arrays.copyOf((boolean[]) array, newLength);
+  }
+
+  @Override
+  public Object createArray(int capacity) {
+    return new boolean[capacity];
+  }
+
+  @Override
+  public long estimateArraySize(int size) {
+    return RamUsageEstimator.sizeOfBooleanArray(size);
+  }
+
+  @Override
+  public long estimateValueSize() {
+    return Byte.BYTES;
+  }
+
+  @Override
+  public int serializedSize(Object array, int rowSize) {
+    return rowSize;
+  }
+
+  @Override
+  public void serializeArray(Object array, int rowSize, DataOutputStream stream)
+      throws IOException {
+    boolean[] values = (boolean[]) array;
+    for (int i = 0; i < rowSize; i++) {
+      ReadWriteIOUtils.write(BytesUtils.boolToByte(values[i]), stream);
+    }
+  }
+
+  @Override
+  public void serializeArray(Object array, int length, ByteBuffer buffer) {
+    boolean[] values = (boolean[]) array;
+    for (int i = 0; i < length; i++) {
+      buffer.put(BytesUtils.boolToByte(values[i]));
+    }
+  }
+
+  @Override
+  public Object deserializeArray(ByteBuffer buffer, int rowSize) {
+    boolean[] values = new boolean[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(buffer));
+    }
+    return values;
+  }
+
+  @Override
+  public Object deserializeArray(DataInputStream stream, int rowSize) throws IOException {
+    boolean[] values = new boolean[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(stream));
+    }
+    return values;
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, ByteBuffer buffer) {
+    array[index] = BytesUtils.byteToBool(ReadWriteIOUtils.readByte(buffer));
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, InputStream stream) throws IOException {
+    array[index] = ReadWriteIOUtils.readBoolean(stream);
+  }
+
+  @Override
+  public Object deserializeColumn(ByteBuffer buffer, int rowSize, boolean[] nullIndicators) {
+    if (nullIndicators == null) {
+      boolean[] values = ColumnEncoder.deserializeBooleanArray(buffer, rowSize);
+      return new BooleanColumn(rowSize, Optional.empty(), values);
+    }
+
+    int nonNullCount = 0;
+    for (boolean isNull : nullIndicators) {
+      if (!isNull) {
+        nonNullCount++;
+      }
+    }
+
+    boolean[] nonNullValues = ColumnEncoder.deserializeBooleanArray(buffer, nonNullCount);
+    boolean[] values = new boolean[rowSize];
+    int nonNullIndex = 0;
+    for (int i = 0; i < rowSize; i++) {
+      if (!nullIndicators[i]) {
+        values[i] = nonNullValues[nonNullIndex++];
+      }
+    }
+    return new BooleanColumn(rowSize, Optional.of(nullIndicators), values);
+  }
+
+  @Override
+  public boolean arrayEquals(Object left, Object right, int rowSize) {
+    return hasEnoughLength(left, right, rowSize)
+        && Arrays.equals((boolean[]) left, 0, rowSize, (boolean[]) right, 0, rowSize);
+  }
+
+  @Override
+  public long estimateArraySize(Object array) {
+    return RamUsageEstimator.sizeOf((boolean[]) array);
+  }
+
+  @Override
+  public Column createColumnWithMaxPosition(int positionCount) {
+    return new BooleanColumn(
+        positionCount, Optional.of(new boolean[positionCount]), new boolean[positionCount]);
+  }
+
+  @Override
+  public Column createColumnWithZeroPosition(int positionCount) {
+    return new BooleanColumn(positionCount);
+  }
+
+  @Override
+  public Column createNullColumn(int positionCount) {
+    return new RunLengthEncodedColumn(BooleanColumnBuilder.NULL_VALUE_BLOCK, positionCount);
+  }
+
   @Override
   public ColumnBuilder createColumnBuilder(int expectedEntries) {
     return new BooleanColumnBuilder(null, expectedEntries);
   }
 
+  @Override
+  public ColumnBuilder createColumnBuilder(
+      ColumnBuilderStatus columnBuilderStatus, int expectedEntries) {
+    return new BooleanColumnBuilder(columnBuilderStatus, expectedEntries);
+  }
+
   @Override
   public TypeEnum getTypeEnum() {
     return TypeEnum.BOOLEAN;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/DateType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/DateType.java
index 88d17e242..e5d262938 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/DateType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/DateType.java
@@ -19,12 +19,288 @@
 
 package org.apache.tsfile.read.common.type;
 
+import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.block.column.ColumnBuilderStatus;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.statistics.DateStatistics;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.block.column.IntColumn;
+import org.apache.tsfile.read.common.block.column.IntColumnBuilder;
+import org.apache.tsfile.utils.DateUtils;
+import org.apache.tsfile.utils.RamUsageEstimator;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.apache.tsfile.utils.TsPrimitiveType;
+import org.apache.tsfile.utils.TsPrimitiveType.TsInt;
+import org.apache.tsfile.write.chunk.ChunkWriterImpl;
+import org.apache.tsfile.write.chunk.ValueChunkWriter;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.IntDataPoint;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.Optional;
+
 public class DateType extends AbstractIntType {
 
   public static final DateType DATE = new DateType();
+  private static final LocalDate EMPTY_DATE = LocalDate.of(1000, 1, 1);
 
   private DateType() {}
 
+  @Override
+  public TsPrimitiveType getTsPrimitiveType() {
+    return new TsInt(TSDataType.DATE);
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType(Object value) {
+    return new TsInt((int) value, TSDataType.DATE);
+  }
+
+  @Override
+  public TsPrimitiveType deserialize(ByteBuffer buffer) {
+    return new TsInt(ReadWriteIOUtils.readInt(buffer), TSDataType.DATE);
+  }
+
+  @Override
+  public TsPrimitiveType getValueAsTsPrimitiveType(Object array, int rowIndex) {
+    return new TsInt(getDateInt(array, rowIndex), TSDataType.DATE);
+  }
+
+  @Override
+  public void write(TsPrimitiveType from, Object toArray, int index) {
+    if (toArray instanceof int[]) {
+      super.write(from, toArray, index);
+      return;
+    }
+    ((LocalDate[]) toArray)[index] = DateUtils.parseIntToLocalDate(from.getInt());
+  }
+
+  @Override
+  public void write(BatchData from, Object toArray, int index) {
+    if (toArray instanceof int[]) {
+      super.write(from, toArray, index);
+      return;
+    }
+    ((LocalDate[]) toArray)[index] = DateUtils.parseIntToLocalDate(from.getInt());
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, String value) {
+    return new IntDataPoint(measurementId, DateUtils.parseDateExpressionToInt(value));
+  }
+
+  @Override
+  public Statistics<?> createStatistics() {
+    return new DateStatistics();
+  }
+
+  @Override
+  public long getStatisticsInstanceSize() {
+    return DateStatistics.INSTANCE_SIZE;
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Object array, int rowIndex, boolean isNull) {
+    if (array instanceof int[]) {
+      super.write(writer, time, array, rowIndex, isNull);
+      return;
+    }
+    writer.write(
+        time,
+        isNull ? 0 : DateUtils.parseDateExpressionToInt(((LocalDate[]) array)[rowIndex]),
+        isNull);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object column, int rowIndex) {
+    if (column instanceof int[]) {
+      super.write(writer, time, column, rowIndex);
+      return;
+    }
+    writer.write(time, DateUtils.parseDateExpressionToInt(((LocalDate[]) column)[rowIndex]));
+  }
+
+  @Override
+  public void addValue(int rowIndex, Object value, Object array) {
+    if (array instanceof int[]) {
+      if (value instanceof Integer) {
+        ((int[]) array)[rowIndex] = (int) value;
+      } else {
+        checkValueType(value, LocalDate.class, "LocalDate");
+        ((int[]) array)[rowIndex] =
+            value != null
+                ? DateUtils.parseDateExpressionToInt((LocalDate) value)
+                : DateUtils.EMPTY_DATE_INT;
+      }
+      return;
+    }
+    checkValueType(value, LocalDate.class, "LocalDate");
+    ((LocalDate[]) array)[rowIndex] = value != null ? (LocalDate) value : EMPTY_DATE;
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Object toArray, int toIndex) {
+    if (toArray instanceof int[]) {
+      super.setTo(from, fromIndex, toArray, toIndex);
+      return;
+    }
+    ((LocalDate[]) toArray)[toIndex] = DateUtils.parseIntToLocalDate(from.getInt(fromIndex));
+  }
+
+  @Override
+  public void copyArrayElement(Object source, int sourceIndex, Object target, int targetIndex) {
+    if (target instanceof int[]) {
+      ((int[]) target)[targetIndex] = getDateInt(source, sourceIndex);
+      return;
+    }
+    ((LocalDate[]) target)[targetIndex] =
+        source instanceof int[]
+            ? DateUtils.parseIntToLocalDate(((int[]) source)[sourceIndex])
+            : ((LocalDate[]) source)[sourceIndex];
+  }
+
+  @Override
+  public Object arrayCopyOf(Object array, int newLength) {
+    return array instanceof int[]
+        ? Arrays.copyOf((int[]) array, newLength)
+        : Arrays.copyOf((LocalDate[]) array, newLength);
+  }
+
+  @Override
+  public Object createArray(int capacity) {
+    return new LocalDate[capacity];
+  }
+
+  @Override
+  public long estimateArraySize(int size) {
+    return RamUsageEstimator.sizeOfObjectArray(size);
+  }
+
+  @Override
+  public Object getValue(Field field) {
+    return field.getDateV();
+  }
+
+  @Override
+  public Field getField(Object value) {
+    Field field = new Field(TSDataType.DATE);
+    field.setIntV((int) value);
+    return field;
+  }
+
+  @Override
+  public void serializeArray(Object array, int rowSize, DataOutputStream stream)
+      throws IOException {
+    if (array instanceof int[]) {
+      for (int i = 0; i < rowSize; i++) {
+        ReadWriteIOUtils.write(((int[]) array)[i], stream);
+      }
+      return;
+    }
+    LocalDate[] values = (LocalDate[]) array;
+    for (int i = 0; i < rowSize; i++) {
+      ReadWriteIOUtils.write(
+          values[i] == null
+              ? DateUtils.EMPTY_DATE_INT
+              : DateUtils.parseDateExpressionToInt(values[i]),
+          stream);
+    }
+  }
+
+  @Override
+  public void serializeArray(Object array, int length, ByteBuffer buffer) {
+    if (array instanceof int[]) {
+      super.serializeArray(array, length, buffer);
+      return;
+    }
+    LocalDate[] values = (LocalDate[]) array;
+    for (int i = 0; i < length; i++) {
+      buffer.putInt(
+          values[i] == null
+              ? DateUtils.EMPTY_DATE_INT
+              : DateUtils.parseDateExpressionToInt(values[i]));
+    }
+  }
+
+  @Override
+  public Object deserializeArray(ByteBuffer buffer, int rowSize) {
+    LocalDate[] values = new LocalDate[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = DateUtils.parseIntToLocalDate(ReadWriteIOUtils.readInt(buffer));
+    }
+    return values;
+  }
+
+  @Override
+  public Object deserializeArray(DataInputStream stream, int rowSize) throws IOException {
+    LocalDate[] values = new LocalDate[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = DateUtils.parseIntToLocalDate(ReadWriteIOUtils.readInt(stream));
+    }
+    return values;
+  }
+
+  @Override
+  public Object deserializeColumn(ByteBuffer buffer, int rowSize, boolean[] nullIndicators) {
+    return ((IntColumn) super.deserializeColumn(buffer, rowSize, nullIndicators))
+        .modifyDataType(TSDataType.DATE);
+  }
+
+  @Override
+  public boolean arrayEquals(Object left, Object right, int rowSize) {
+    if (!hasEnoughLength(left, right, rowSize)) {
+      return false;
+    }
+    if (left instanceof int[] && right instanceof int[]) {
+      return Arrays.equals((int[]) left, 0, rowSize, (int[]) right, 0, rowSize);
+    }
+    if (left instanceof LocalDate[] && right instanceof LocalDate[]) {
+      return Arrays.equals((LocalDate[]) left, 0, rowSize, (LocalDate[]) right, 0, rowSize);
+    }
+    for (int i = 0; i < rowSize; i++) {
+      if (getDateInt(left, i) != getDateInt(right, i)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @Override
+  public long estimateArraySize(Object array) {
+    return array instanceof int[]
+        ? RamUsageEstimator.sizeOf((int[]) array)
+        : RamUsageEstimator.sizeOf((LocalDate[]) array);
+  }
+
+  @Override
+  public Column createColumnWithMaxPosition(int positionCount) {
+    return new IntColumn(
+        positionCount,
+        Optional.of(new boolean[positionCount]),
+        new int[positionCount],
+        TSDataType.DATE);
+  }
+
+  @Override
+  public Column createColumnWithZeroPosition(int positionCount) {
+    return new IntColumn(positionCount, TSDataType.DATE);
+  }
+
+  @Override
+  public ColumnBuilder createColumnBuilder(
+      ColumnBuilderStatus columnBuilderStatus, int expectedEntries) {
+    return new IntColumnBuilder(columnBuilderStatus, expectedEntries, TSDataType.DATE);
+  }
+
   @Override
   public TypeEnum getTypeEnum() {
     return TypeEnum.DATE;
@@ -35,6 +311,14 @@ public class DateType extends AbstractIntType {
     return "DATE";
   }
 
+  private int getDateInt(Object array, int index) {
+    if (array instanceof int[]) {
+      return ((int[]) array)[index];
+    }
+    LocalDate value = ((LocalDate[]) array)[index];
+    return value != null ? DateUtils.parseDateExpressionToInt(value) : DateUtils.EMPTY_DATE_INT;
+  }
+
   public static DateType getInstance() {
     return DATE;
   }
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/DoubleType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/DoubleType.java
index 6e325c066..1fe10746b 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/DoubleType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/DoubleType.java
@@ -21,10 +21,47 @@ package org.apache.tsfile.read.common.type;
 
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.block.column.ColumnBuilderStatus;
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.encoding.decoder.CamelDecoder;
+import org.apache.tsfile.encoding.decoder.Decoder;
+import org.apache.tsfile.encoding.decoder.DoublePrecisionChimpDecoder;
+import org.apache.tsfile.encoding.decoder.DoublePrecisionDecoderV1;
+import org.apache.tsfile.encoding.decoder.DoublePrecisionDecoderV2;
+import org.apache.tsfile.encoding.decoder.DoubleRLBEDecoder;
+import org.apache.tsfile.encoding.decoder.DoubleSprintzDecoder;
+import org.apache.tsfile.encoding.decoder.FloatDecoder;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.file.metadata.statistics.DoubleStatistics;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.read.common.block.column.DoubleColumn;
 import org.apache.tsfile.read.common.block.column.DoubleColumnBuilder;
+import org.apache.tsfile.read.common.block.column.RunLengthEncodedColumn;
+import org.apache.tsfile.read.query.dataset.ResultSet;
+import org.apache.tsfile.utils.BytesUtils;
+import org.apache.tsfile.utils.RamUsageEstimator;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.apache.tsfile.utils.TsPrimitiveType;
+import org.apache.tsfile.write.chunk.ChunkWriterImpl;
+import org.apache.tsfile.write.chunk.ValueChunkWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.DoubleDataPoint;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 public class DoubleType extends AbstractType {
 
@@ -32,6 +69,272 @@ public class DoubleType extends AbstractType {
 
   private DoubleType() {}
 
+  @Override
+  public void toBytes(TsPrimitiveType value, byte[] valueBytes, int offset) {
+    BytesUtils.doubleToBytes(value.getDouble(), valueBytes, offset);
+  }
+
+  @Override
+  public int calcTypeSize(TsPrimitiveType value) {
+    return Double.BYTES;
+  }
+
+  @Override
+  public int calcTypeSize(Object value) {
+    return Double.BYTES;
+  }
+
+  @Override
+  public void init(BatchData batchData) {
+    batchData.initDoubleValues();
+  }
+
+  @Override
+  public void put(BatchData batchData, long timestamp, Object value) {
+    batchData.putDouble(timestamp, (double) value);
+  }
+
+  @Override
+  public int serialize(BatchData batchData, DataOutputStream outputStream, boolean isDesc)
+      throws IOException {
+    for (int i = 0; i < batchData.length(); i++) {
+      int index = isDesc ? batchData.length() - 1 - i : i;
+      outputStream.writeLong(batchData.getTimeByIndex(index));
+      outputStream.writeDouble(batchData.getDoubleByIndex(index));
+    }
+    return Math.multiplyExact(Long.BYTES + Double.BYTES, batchData.length());
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer, BatchData batchData, int length) {
+    for (int i = 0; i < length; i++) {
+      batchData.putDouble(buffer.getLong(), buffer.getDouble());
+    }
+  }
+
+  @Override
+  public TsPrimitiveType deserialize(ByteBuffer buffer) {
+    return new TsPrimitiveType.TsDouble(ReadWriteIOUtils.readDouble(buffer));
+  }
+
+  @Override
+  public int serialize(TsPrimitiveType value, DataOutputStream stream) throws IOException {
+    stream.writeDouble(value.getDouble());
+    return Double.BYTES;
+  }
+
+  @Override
+  public int serializeValue(Object value, ByteBuffer buffer) {
+    buffer.putDouble((double) value);
+    return Double.BYTES;
+  }
+
+  @Override
+  public int serializeValue(Object value, DataOutputStream stream) throws IOException {
+    stream.writeDouble((double) value);
+    return Double.BYTES;
+  }
+
+  @Override
+  public TSEncoding getDefaultEncoding(TSFileConfig config) {
+    return TSEncoding.valueOf(config.getDoubleEncoding());
+  }
+
+  @Override
+  public CompressionType getDefaultCompressor(TSFileConfig config) {
+    return config.getDoubleCompressor();
+  }
+
+  @Override
+  public Decoder getDecoder(TSEncoding encoding) {
+    return switch (encoding) {
+      case PLAIN, DICTIONARY -> super.getDecoder(encoding);
+      case RLE, TS_2DIFF -> new FloatDecoder(encoding, TSDataType.DOUBLE);
+      case GORILLA_V1 -> new DoublePrecisionDecoderV1();
+      case GORILLA -> new DoublePrecisionDecoderV2();
+      case CHIMP -> new DoublePrecisionChimpDecoder();
+      case SPRINTZ -> new DoubleSprintzDecoder();
+      case RLBE -> new DoubleRLBEDecoder();
+      case CAMEL -> new CamelDecoder();
+      default -> throw decoderNotFound(encoding);
+    };
+  }
+
+  @Override
+  public int getOneItemMaxSize(int valveLength) {
+    return Double.BYTES;
+  }
+
+  @Override
+  public Statistics<?> createStatistics() {
+    return new DoubleStatistics();
+  }
+
+  @Override
+  public long getStatisticsInstanceSize() {
+    return DoubleStatistics.INSTANCE_SIZE;
+  }
+
+  @Override
+  public void update(Statistics<?> stats, long timestamp, TsPrimitiveType value) {
+    stats.update(timestamp, value.getDouble());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, BatchData batchData) {
+    stats.update(batchData.currentTime(), batchData.getDouble());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, TsBlock block, int columnIndex, int rowIndex) {
+    stats.update(block.getTimeByIndex(rowIndex), block.getColumn(columnIndex).getDouble(rowIndex));
+  }
+
+  @Override
+  public Object getCurrentValue(BatchData batchData) {
+    return batchData.getDouble();
+  }
+
+  @Override
+  public String toString(Field field) {
+    return String.valueOf(field.getDoubleV());
+  }
+
+  @Override
+  public Object getValue(Field field) {
+    return field.getDoubleV();
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Field to) {
+    to.setDoubleV(from.getDouble());
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Column to, int index) {
+    to.getDoubles()[index] = from.getDouble();
+  }
+
+  @Override
+  public void setTo(Object value, Column to, int startIndex, int endIndex) {
+    Arrays.fill(to.getDoubles(), startIndex, endIndex, (double) value);
+  }
+
+  @Override
+  public void setTo(Field from, Field to) {
+    to.setDoubleV(from.getDoubleV());
+  }
+
+  @Override
+  public void setTo(BatchData from, Field to) {
+    to.setDoubleV(from.getDouble());
+  }
+
+  @Override
+  public void setTo(BatchData from, Column to, int index) {
+    to.getDoubles()[index] = from.getDouble();
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Column to, int toIndex) {
+    to.getDoubles()[toIndex] = from.getDouble(fromIndex);
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Object toArray, int toIndex) {
+    ((double[]) toArray)[toIndex] = from.getDouble(fromIndex);
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, Field field) {
+    record.addPoint(columnName, field.getDoubleV());
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, ResultSet resultSet) {
+    record.addPoint(columnName, resultSet.getDouble(columnName));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, String value) {
+    return new DoubleDataPoint(measurementId, Double.parseDouble(value));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, long value) {
+    return new DoubleDataPoint(measurementId, (double) value);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, Object value, boolean isNull) {
+    writer.write(time, isNull ? 0.0D : (double) value, isNull);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, TsPrimitiveType value) {
+    writer.write(time, value != null ? value.getDouble() : Double.MAX_VALUE, value == null);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Object array, int rowIndex, boolean isNull) {
+    writer.write(time, ((double[]) array)[rowIndex], isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Column column, int rowIndex, boolean isNull) {
+    writer.write(time, isNull ? 0 : column.getDouble(rowIndex), isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long[] times, Column column, int batchSize, int arrayOffset) {
+    writer.write(times, column.getDoubles(), column.isNull(), batchSize, arrayOffset);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object column, int rowIndex) {
+    writer.write(time, ((double[]) column)[rowIndex]);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, TsPrimitiveType value) {
+    writer.write(time, value.getDouble());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, BatchData data) {
+    writer.write(time, data.getDouble());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object value) {
+    writer.write(time, (double) value);
+  }
+
+  @Override
+  public Field getField(Object value) {
+    Field field = new Field(TSDataType.DOUBLE);
+    field.setDoubleV((double) value);
+    return field;
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType() {
+    return new TsPrimitiveType.TsDouble();
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType(Object value) {
+    return new TsPrimitiveType.TsDouble((double) value);
+  }
+
+  @Override
+  public TsPrimitiveType getValueAsTsPrimitiveType(Object array, int rowIndex) {
+    return new TsPrimitiveType.TsDouble(((double[]) array)[rowIndex]);
+  }
+
   @Override
   public int getInt(Column c, int position) {
     return (int) c.getDouble(position);
@@ -52,6 +355,31 @@ public class DoubleType extends AbstractType {
     return c.getDouble(position);
   }
 
+  @Override
+  public void write(ColumnBuilder builder, TsPrimitiveType value) {
+    builder.writeDouble(value.getDouble());
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, byte[] bytes, int offset) {
+    builder.writeDouble(BytesUtils.bytesToDouble(bytes, offset));
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, Column column, int index) {
+    builder.writeDouble(column.getDouble(index));
+  }
+
+  @Override
+  public void write(TsPrimitiveType from, Object toArray, int index) {
+    ((double[]) toArray)[index] = from.getDouble();
+  }
+
+  @Override
+  public void write(BatchData from, Object toArray, int index) {
+    ((double[]) toArray)[index] = from.getDouble();
+  }
+
   @Override
   public void writeInt(ColumnBuilder builder, int value) {
     builder.writeDouble(value);
@@ -72,11 +400,142 @@ public class DoubleType extends AbstractType {
     builder.writeDouble(value);
   }
 
+  @Override
+  public void addValue(int rowIndex, Object value, Object array) {
+    checkValueType(value, Double.class, "Double");
+    ((double[]) array)[rowIndex] = value != null ? (double) value : Double.MIN_VALUE;
+  }
+
+  @Override
+  public void copyArrayElement(Object source, int sourceIndex, Object target, int targetIndex) {
+    ((double[]) target)[targetIndex] = ((double[]) source)[sourceIndex];
+  }
+
+  @Override
+  public Object arrayCopyOf(Object array, int newLength) {
+    return Arrays.copyOf((double[]) array, newLength);
+  }
+
+  @Override
+  public Object createArray(int capacity) {
+    return new double[capacity];
+  }
+
+  @Override
+  public long estimateArraySize(int size) {
+    return RamUsageEstimator.sizeOfDoubleArray(size);
+  }
+
+  @Override
+  public long estimateValueSize() {
+    return Double.BYTES;
+  }
+
+  @Override
+  public int serializedSize(Object array, int rowSize) {
+    return Math.multiplyExact(Double.BYTES, rowSize);
+  }
+
+  @Override
+  public void serializeArray(Object array, int rowSize, DataOutputStream stream)
+      throws IOException {
+    double[] values = (double[]) array;
+    for (int i = 0; i < rowSize; i++) {
+      ReadWriteIOUtils.write(values[i], stream);
+    }
+  }
+
+  @Override
+  public void serializeArray(Object array, int length, ByteBuffer buffer) {
+    double[] values = (double[]) array;
+    for (int i = 0; i < length; i++) {
+      buffer.putDouble(values[i]);
+    }
+  }
+
+  @Override
+  public Object deserializeArray(ByteBuffer buffer, int rowSize) {
+    double[] values = new double[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = ReadWriteIOUtils.readDouble(buffer);
+    }
+    return values;
+  }
+
+  @Override
+  public Object deserializeArray(DataInputStream stream, int rowSize) throws IOException {
+    double[] values = new double[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = ReadWriteIOUtils.readDouble(stream);
+    }
+    return values;
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, ByteBuffer buffer) {
+    array[index] = ReadWriteIOUtils.readDouble(buffer);
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, InputStream stream) throws IOException {
+    array[index] = ReadWriteIOUtils.readDouble(stream);
+  }
+
+  @Override
+  public Object deserializeColumn(ByteBuffer buffer, int rowSize, boolean[] nullIndicators) {
+    double[] values = new double[rowSize];
+    if (nullIndicators == null) {
+      for (int i = 0; i < rowSize; i++) {
+        values[i] = Double.longBitsToDouble(buffer.getLong());
+      }
+    } else {
+      for (int i = 0; i < rowSize; i++) {
+        if (!nullIndicators[i]) {
+          values[i] = Double.longBitsToDouble(buffer.getLong());
+        }
+      }
+    }
+    return new DoubleColumn(rowSize, Optional.ofNullable(nullIndicators), values);
+  }
+
+  @Override
+  public boolean arrayEquals(Object left, Object right, int rowSize) {
+    return hasEnoughLength(left, right, rowSize)
+        && Arrays.equals((double[]) left, 0, rowSize, (double[]) right, 0, rowSize);
+  }
+
+  @Override
+  public long estimateArraySize(Object array) {
+    return RamUsageEstimator.sizeOf((double[]) array);
+  }
+
+  @Override
+  public Column createColumnWithMaxPosition(int positionCount) {
+    return new DoubleColumn(
+        positionCount, Optional.of(new boolean[positionCount]), new double[positionCount]);
+  }
+
+  @Override
+  public Column createColumnWithZeroPosition(int positionCount) {
+    return new DoubleColumn(positionCount);
+  }
+
+  @Override
+  public Column createNullColumn(int positionCount) {
+    return new RunLengthEncodedColumn(DoubleColumnBuilder.NULL_VALUE_BLOCK, positionCount);
+  }
+
   @Override
   public ColumnBuilder createColumnBuilder(int expectedEntries) {
     return new DoubleColumnBuilder(null, expectedEntries);
   }
 
+  @Override
+  public ColumnBuilder createColumnBuilder(
+      ColumnBuilderStatus columnBuilderStatus, int expectedEntries) {
+    return new DoubleColumnBuilder(columnBuilderStatus, expectedEntries);
+  }
+
   @Override
   public TypeEnum getTypeEnum() {
     return TypeEnum.DOUBLE;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/FloatType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/FloatType.java
index 6417f0f52..14458dde9 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/FloatType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/FloatType.java
@@ -21,10 +21,46 @@ package org.apache.tsfile.read.common.type;
 
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.block.column.ColumnBuilderStatus;
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.encoding.decoder.Decoder;
+import org.apache.tsfile.encoding.decoder.FloatDecoder;
+import org.apache.tsfile.encoding.decoder.FloatRLBEDecoder;
+import org.apache.tsfile.encoding.decoder.FloatSprintzDecoder;
+import org.apache.tsfile.encoding.decoder.SinglePrecisionChimpDecoder;
+import org.apache.tsfile.encoding.decoder.SinglePrecisionDecoderV1;
+import org.apache.tsfile.encoding.decoder.SinglePrecisionDecoderV2;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.file.metadata.statistics.FloatStatistics;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.read.common.block.column.FloatColumn;
 import org.apache.tsfile.read.common.block.column.FloatColumnBuilder;
+import org.apache.tsfile.read.common.block.column.RunLengthEncodedColumn;
+import org.apache.tsfile.read.query.dataset.ResultSet;
+import org.apache.tsfile.utils.BytesUtils;
+import org.apache.tsfile.utils.RamUsageEstimator;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.apache.tsfile.utils.TsPrimitiveType;
+import org.apache.tsfile.write.chunk.ChunkWriterImpl;
+import org.apache.tsfile.write.chunk.ValueChunkWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.FloatDataPoint;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 public class FloatType extends AbstractType {
 
@@ -32,6 +68,271 @@ public class FloatType extends AbstractType {
 
   private FloatType() {}
 
+  @Override
+  public void toBytes(TsPrimitiveType value, byte[] valueBytes, int offset) {
+    BytesUtils.floatToBytes(value.getFloat(), valueBytes, offset);
+  }
+
+  @Override
+  public int calcTypeSize(TsPrimitiveType value) {
+    return Float.BYTES;
+  }
+
+  @Override
+  public int calcTypeSize(Object value) {
+    return Float.BYTES;
+  }
+
+  @Override
+  public void init(BatchData batchData) {
+    batchData.initFloatValues();
+  }
+
+  @Override
+  public void put(BatchData batchData, long timestamp, Object value) {
+    batchData.putFloat(timestamp, (float) value);
+  }
+
+  @Override
+  public int serialize(BatchData batchData, DataOutputStream outputStream, boolean isDesc)
+      throws IOException {
+    for (int i = 0; i < batchData.length(); i++) {
+      int index = isDesc ? batchData.length() - 1 - i : i;
+      outputStream.writeLong(batchData.getTimeByIndex(index));
+      outputStream.writeFloat(batchData.getFloatByIndex(index));
+    }
+    return Math.multiplyExact(Long.BYTES + Float.BYTES, batchData.length());
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer, BatchData batchData, int length) {
+    for (int i = 0; i < length; i++) {
+      batchData.putFloat(buffer.getLong(), buffer.getFloat());
+    }
+  }
+
+  @Override
+  public TsPrimitiveType deserialize(ByteBuffer buffer) {
+    return new TsPrimitiveType.TsFloat(ReadWriteIOUtils.readFloat(buffer));
+  }
+
+  @Override
+  public int serialize(TsPrimitiveType value, DataOutputStream stream) throws IOException {
+    stream.writeFloat(value.getFloat());
+    return Float.BYTES;
+  }
+
+  @Override
+  public int serializeValue(Object value, ByteBuffer buffer) {
+    buffer.putFloat((float) value);
+    return Float.BYTES;
+  }
+
+  @Override
+  public int serializeValue(Object value, DataOutputStream stream) throws IOException {
+    stream.writeFloat((float) value);
+    return Float.BYTES;
+  }
+
+  @Override
+  public TSEncoding getDefaultEncoding(TSFileConfig config) {
+    return TSEncoding.valueOf(config.getFloatEncoding());
+  }
+
+  @Override
+  public CompressionType getDefaultCompressor(TSFileConfig config) {
+    return config.getFloatCompressor();
+  }
+
+  @Override
+  public Decoder getDecoder(TSEncoding encoding) {
+    return switch (encoding) {
+      case PLAIN, DICTIONARY -> super.getDecoder(encoding);
+      case RLE, TS_2DIFF -> new FloatDecoder(encoding, TSDataType.FLOAT);
+      case GORILLA_V1 -> new SinglePrecisionDecoderV1();
+      case GORILLA -> new SinglePrecisionDecoderV2();
+      case CHIMP -> new SinglePrecisionChimpDecoder();
+      case SPRINTZ -> new FloatSprintzDecoder();
+      case RLBE -> new FloatRLBEDecoder();
+      default -> throw decoderNotFound(encoding);
+    };
+  }
+
+  @Override
+  public int getOneItemMaxSize(int valveLength) {
+    return Float.BYTES;
+  }
+
+  @Override
+  public Statistics<?> createStatistics() {
+    return new FloatStatistics();
+  }
+
+  @Override
+  public long getStatisticsInstanceSize() {
+    return FloatStatistics.INSTANCE_SIZE;
+  }
+
+  @Override
+  public void update(Statistics<?> stats, long timestamp, TsPrimitiveType value) {
+    stats.update(timestamp, value.getFloat());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, BatchData batchData) {
+    stats.update(batchData.currentTime(), batchData.getFloat());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, TsBlock block, int columnIndex, int rowIndex) {
+    stats.update(block.getTimeByIndex(rowIndex), block.getColumn(columnIndex).getFloat(rowIndex));
+  }
+
+  @Override
+  public Object getCurrentValue(BatchData batchData) {
+    return batchData.getFloat();
+  }
+
+  @Override
+  public String toString(Field field) {
+    return String.valueOf(field.getFloatV());
+  }
+
+  @Override
+  public Object getValue(Field field) {
+    return field.getFloatV();
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Field to) {
+    to.setFloatV(from.getFloat());
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Column to, int index) {
+    to.getFloats()[index] = from.getFloat();
+  }
+
+  @Override
+  public void setTo(Object value, Column to, int startIndex, int endIndex) {
+    Arrays.fill(to.getFloats(), startIndex, endIndex, (float) value);
+  }
+
+  @Override
+  public void setTo(Field from, Field to) {
+    to.setFloatV(from.getFloatV());
+  }
+
+  @Override
+  public void setTo(BatchData from, Field to) {
+    to.setFloatV(from.getFloat());
+  }
+
+  @Override
+  public void setTo(BatchData from, Column to, int index) {
+    to.getFloats()[index] = from.getFloat();
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Column to, int toIndex) {
+    to.getFloats()[toIndex] = from.getFloat(fromIndex);
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Object toArray, int toIndex) {
+    ((float[]) toArray)[toIndex] = from.getFloat(fromIndex);
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, Field field) {
+    record.addPoint(columnName, field.getFloatV());
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, ResultSet resultSet) {
+    record.addPoint(columnName, resultSet.getFloat(columnName));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, String value) {
+    return new FloatDataPoint(measurementId, Float.parseFloat(value));
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, long value) {
+    return new FloatDataPoint(measurementId, (float) value);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, Object value, boolean isNull) {
+    writer.write(time, isNull ? 0.0F : (float) value, isNull);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, TsPrimitiveType value) {
+    writer.write(time, value != null ? value.getFloat() : Float.MAX_VALUE, value == null);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Object array, int rowIndex, boolean isNull) {
+    writer.write(time, ((float[]) array)[rowIndex], isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Column column, int rowIndex, boolean isNull) {
+    writer.write(time, isNull ? 0 : column.getFloat(rowIndex), isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long[] times, Column column, int batchSize, int arrayOffset) {
+    writer.write(times, column.getFloats(), column.isNull(), batchSize, arrayOffset);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object column, int rowIndex) {
+    writer.write(time, ((float[]) column)[rowIndex]);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, TsPrimitiveType value) {
+    writer.write(time, value.getFloat());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, BatchData data) {
+    writer.write(time, data.getFloat());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object value) {
+    writer.write(time, (float) value);
+  }
+
+  @Override
+  public Field getField(Object value) {
+    Field field = new Field(TSDataType.FLOAT);
+    field.setFloatV((float) value);
+    return field;
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType() {
+    return new TsPrimitiveType.TsFloat();
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType(Object value) {
+    return new TsPrimitiveType.TsFloat((float) value);
+  }
+
+  @Override
+  public TsPrimitiveType getValueAsTsPrimitiveType(Object array, int rowIndex) {
+    return new TsPrimitiveType.TsFloat(((float[]) array)[rowIndex]);
+  }
+
   @Override
   public int getInt(Column c, int position) {
     return (int) c.getFloat(position);
@@ -52,6 +353,31 @@ public class FloatType extends AbstractType {
     return c.getFloat(position);
   }
 
+  @Override
+  public void write(ColumnBuilder builder, TsPrimitiveType value) {
+    builder.writeFloat(value.getFloat());
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, byte[] bytes, int offset) {
+    builder.writeFloat(BytesUtils.bytesToFloat(bytes, offset));
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, Column column, int index) {
+    builder.writeFloat(column.getFloat(index));
+  }
+
+  @Override
+  public void write(TsPrimitiveType from, Object toArray, int index) {
+    ((float[]) toArray)[index] = from.getFloat();
+  }
+
+  @Override
+  public void write(BatchData from, Object toArray, int index) {
+    ((float[]) toArray)[index] = from.getFloat();
+  }
+
   @Override
   public void writeInt(ColumnBuilder builder, int value) {
     builder.writeFloat(value);
@@ -72,11 +398,142 @@ public class FloatType extends AbstractType {
     builder.writeFloat((float) value);
   }
 
+  @Override
+  public void addValue(int rowIndex, Object value, Object array) {
+    checkValueType(value, Float.class, "Float");
+    ((float[]) array)[rowIndex] = value != null ? (float) value : Float.MIN_VALUE;
+  }
+
+  @Override
+  public void copyArrayElement(Object source, int sourceIndex, Object target, int targetIndex) {
+    ((float[]) target)[targetIndex] = ((float[]) source)[sourceIndex];
+  }
+
+  @Override
+  public Object arrayCopyOf(Object array, int newLength) {
+    return Arrays.copyOf((float[]) array, newLength);
+  }
+
+  @Override
+  public Object createArray(int capacity) {
+    return new float[capacity];
+  }
+
+  @Override
+  public long estimateArraySize(int size) {
+    return RamUsageEstimator.sizeOfFloatArray(size);
+  }
+
+  @Override
+  public long estimateValueSize() {
+    return Float.BYTES;
+  }
+
+  @Override
+  public int serializedSize(Object array, int rowSize) {
+    return Math.multiplyExact(Float.BYTES, rowSize);
+  }
+
+  @Override
+  public void serializeArray(Object array, int rowSize, DataOutputStream stream)
+      throws IOException {
+    float[] values = (float[]) array;
+    for (int i = 0; i < rowSize; i++) {
+      ReadWriteIOUtils.write(values[i], stream);
+    }
+  }
+
+  @Override
+  public void serializeArray(Object array, int length, ByteBuffer buffer) {
+    float[] values = (float[]) array;
+    for (int i = 0; i < length; i++) {
+      buffer.putFloat(values[i]);
+    }
+  }
+
+  @Override
+  public Object deserializeArray(ByteBuffer buffer, int rowSize) {
+    float[] values = new float[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = ReadWriteIOUtils.readFloat(buffer);
+    }
+    return values;
+  }
+
+  @Override
+  public Object deserializeArray(DataInputStream stream, int rowSize) throws IOException {
+    float[] values = new float[rowSize];
+    for (int i = 0; i < rowSize; i++) {
+      values[i] = ReadWriteIOUtils.readFloat(stream);
+    }
+    return values;
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, ByteBuffer buffer) {
+    array[index] = ReadWriteIOUtils.readFloat(buffer);
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, InputStream stream) throws IOException {
+    array[index] = ReadWriteIOUtils.readFloat(stream);
+  }
+
+  @Override
+  public Object deserializeColumn(ByteBuffer buffer, int rowSize, boolean[] nullIndicators) {
+    float[] values = new float[rowSize];
+    if (nullIndicators == null) {
+      for (int i = 0; i < rowSize; i++) {
+        values[i] = Float.intBitsToFloat(buffer.getInt());
+      }
+    } else {
+      for (int i = 0; i < rowSize; i++) {
+        if (!nullIndicators[i]) {
+          values[i] = Float.intBitsToFloat(buffer.getInt());
+        }
+      }
+    }
+    return new FloatColumn(rowSize, Optional.ofNullable(nullIndicators), values);
+  }
+
+  @Override
+  public boolean arrayEquals(Object left, Object right, int rowSize) {
+    return hasEnoughLength(left, right, rowSize)
+        && Arrays.equals((float[]) left, 0, rowSize, (float[]) right, 0, rowSize);
+  }
+
+  @Override
+  public long estimateArraySize(Object array) {
+    return RamUsageEstimator.sizeOf((float[]) array);
+  }
+
+  @Override
+  public Column createColumnWithMaxPosition(int positionCount) {
+    return new FloatColumn(
+        positionCount, Optional.of(new boolean[positionCount]), new float[positionCount]);
+  }
+
+  @Override
+  public Column createColumnWithZeroPosition(int positionCount) {
+    return new FloatColumn(positionCount);
+  }
+
+  @Override
+  public Column createNullColumn(int positionCount) {
+    return new RunLengthEncodedColumn(FloatColumnBuilder.NULL_VALUE_BLOCK, positionCount);
+  }
+
   @Override
   public ColumnBuilder createColumnBuilder(int expectedEntries) {
     return new FloatColumnBuilder(null, expectedEntries);
   }
 
+  @Override
+  public ColumnBuilder createColumnBuilder(
+      ColumnBuilderStatus columnBuilderStatus, int expectedEntries) {
+    return new FloatColumnBuilder(columnBuilderStatus, expectedEntries);
+  }
+
   @Override
   public TypeEnum getTypeEnum() {
     return TypeEnum.FLOAT;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/IntType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/IntType.java
index e4d36c2a3..32e958193 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/IntType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/IntType.java
@@ -19,12 +19,22 @@
 
 package org.apache.tsfile.read.common.type;
 
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.read.common.Field;
+
 public class IntType extends AbstractIntType {
 
   public static final IntType INT32 = new IntType();
 
   private IntType() {}
 
+  @Override
+  public Field getField(Object value) {
+    Field field = new Field(TSDataType.INT32);
+    field.setIntV((int) value);
+    return field;
+  }
+
   @Override
   public TypeEnum getTypeEnum() {
     return TypeEnum.INT32;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/LongType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/LongType.java
index a1ed2a1c9..77c3d0520 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/LongType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/LongType.java
@@ -19,12 +19,22 @@
 
 package org.apache.tsfile.read.common.type;
 
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.read.common.Field;
+
 public class LongType extends AbstractLongType {
 
   public static final LongType INT64 = new LongType();
 
   private LongType() {}
 
+  @Override
+  public Field getField(Object value) {
+    Field field = new Field(TSDataType.INT64);
+    field.setLongV((long) value);
+    return field;
+  }
+
   @Override
   public TypeEnum getTypeEnum() {
     return TypeEnum.INT64;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/ObjectType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/ObjectType.java
index b30b621f1..53fd7d9fe 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/ObjectType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/ObjectType.java
@@ -21,11 +21,44 @@ package org.apache.tsfile.read.common.type;
 
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.block.column.ColumnBuilderStatus;
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.file.metadata.statistics.ObjectStatistics;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.read.common.block.column.BinaryColumn;
 import org.apache.tsfile.read.common.block.column.BinaryColumnBuilder;
+import org.apache.tsfile.read.common.block.column.RunLengthEncodedColumn;
+import org.apache.tsfile.read.query.dataset.ResultSet;
 import org.apache.tsfile.utils.Binary;
+import org.apache.tsfile.utils.BytesUtils;
+import org.apache.tsfile.utils.RamUsageEstimator;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.apache.tsfile.utils.TsPrimitiveType;
+import org.apache.tsfile.utils.TsPrimitiveType.TsBinary;
+import org.apache.tsfile.write.chunk.ChunkWriterImpl;
+import org.apache.tsfile.write.chunk.ValueChunkWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.StringDataPoint;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
+
+import static org.apache.tsfile.utils.BytesUtils.parseObjectByteArrayToString;
 
 public class ObjectType extends AbstractType {
 
@@ -33,21 +66,418 @@ public class ObjectType extends AbstractType {
 
   private ObjectType() {}
 
+  @Override
+  public void toBytes(TsPrimitiveType value, byte[] valueBytes, int offset) {
+    binaryToBytes(value, valueBytes, offset);
+  }
+
+  @Override
+  public int calcTypeSize(TsPrimitiveType value) {
+    return binaryTypeSize(value);
+  }
+
+  @Override
+  public int calcTypeSize(Object value) {
+    return binaryTypeSize(value);
+  }
+
+  @Override
+  public void init(BatchData batchData) {
+    batchData.initBinaryValues();
+  }
+
+  @Override
+  public void put(BatchData batchData, long timestamp, Object value) {
+    batchData.putBinary(timestamp, (Binary) value);
+  }
+
+  @Override
+  public int serialize(BatchData batchData, DataOutputStream outputStream, boolean isDesc)
+      throws IOException {
+    int size = 0;
+    for (int i = 0; i < batchData.length(); i++) {
+      int index = isDesc ? batchData.length() - 1 - i : i;
+      outputStream.writeLong(batchData.getTimeByIndex(index));
+      Binary binary = batchData.getBinaryByIndex(index);
+      outputStream.writeInt(binary.getLength());
+      outputStream.write(binary.getValues());
+      size = Math.addExact(size, Long.BYTES + Integer.BYTES);
+      size = Math.addExact(size, binary.getLength());
+    }
+    return size;
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer, BatchData batchData, int length) {
+    for (int i = 0; i < length; i++) {
+      batchData.putBinary(buffer.getLong(), ReadWriteIOUtils.readBinary(buffer));
+    }
+  }
+
+  @Override
+  public TsPrimitiveType deserialize(ByteBuffer buffer) {
+    return new TsBinary(ReadWriteIOUtils.readBinary(buffer));
+  }
+
+  @Override
+  public int serialize(TsPrimitiveType value, DataOutputStream stream) throws IOException {
+    Binary binary = value.getBinary();
+    stream.writeInt(binary.getLength());
+    stream.write(binary.getValues());
+    return Math.addExact(Integer.BYTES, binary.getLength());
+  }
+
+  @Override
+  public int serializeValue(Object value, ByteBuffer buffer) {
+    return ReadWriteIOUtils.write((Binary) value, buffer);
+  }
+
+  @Override
+  public int serializeValue(Object value, DataOutputStream stream) throws IOException {
+    return ReadWriteIOUtils.write((Binary) value, stream);
+  }
+
+  @Override
+  public TSEncoding getDefaultEncoding(TSFileConfig config) {
+    return TSEncoding.valueOf(config.getTextEncoding());
+  }
+
+  @Override
+  public CompressionType getDefaultCompressor(TSFileConfig config) {
+    return config.getTextCompressor();
+  }
+
+  @Override
+  public int getOneItemMaxSize(int valveLength) {
+    return Integer.BYTES + TSFileConfig.BYTE_SIZE_PER_CHAR * valveLength;
+  }
+
+  @Override
+  public Statistics<?> createStatistics() {
+    return new ObjectStatistics();
+  }
+
+  @Override
+  public long getStatisticsInstanceSize() {
+    return ObjectStatistics.INSTANCE_SIZE;
+  }
+
+  @Override
+  public void update(Statistics<?> stats, long timestamp, TsPrimitiveType value) {
+    stats.update(timestamp, value.getBinary());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, BatchData batchData) {
+    stats.update(batchData.currentTime(), batchData.getBinary());
+  }
+
+  @Override
+  public void update(Statistics<?> stats, TsBlock block, int columnIndex, int rowIndex) {
+    stats.update(block.getTimeByIndex(rowIndex), block.getColumn(columnIndex).getBinary(rowIndex));
+  }
+
+  @Override
+  public Object getCurrentValue(BatchData batchData) {
+    return batchData.getBinary();
+  }
+
+  @Override
+  public String toString(Field field) {
+    return parseObjectByteArrayToString(field.getBinaryV().getValues());
+  }
+
+  @Override
+  public Object getValue(Field field) {
+    return field.getStringValue();
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Field to) {
+    to.setBinaryV(from.getBinary());
+  }
+
+  @Override
+  public void setTo(TsPrimitiveType from, Column to, int index) {
+    to.getBinaries()[index] = from.getBinary();
+  }
+
+  @Override
+  public void setTo(Object value, Column to, int startIndex, int endIndex) {
+    Arrays.fill(to.getBinaries(), startIndex, endIndex, value);
+  }
+
+  @Override
+  public void setTo(Field from, Field to) {
+    to.setBinaryV(from.getBinaryV());
+  }
+
+  @Override
+  public void setTo(BatchData from, Field to) {
+    to.setBinaryV(from.getBinary());
+  }
+
+  @Override
+  public void setTo(BatchData from, Column to, int index) {
+    to.getBinaries()[index] = from.getBinary();
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Column to, int toIndex) {
+    to.getBinaries()[toIndex] = from.getBinary(fromIndex);
+  }
+
+  @Override
+  public void setTo(Column from, int fromIndex, Object toArray, int toIndex) {
+    ((Binary[]) toArray)[toIndex] = from.getBinary(fromIndex);
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, ResultSet resultSet) {
+    record.addPoint(columnName, resultSet.getBinary(columnName));
+  }
+
+  @Override
+  public void addPoint(TSRecord record, String columnName, Field field) {
+    record.addPoint(columnName, field.getBinaryV().getValues());
+  }
+
+  @Override
+  public DataPoint getDataPoint(String measurementId, String value) {
+    return new StringDataPoint(measurementId, new Binary(value, TSFileConfig.STRING_CHARSET));
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, Object value, boolean isNull) {
+    writer.write(time, isNull ? Binary.EMPTY_VALUE : (Binary) value, isNull);
+  }
+
+  @Override
+  public void write(ValueChunkWriter writer, long time, TsPrimitiveType value) {
+    writer.write(time, value != null ? value.getBinary() : Binary.EMPTY_VALUE, value == null);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long time, Object array, int rowIndex, boolean isNull) {
+    writer.write(time, ((Binary[]) array)[rowIndex], isNull);
+  }
+
+  @Override
+  public void write(
+      ValueChunkWriter writer, long[] times, Column column, int batchSize, int arrayOffset) {
+    writer.write(times, column.getBinaries(), column.isNull(), batchSize, arrayOffset);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object column, int rowIndex) {
+    writer.write(time, ((Binary[]) column)[rowIndex]);
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, TsPrimitiveType value) {
+    writer.write(time, value.getBinary());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, BatchData data) {
+    writer.write(time, data.getBinary());
+  }
+
+  @Override
+  public void write(ChunkWriterImpl writer, long time, Object value) {
+    writer.write(time, (Binary) value);
+  }
+
+  @Override
+  public Field getField(Object value) {
+    Field field = new Field(TSDataType.OBJECT);
+    field.setBinaryV((Binary) value);
+    return field;
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType() {
+    return new TsBinary();
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType(Object value) {
+    return new TsBinary((Binary) value);
+  }
+
+  @Override
+  public TsPrimitiveType getValueAsTsPrimitiveType(Object array, int rowIndex) {
+    return new TsBinary(((Binary[]) array)[rowIndex]);
+  }
+
   @Override
   public Binary getBinary(Column c, int position) {
     return c.getBinary(position);
   }
 
+  @Override
+  public void write(ColumnBuilder builder, TsPrimitiveType value) {
+    builder.writeBinary(value.getBinary());
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, byte[] bytes, int offset) {
+    int length = BytesUtils.bytesToInt(bytes, offset);
+    builder.writeBinary(
+        new Binary(
+            Arrays.copyOfRange(bytes, offset + Integer.BYTES, offset + Integer.BYTES + length)));
+  }
+
+  @Override
+  public void write(ColumnBuilder builder, Column column, int index) {
+    builder.writeBinary(column.getBinary(index));
+  }
+
+  @Override
+  public void write(TsPrimitiveType from, Object toArray, int index) {
+    ((Binary[]) toArray)[index] = from.getBinary();
+  }
+
+  @Override
+  public void write(BatchData from, Object toArray, int index) {
+    ((Binary[]) toArray)[index] = from.getBinary();
+  }
+
   @Override
   public void writeBinary(ColumnBuilder builder, Binary value) {
     builder.writeBinary(value);
   }
 
+  @Override
+  public void addValue(int rowIndex, Object value, Object array) {
+    if (value != null && !(value instanceof Binary) && !(value instanceof String)) {
+      throw new IllegalArgumentException(
+          Messages.format(
+              "error.write.tablet_expected_type",
+              "Binary or String",
+              getDisplayName(),
+              value.getClass().getName()));
+    }
+    if (value instanceof Binary) {
+      ((Binary[]) array)[rowIndex] = (Binary) value;
+    } else {
+      ((Binary[]) array)[rowIndex] =
+          value != null
+              ? new Binary(((String) value).getBytes(TSFileConfig.STRING_CHARSET))
+              : Binary.EMPTY_VALUE;
+    }
+  }
+
+  @Override
+  public void copyArrayElement(Object source, int sourceIndex, Object target, int targetIndex) {
+    ((Binary[]) target)[targetIndex] = ((Binary[]) source)[sourceIndex];
+  }
+
+  @Override
+  public Object arrayCopyOf(Object array, int newLength) {
+    return Arrays.copyOf((Binary[]) array, newLength);
+  }
+
+  @Override
+  public Object createArray(int capacity) {
+    return new Binary[capacity];
+  }
+
+  @Override
+  public long estimateArraySize(int size) {
+    return RamUsageEstimator.sizeOfObjectArray(size);
+  }
+
+  @Override
+  public long estimateValueSize() {
+    return RamUsageEstimator.NUM_BYTES_OBJECT_REF;
+  }
+
+  @Override
+  public int serializedSize(Object array, int rowSize) {
+    return serializedSizeOfBinaryValues(array, rowSize);
+  }
+
+  @Override
+  public int serializedSize(Object array, int startRow, int endRow) {
+    return serializedSizeOfBinaryValues(array, startRow, endRow);
+  }
+
+  @Override
+  public void serializeArray(Object array, int rowSize, DataOutputStream stream)
+      throws IOException {
+    serializeBinaryValues(array, rowSize, stream);
+  }
+
+  @Override
+  public void serializeArray(Object array, int length, ByteBuffer buffer) {
+    serializeBinaryValues(array, length, buffer);
+  }
+
+  @Override
+  public Object deserializeArray(ByteBuffer buffer, int rowSize) {
+    return deserializeBinaryValues(buffer, rowSize);
+  }
+
+  @Override
+  public Object deserializeArray(DataInputStream stream, int rowSize) throws IOException {
+    return deserializeBinaryValues(stream, rowSize);
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, ByteBuffer buffer) {
+    array[index] = ReadWriteIOUtils.readBinary(buffer);
+  }
+
+  @Override
+  public void deserialize(Object[] array, int index, InputStream stream) throws IOException {
+    array[index] = ReadWriteIOUtils.readBinary(stream);
+  }
+
+  @Override
+  public Object deserializeColumn(ByteBuffer buffer, int rowSize, boolean[] nullIndicators) {
+    Binary[] values = deserializeBinaryValues(buffer, rowSize, nullIndicators);
+    return new BinaryColumn(0, rowSize, nullIndicators, values);
+  }
+
+  @Override
+  public boolean arrayEquals(Object left, Object right, int rowSize) {
+    return binaryArrayEquals(left, right, rowSize);
+  }
+
+  @Override
+  public long estimateArraySize(Object array) {
+    return RamUsageEstimator.sizeOf((Binary[]) array);
+  }
+
+  @Override
+  public Column createColumnWithMaxPosition(int positionCount) {
+    return new BinaryColumn(
+        positionCount, Optional.of(new boolean[positionCount]), new Binary[positionCount]);
+  }
+
+  @Override
+  public Column createColumnWithZeroPosition(int positionCount) {
+    return new BinaryColumn(positionCount);
+  }
+
+  @Override
+  public Column createNullColumn(int positionCount) {
+    return new RunLengthEncodedColumn(BinaryColumnBuilder.NULL_VALUE_BLOCK, positionCount);
+  }
+
   @Override
   public ColumnBuilder createColumnBuilder(int expectedEntries) {
     return new BinaryColumnBuilder(null, expectedEntries);
   }
 
+  @Override
+  public ColumnBuilder createColumnBuilder(
+      ColumnBuilderStatus columnBuilderStatus, int expectedEntries) {
+    return new BinaryColumnBuilder(columnBuilderStatus, expectedEntries);
+  }
+
   @Override
   public TypeEnum getTypeEnum() {
     return TypeEnum.OBJECT;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/RowType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/RowType.java
index 96bd3b380..012fa9307 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/RowType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/RowType.java
@@ -20,7 +20,10 @@
 package org.apache.tsfile.read.common.type;
 
 import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.utils.TsPrimitiveType;
 
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -73,6 +76,36 @@ public class RowType extends AbstractType {
     return new RowType(fields);
   }
 
+  @Override
+  public TsPrimitiveType getTsPrimitiveType() {
+    return new TsPrimitiveType.TsVector();
+  }
+
+  @Override
+  public TsPrimitiveType getTsPrimitiveType(Object value) {
+    return new TsPrimitiveType.TsVector((TsPrimitiveType[]) value);
+  }
+
+  @Override
+  public TsPrimitiveType deserialize(ByteBuffer buffer) {
+    throw new UnsupportedOperationException(getDisplayName());
+  }
+
+  @Override
+  public TsPrimitiveType getValueAsTsPrimitiveType(Object array, int rowIndex) {
+    return new TsPrimitiveType.TsVector(((TsPrimitiveType[][]) array)[rowIndex]);
+  }
+
+  @Override
+  public void write(TsPrimitiveType from, Object toArray, int index) {
+    ((TsPrimitiveType[][]) toArray)[index] = from.getVector();
+  }
+
+  @Override
+  public void write(BatchData from, Object toArray, int index) {
+    ((TsPrimitiveType[][]) toArray)[index] = from.getVector();
+  }
+
   public static Field field(String name, Type type) {
     return new Field(Optional.of(name), type);
   }
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/StringType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/StringType.java
index 725ae9e3b..f5d54ed7d 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/StringType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/StringType.java
@@ -19,12 +19,35 @@
 
 package org.apache.tsfile.read.common.type;
 
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.file.metadata.statistics.StringStatistics;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.utils.Binary;
+
 public class StringType extends AbstractVarcharType {
 
   public static final StringType STRING = new StringType();
 
   private StringType() {}
 
+  @Override
+  public Statistics<?> createStatistics() {
+    return new StringStatistics();
+  }
+
+  @Override
+  public long getStatisticsInstanceSize() {
+    return StringStatistics.INSTANCE_SIZE;
+  }
+
+  @Override
+  public Field getField(Object value) {
+    Field field = new Field(TSDataType.STRING);
+    field.setBinaryV((Binary) value);
+    return field;
+  }
+
   @Override
   public TypeEnum getTypeEnum() {
     return TypeEnum.STRING;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TimestampType.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TimestampType.java
index c4e5e8434..143c577f0 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TimestampType.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TimestampType.java
@@ -19,12 +19,34 @@
 
 package org.apache.tsfile.read.common.type;
 
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.file.metadata.statistics.TimestampStatistics;
+import org.apache.tsfile.read.common.Field;
+
 public class TimestampType extends AbstractLongType {
 
   public static final TimestampType TIMESTAMP = new TimestampType();
 
   private TimestampType() {}
 
+  @Override
+  public Statistics<?> createStatistics() {
+    return new TimestampStatistics();
+  }
+
+  @Override
+  public long getStatisticsInstanceSize() {
+    return TimestampStatistics.INSTANCE_SIZE;
+  }
+
+  @Override
+  public Field getField(Object value) {
+    Field field = new Field(TSDataType.TIMESTAMP);
+    field.setLongV((long) value);
+    return field;
+  }
+
   @Override
   public TypeEnum getTypeEnum() {
     return TypeEnum.TIMESTAMP;
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/Type.java b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/Type.java
index cb6b60944..2fa93144b 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/Type.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/Type.java
@@ -21,12 +21,49 @@ package org.apache.tsfile.read.common.type;
 
 import org.apache.tsfile.block.column.Column;
 import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.block.column.ColumnBuilderStatus;
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.encoding.decoder.Decoder;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.exception.write.UnknownColumnTypeException;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.file.metadata.statistics.Statistics;
+import org.apache.tsfile.i18n.Messages;
+import org.apache.tsfile.read.TimeValuePair;
+import org.apache.tsfile.read.common.BatchData;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.block.TsBlock;
+import org.apache.tsfile.read.query.dataset.ResultSet;
 import org.apache.tsfile.utils.Binary;
+import org.apache.tsfile.utils.TsPrimitiveType;
+import org.apache.tsfile.write.UnSupportedDataTypeException;
+import org.apache.tsfile.write.chunk.ChunkWriterImpl;
+import org.apache.tsfile.write.chunk.ValueChunkWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.StringDataPoint;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
 import java.util.List;
 
+/**
+ * Type provides common interfaces associated with a specific TsDataType to remove uses of
+ * "switch(dataType)", which make the extension of datatypes very difficult.
+ *
+ * <p>Interfaces that are less generic should be defined using TypeService and checked in a proper
+ * context.
+ */
 public interface Type {
 
+  static Type fromTsDataType(TSDataType tsDataType) {
+    return TypeFactory.getType(tsDataType);
+  }
+
   /** Gets a boolean at {@code position}. */
   default boolean getBoolean(Column c, int position) {
     throw new UnsupportedOperationException(getClass().getName());
@@ -62,6 +99,114 @@ public interface Type {
     return c.getObject(position);
   }
 
+  /** Creates an empty TsPrimitiveType for this type. */
+  default TsPrimitiveType getTsPrimitiveType() {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Creates a TsPrimitiveType initialized with {@code value}. */
+  default TsPrimitiveType getTsPrimitiveType(Object value) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Serializes {@code value} into {@code valueBytes} starting at {@code offset}. */
+  default void toBytes(TsPrimitiveType value, byte[] valueBytes, int offset) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns the number of bytes required to serialize {@code value}. */
+  default int calcTypeSize(TsPrimitiveType value) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns the number of bytes required to serialize {@code value}. */
+  default int calcTypeSize(Object value) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Initializes the value storage in {@code batchData} for this type. */
+  default void init(BatchData batchData) {
+    throw new UnSupportedDataTypeException(String.valueOf(batchData.getDataType()));
+  }
+
+  /** Adds a timestamp-value pair to {@code batchData}. */
+  default void put(BatchData batchData, long timestamp, Object value) {
+    throw new UnSupportedDataTypeException(String.valueOf(batchData.getDataType()));
+  }
+
+  /** Serializes all timestamp-value pairs in {@code batchData} and returns the serialized size. */
+  default int serialize(BatchData batchData, DataOutputStream outputStream, boolean isDesc)
+      throws IOException {
+    throw new IllegalArgumentException(
+        Messages.format("error.read.batch_data_unknown_type", batchData.getDataType()));
+  }
+
+  /**
+   * Deserializes {@code length} timestamp-value pairs from {@code buffer} into {@code batchData}.
+   */
+  default void deserialize(ByteBuffer buffer, BatchData batchData, int length) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Deserializes one value from {@code buffer} as a {@link TsPrimitiveType}. */
+  TsPrimitiveType deserialize(ByteBuffer buffer);
+
+  /** Deserializes one timestamp-value pair from {@code buffer}. */
+  default TimeValuePair deserializeTVPair(ByteBuffer buffer) {
+    long timestamp = buffer.getLong();
+    return new TimeValuePair(timestamp, deserialize(buffer));
+  }
+
+  /** Serializes {@code value} to {@code stream} and returns the serialized size. */
+  default int serialize(TsPrimitiveType value, DataOutputStream stream) throws IOException {
+    throw new IllegalArgumentException(
+        Messages.format("error.read.batch_data_unknown_type", value.getDataType()));
+  }
+
+  /**
+   * Serializes {@code timeValuePair} to {@code dataOutputStream} and returns the serialized size.
+   */
+  default int serialize(TimeValuePair timeValuePair, DataOutputStream dataOutputStream)
+      throws IOException {
+    dataOutputStream.writeLong(timeValuePair.getTimestamp());
+    return Math.addExact(Long.BYTES, serialize(timeValuePair.getValue(), dataOutputStream));
+  }
+
+  /** Serializes {@code value} to {@code buffer} and returns the serialized size. */
+  default int serializeValue(Object value, ByteBuffer buffer) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Serializes {@code value} to {@code stream} and returns the serialized size. */
+  default int serializeValue(Object value, DataOutputStream stream) throws IOException {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Writes a TsPrimitiveType value to the current entry. */
+  default void write(ColumnBuilder builder, TsPrimitiveType value) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Writes the value serialized in {@code bytes} at {@code offset} to the current entry. */
+  default void write(ColumnBuilder builder, byte[] bytes, int offset) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Writes the value at {@code index} in {@code column} to the current entry. */
+  default void write(ColumnBuilder builder, Column column, int index) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Writes a TsPrimitiveType value to {@code array} at {@code index}. */
+  default void write(TsPrimitiveType from, Object toArray, int index) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Writes the current value from {@code from} to {@code toArray} at {@code index}. */
+  default void write(BatchData from, Object toArray, int index) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
   /** Write a boolean to the current entry; */
   default void writeBoolean(ColumnBuilder builder, boolean value) {
     throw new UnsupportedOperationException(getClass().getName());
@@ -97,12 +242,323 @@ public interface Type {
     builder.writeObject(value);
   }
 
+  /** Adds a value to the array at {@code rowIndex}. */
+  default void addValue(int rowIndex, Object value, Object array) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Copies one element from {@code source} to {@code target}. */
+  default void copyArrayElement(Object source, int sourceIndex, Object target, int targetIndex) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Copies {@code array}, truncating or padding it to {@code newLength}. */
+  default Object arrayCopyOf(Object array, int newLength) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Creates an array column with {@code capacity} entries for this type. */
+  default Object createArray(int capacity) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Estimates the retained memory size of an array with {@code size} entries. */
+  default long estimateArraySize(int size) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Estimates the retained memory size of {@code array}. */
+  default long estimateArraySize(Object array) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Estimates the retained memory size of a value of this type. */
+  default long estimateValueSize() {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns the serialized byte size of the array with {@code rowSize} entries. */
+  default int serializedSize(Object array, int rowSize) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns the serialized byte size of the array within the given range. */
+  default int serializedSize(Object array, int startRow, int endRow) {
+    return serializedSize(array, endRow - startRow);
+  }
+
+  /** Serializes the array column with {@code rowSize} entries. */
+  default void serializeArray(Object array, int rowSize, DataOutputStream stream)
+      throws IOException {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Serializes the first {@code length} entries in {@code array} to {@code buffer}. */
+  default void serializeArray(Object array, int length, ByteBuffer buffer) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Deserializes an array with {@code rowSize} entries from {@code buffer}. */
+  default Object deserializeArray(ByteBuffer buffer, int rowSize) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Deserializes an array with {@code rowSize} entries from {@code stream}. */
+  default Object deserializeArray(DataInputStream stream, int rowSize) throws IOException {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Deserializes one value from {@code buffer} into {@code array} at {@code index}. */
+  default void deserialize(Object[] array, int index, ByteBuffer buffer) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Deserializes one value from {@code stream} into {@code array} at {@code index}. */
+  default void deserialize(Object[] array, int index, InputStream stream) throws IOException {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Deserializes an array with {@code rowSize} entries from {@code buffer}. */
+  default Object deserializeColumn(ByteBuffer buffer, int rowSize, boolean[] nullIndicators) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns whether two array columns are equal in the first {@code rowSize} entries. */
+  default boolean arrayEquals(Object left, Object right, int rowSize) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns the value at {@code rowIndex} from an array. */
+  default Object getValue(Object array, int rowIndex) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns the value at {@code rowIndex} from an array as a TsPrimitiveType. */
+  default TsPrimitiveType getValueAsTsPrimitiveType(Object array, int rowIndex) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns the value in {@code field}. */
+  default Object getValue(Field field) {
+    throw new UnSupportedDataTypeException(getTypeEnum().toString());
+  }
+
+  /** Creates a field initialized with {@code value}. */
+  default Field getField(Object value) {
+    throw new UnSupportedDataTypeException(getTypeEnum().toString());
+  }
+
+  /** Copies the value from {@code from} to {@code to}. */
+  default void setTo(TsPrimitiveType from, Field to) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.common.unsupported_data_type", from.getDataType()));
+  }
+
+  /** Copies the value from {@code from} to {@code to} at {@code index}. */
+  default void setTo(TsPrimitiveType from, Column to, int index) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.common.unsupported_data_type", from.getDataType()));
+  }
+
+  /** Copies {@code value} to {@code to} from {@code startIndex} to {@code endIndex}. */
+  default void setTo(Object value, Column to, int startIndex, int endIndex) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Copies the value from {@code from} to {@code to}. */
+  default void setTo(Field from, Field to) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.common.unsupported_data_type", from.getDataType()));
+  }
+
+  /** Copies the current value from {@code from} to {@code to}. */
+  default void setTo(BatchData from, Field to) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.common.unsupported_data_type", from.getDataType()));
+  }
+
+  /** Copies the current value from {@code from} to {@code to} at {@code index}. */
+  default void setTo(BatchData from, Column to, int index) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.common.unsupported_data_type", from.getDataType()));
+  }
+
+  /** Copies a value from {@code from} at {@code fromIndex} to {@code to} at {@code toIndex}. */
+  default void setTo(Column from, int fromIndex, Column to, int toIndex) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /**
+   * Copies a value from {@code from} at {@code fromIndex} to {@code toArray} at {@code toIndex}.
+   */
+  default void setTo(Column from, int fromIndex, Object toArray, int toIndex) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Adds the value of {@code columnName} in {@code resultSet} to {@code record}. */
+  default void addPoint(TSRecord record, String columnName, ResultSet resultSet) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.common.unsupported_data_type", this.getTypeEnum()));
+  }
+
+  /** Adds the value in {@code field} to {@code record}. */
+  default void addPoint(TSRecord record, String columnName, Field field) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.common.unsupported_data_type", this.getTypeEnum()));
+  }
+
+  /** Creates a data point by parsing a string value. */
+  default DataPoint getDataPoint(String measurementId, String value) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.write.type_not_supported", getTypeEnum()));
+  }
+
+  /** Creates a data point from a long value for test file generation. */
+  default DataPoint getDataPoint(String measurementId, long value) {
+    return new StringDataPoint(
+        measurementId, new Binary(String.valueOf(value), TSFileConfig.STRING_CHARSET));
+  }
+
+  /** Writes a value to an aligned value chunk. */
+  default void write(ValueChunkWriter writer, long time, Object value, boolean isNull) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.write.type_not_supported", getTypeEnum()));
+  }
+
+  /** Writes a TsPrimitiveType value to an aligned value chunk. */
+  default void write(ValueChunkWriter writer, long time, TsPrimitiveType value) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.write.type_not_supported", getTypeEnum()));
+  }
+
+  /** Writes a value at {@code rowIndex} in a Tablet column to an aligned value chunk. */
+  default void write(
+      ValueChunkWriter writer, long time, Object array, int rowIndex, boolean isNull) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.write.type_not_supported", getTypeEnum()));
+  }
+
+  /** Writes a value at {@code rowIndex} in a TsBlock column to an aligned value chunk. */
+  default void write(
+      ValueChunkWriter writer, long time, Column column, int rowIndex, boolean isNull) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.write.type_not_supported", getTypeEnum()));
+  }
+
+  /** Writes a batch of values in a TsBlock column to an aligned value chunk. */
+  default void write(
+      ValueChunkWriter writer, long[] times, Column column, int batchSize, int arrayOffset) {
+    throw new UnsupportedOperationException(
+        Messages.format("error.write.chunk_unknown_type", getTypeEnum()));
+  }
+
+  /** Writes a value at {@code rowIndex} in a Tablet column to a non-aligned chunk. */
+  default void write(ChunkWriterImpl writer, long time, Object column, int rowIndex) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.write.type_not_supported", getTypeEnum()));
+  }
+
+  /** Writes a TsPrimitiveType value to a non-aligned chunk. */
+  default void write(ChunkWriterImpl writer, long time, TsPrimitiveType value) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.write.type_not_supported", getTypeEnum()));
+  }
+
+  /** Writes the current value in {@code data} to a non-aligned chunk. */
+  default void write(ChunkWriterImpl writer, long time, BatchData data) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.write.type_not_supported", getTypeEnum()));
+  }
+
+  /** Writes a value to a non-aligned chunk. */
+  default void write(ChunkWriterImpl writer, long time, Object value) {
+    throw new UnSupportedDataTypeException(
+        Messages.format("error.write.type_not_supported", getTypeEnum()));
+  }
+
+  /** Creates a column with {@code positionCount} capacity for this type. */
+  default Column createColumnWithMaxPosition(int positionCount) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Creates a column with {@code positionCount} capacity for this type. */
+  default Column createColumnWithZeroPosition(int positionCount) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Creates an all-null column with {@code positionCount} positions. */
+  default Column createNullColumn(int positionCount) {
+    throw new IllegalArgumentException(
+        Messages.format("error.read.null_col_unknown_type", getTypeEnum()));
+  }
+
+  /** Returns the default encoding configured for this type. */
+  default TSEncoding getDefaultEncoding(TSFileConfig config) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns the default compressor configured for this type. */
+  default CompressionType getDefaultCompressor(TSFileConfig config) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns a decoder for the specified encoding. */
+  default Decoder getDecoder(TSEncoding encoding) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Returns the maximum encoded size of one item. */
+  default int getOneItemMaxSize(int valveLength) {
+    throw new UnsupportedOperationException(getClass().getName());
+  }
+
+  /** Creates empty statistics for this type. */
+  default Statistics<?> createStatistics() {
+    throw new UnknownColumnTypeException(getTypeEnum().toString());
+  }
+
+  /** Returns the estimated instance size of statistics for this type. */
... 9442 lines suppressed ...