/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.aliyun.odps.io; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; /** * BytesWritable 提供了 byte[] 的 {@link Writable} 和 {@link WritableComparable} 的实现. */ public class BytesWritable extends BinaryComparable implements WritableComparable<BinaryComparable> { private static final int LENGTH_BYTES = 4; private static final byte[] EMPTY_BYTES = {}; private int size; private byte[] bytes; /** * 默认构造 空 byte[] 的 BytesWritable. */ public BytesWritable() { this(EMPTY_BYTES); } /** * 构造值为给定 byte 数组的 BytesWritable. * * @param bytes */ public BytesWritable(byte[] bytes) { this.bytes = bytes; this.size = bytes.length; } /** * 返回此 byte 数组的内容 * * @return 此 byte 数组的内容,数据只有在 bytes[0, getLength() - 1]直接有效 */ public byte[] getBytes() { return bytes; } /** * 返回内容长度. */ public int getLength() { return size; } /** * 更改数组内容长度. * * <p> * 注意:更改后,有效数据内容只由bytes[0, 更改前 getLength() -1], 新增加的数组内容是未定义的,数组的容量按需增加。 * * @param size * 新内容长度 */ public void setSize(int size) { if (size > getCapacity()) { setCapacity(size * 3 / 2); } this.size = size; } /** * 获取字节数组容量. * * @return 字节数组容量,即:bytes.length. */ public int getCapacity() { return bytes.length; } /** * 更该字节数组容量 * * @param new_cap * 新容量大小 */ public void setCapacity(int new_cap) { if (new_cap != getCapacity()) { byte[] new_data = new byte[new_cap]; if (new_cap < size) { size = new_cap; } if (size != 0) { System.arraycopy(bytes, 0, new_data, 0, size); } bytes = new_data; } } /** * 更新数据内容为给定 BytesWritable 的数据. * * <p> * 等价于:set(newData.getBytes(), 0, newData.getLength()) * * @param newData * 新数据 */ public void set(BytesWritable newData) { set(newData.bytes, 0, newData.size); } /** * 更新数据内容为给定字节数组中的数据. * * @param newData * 源数组 * @param offset * 数据内容在 newData 中的偏移量 * @param length * 数据内容长度 */ public void set(byte[] newData, int offset, int length) { setSize(0); setSize(length); System.arraycopy(newData, offset, bytes, 0, size); } @Override public void readFields(DataInput in) throws IOException { setSize(0); // clear the old data setSize(in.readInt()); in.readFully(bytes, 0, size); } @Override public void write(DataOutput out) throws IOException { out.writeInt(size); out.write(bytes, 0, size); } @Override public int hashCode() { return super.hashCode(); } /** * 判断两个 BytesWritable 内容是否相同. * * @param right_obj * @return 如果两个都是 BytesWritable 且内容相同,返回true,否则返回false */ @Override public boolean equals(Object right_obj) { if (right_obj instanceof BytesWritable) { return super.equals(right_obj); } return false; } /** * 输出数据的十六进制内容. */ @Override public String toString() { StringBuffer sb = new StringBuffer(3 * size); for (int idx = 0; idx < size; idx++) { // if not the first, put a blank separator in if (idx != 0) { sb.append(' '); } String num = Integer.toHexString(0xff & bytes[idx]); // if it is only one digit, add a leading 0. if (num.length() < 2) { sb.append('0'); } sb.append(num); } return sb.toString(); } /** * BytesWritable 对象的 {@link WritableComparator} 自然顺序实现(升序). */ public static class Comparator extends WritableComparator { public Comparator() { super(BytesWritable.class); } /** * 基于二进制内容的 LongWritable 对象比较函数. * * <p> * 直接使用 {@link #compareBytes(byte[], int, int, byte[], int, int)} 进行二进制内容的比较 */ @Override public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { return compareBytes(b1, s1 + LENGTH_BYTES, l1 - LENGTH_BYTES, b2, s2 + LENGTH_BYTES, l2 - LENGTH_BYTES); } } static { // register this comparator WritableComparator.define(BytesWritable.class, new Comparator()); } }