一、前言
在完成了前面的理論學習後,現在可以從原始碼角度來解析Zookeeper的細節,首先筆者想從序列化入手,因為在網路通訊、資料儲存中都用到了序列化,下面開始分析。
二、序列化
序列化主要在zookeeper.jute包中,其中涉及的主要介面如下
· InputArchive
· OutputArchive
· Index
· Record
2.1 InputArchive
其是所有反序列化器都需要實現的介面,其方法如下
public interface InputArchive { // 讀取byte型別 public byte readByte(String tag) throws IOException; // 讀取boolean型別 public boolean readBool(String tag) throws IOException; // 讀取int型別 public int readInt(String tag) throws IOException; // 讀取long型別 public long readLong(String tag) throws IOException; // 讀取float型別 public float readFloat(String tag) throws IOException; // 讀取double型別 public double readDouble(String tag) throws IOException; // 讀取String型別 public String readString(String tag) throws IOException; // 通過緩衝方式讀取 public byte[] readBuffer(String tag) throws IOException; // 開始讀取記錄 public void readRecord(Record r, String tag) throws IOException; // 開始讀取記錄 public void startRecord(String tag) throws IOException; // 結束讀取記錄 public void endRecord(String tag) throws IOException; // 開始讀取向量 public Index startVector(String tag) throws IOException; // 結束讀取向量 public void endVector(String tag) throws IOException; // 開始讀取Map public Index startMap(String tag) throws IOException; // 結束讀取Map public void endMap(String tag) throws IOException; }
InputArchive的類結構如下
1. BinaryInputArchive
public class BinaryInputArchive implements InputArchive { // DataInput介面,用於從二進位制流中讀取位元組 private DataInput in; // 靜態方法,用於獲取Archive static public BinaryInputArchive getArchive(InputStream strm) { return new BinaryInputArchive(new DataInputStream(strm)); } // 內部類,對應BinaryInputArchive索引 static private class BinaryIndex implements Index { private int nelems; BinaryIndex(int nelems) { this.nelems = nelems; } public boolean done() { return (nelems <= 0); } public void incr() { nelems--; } } /** Creates a new instance of BinaryInputArchive */ // 建構函式 public BinaryInputArchive(DataInput in) { this.in = in; } // 讀取位元組 public byte readByte(String tag) throws IOException { return in.readByte(); } // 讀取boolean型別 public boolean readBool(String tag) throws IOException { return in.readBoolean(); } // 讀取int型別 public int readInt(String tag) throws IOException { return in.readInt(); } // 讀取long型別 public long readLong(String tag) throws IOException { return in.readLong(); } // 讀取float型別 public float readFloat(String tag) throws IOException { return in.readFloat(); } // 讀取double型別 public double readDouble(String tag) throws IOException { return in.readDouble(); } // 讀取String型別 public String readString(String tag) throws IOException { // 確定長度 int len = in.readInt(); if (len == -1) return null; byte b[] = new byte[len]; // 從輸入流中讀取一些位元組,並將它們儲存在緩衝區陣列b中 in.readFully(b); return new String(b, "UTF8"); } // 最大緩衝值 static public final int maxBuffer = Integer.getInteger("jute.maxbuffer", 0xfffff); // 讀取緩衝 public byte[] readBuffer(String tag) throws IOException { // 確定長度 int len = readInt(tag); if (len == -1) return null; // Since this is a rough sanity check, add some padding to maxBuffer to // make up for extra fields, etc. (otherwise e.g. clients may be able to // write buffers larger than we can read from disk!) if (len < 0 || len > maxBuffer + 1024) { // 檢查長度是否合理 throw new IOException("Unreasonable length = " + len); } byte[] arr = new byte[len]; // 從輸入流中讀取一些位元組,並將它們儲存在緩衝區陣列arr中 in.readFully(arr); return arr; } // 讀取記錄 public void readRecord(Record r, String tag) throws IOException { // 反序列化,動態呼叫 r.deserialize(this, tag); } // 開始讀取記錄,實現為空 public void startRecord(String tag) throws IOException {} // 結束讀取記錄,實現為空 public void endRecord(String tag) throws IOException {} // 開始讀取向量 public Index startVector(String tag) throws IOException { // 確定長度 int len = readInt(tag); if (len == -1) { return null; } // 返回索引 return new BinaryIndex(len); } // 結束讀取向量 public void endVector(String tag) throws IOException {} // 開始讀取Map public Index startMap(String tag) throws IOException { // 返回索引 return new BinaryIndex(readInt(tag)); } // 結束讀取Map,實現為空 public void endMap(String tag) throws IOException {} }
2. CsvInputArchive
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jute; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PushbackReader; import java.io.UnsupportedEncodingException; /** * */ class CsvInputArchive implements InputArchive { // 推回位元組流 private PushbackReader stream; // 內部類,對應CsvInputArchive索引 private class CsvIndex implements Index { public boolean done() { char c = '\0'; try { c = (char) stream.read(); stream.unread(c); } catch (IOException ex) { } return (c == '}') ? true : false; } public void incr() {} } // 私有方法,丟擲異常 private void throwExceptionOnError(String tag) throws IOException { throw new IOException("Error deserializing "+tag); } // 私有方法,讀取欄位 private String readField(String tag) throws IOException { try { StringBuilder buf = new StringBuilder(); while (true) { // 讀取並轉化為字元 char c = (char) stream.read(); switch (c) { // 判斷字元 case ',': // 讀取欄位完成,可直接返回 return buf.toString(); case '}': case '\n': case '\r': // 推回緩衝區 stream.unread(c); return buf.toString(); default: // 預設新增至buf中 buf.append(c); } } } catch (IOException ex) { throw new IOException("Error reading "+tag); } } // 獲取CsvInputArchive static CsvInputArchive getArchive(InputStream strm) throws UnsupportedEncodingException { return new CsvInputArchive(strm); } /** Creates a new instance of CsvInputArchive */ // 建構函式 public CsvInputArchive(InputStream in) throws UnsupportedEncodingException { // 初始化stream屬性 stream = new PushbackReader(new InputStreamReader(in, "UTF-8")); } // 讀取byte型別 public byte readByte(String tag) throws IOException { return (byte) readLong(tag); } // 讀取boolean型別 public boolean readBool(String tag) throws IOException { String sval = readField(tag); return "T".equals(sval) ? true : false; } // 讀取int型別 public int readInt(String tag) throws IOException { return (int) readLong(tag); } // 讀取long型別 public long readLong(String tag) throws IOException { // 讀取欄位 String sval = readField(tag); try { // 轉化 long lval = Long.parseLong(sval); return lval; } catch (NumberFormatException ex) { throw new IOException("Error deserializing "+tag); } } // 讀取float型別 public float readFloat(String tag) throws IOException { return (float) readDouble(tag); } // 讀取double型別 public double readDouble(String tag) throws IOException { // 讀取欄位 String sval = readField(tag); try { // 轉化 double dval = Double.parseDouble(sval); return dval; } catch (NumberFormatException ex) { throw new IOException("Error deserializing "+tag); } } // 讀取String型別 public String readString(String tag) throws IOException { // 讀取欄位 String sval = readField(tag); // 轉化 return Utils.fromCSVString(sval); } // 讀取緩衝型別 public byte[] readBuffer(String tag) throws IOException { // 讀取欄位 String sval = readField(tag); // 轉化 return Utils.fromCSVBuffer(sval); } // 讀取記錄 public void readRecord(Record r, String tag) throws IOException { // 反序列化 r.deserialize(this, tag); } // 開始讀取記錄 public void startRecord(String tag) throws IOException { if (tag != null && !"".equals(tag)) { // 讀取並轉化為字元 char c1 = (char) stream.read(); // 讀取並轉化為字元 char c2 = (char) stream.read(); if (c1 != 's' || c2 != '{') { // 進行判斷 throw new IOException("Error deserializing "+tag); } } } // 結束讀取記錄 public void endRecord(String tag) throws IOException { // 讀取並轉化為字元 char c = (char) stream.read(); if (tag == null || "".equals(tag)) { if (c != '\n' && c != '\r') { // 進行判斷 throw new IOException("Error deserializing record."); } else { return; } } if (c != '}') { // 進行判斷 throw new IOException("Error deserializing "+tag); } // 讀取並轉化為字元 c = (char) stream.read(); if (c != ',') { // 推回緩衝區 stream.unread(c); } return; } // 開始讀取vector public Index startVector(String tag) throws IOException { char c1 = (char) stream.read(); char c2 = (char) stream.read(); if (c1 != 'v' || c2 != '{') { throw new IOException("Error deserializing "+tag); } return new CsvIndex(); } // 結束讀取vector public void endVector(String tag) throws IOException { char c = (char) stream.read(); if (c != '}') { throw new IOException("Error deserializing "+tag); } c = (char) stream.read(); if (c != ',') { stream.unread(c); } return; } // 開始讀取Map public Index startMap(String tag) throws IOException { char c1 = (char) stream.read(); char c2 = (char) stream.read(); if (c1 != 'm' || c2 != '{') { throw new IOException("Error deserializing "+tag); } return new CsvIndex(); } // 結束讀取Map public void endMap(String tag) throws IOException { char c = (char) stream.read(); if (c != '}') { throw new IOException("Error deserializing "+tag); } c = (char) stream.read(); if (c != ',') { stream.unread(c); } return; } }
3. XmlInputArchive
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jute; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * */ class XmlInputArchive implements InputArchive { // 內部類,值(包含型別和值) static private class Value { private String type; private StringBuffer sb; public Value(String t) { type = t; sb = new StringBuffer(); } // 新增chars public void addChars(char[] buf, int offset, int len) { sb.append(buf, offset, len); } // 返回value public String getValue() { return sb.toString(); } // 返回type public String getType() { return type; } } // 內部類,XML解析器 private static class XMLParser extends DefaultHandler { private boolean charsValid = false; private ArrayList<Value> valList; private XMLParser(ArrayList<Value> vlist) { valList = vlist; } // 文件開始,空的實現 public void startDocument() throws SAXException {} // 文件結束,空的實現 public void endDocument() throws SAXException {} // 開始解析元素 public void startElement(String ns, String sname, String qname, Attributes attrs) throws SAXException { // charsValid = false; if ("boolean".equals(qname) || // boolean型別 "i4".equals(qname) || // 四個位元組 "int".equals(qname) || // int型別 "string".equals(qname) || // String型別 "double".equals(qname) || // double型別 "ex:i1".equals(qname) || // 一個位元組 "ex:i8".equals(qname) || // 八個位元組 "ex:float".equals(qname)) { // 基本型別 // charsValid = true; // 新增至列表 valList.add(new Value(qname)); } else if ("struct".equals(qname) || "array".equals(qname)) { // 結構體或陣列型別 // 新增至列表 valList.add(new Value(qname)); } } // 結束解析元素 public void endElement(String ns, String sname, String qname) throws SAXException { charsValid = false; if ("struct".equals(qname) || "array".equals(qname)) { // 結構體或陣列型別 // 新增至列表 valList.add(new Value("/"+qname)); } } public void characters(char buf[], int offset, int len) throws SAXException { if (charsValid) { // 是否合法 // 從列表獲取value Value v = valList.get(valList.size()-1); // 將buf新增至value v.addChars(buf, offset,len); } } } // 內部類,對應XmlInputArchive private class XmlIndex implements Index { // 是否已經完成 public boolean done() { // 根據索引獲取value Value v = valList.get(vIdx); if ("/array".equals(v.getType())) { // 型別為/array // 設定開索引值為null valList.set(vIdx, null); // 增加索引值 vIdx++; return true; } else { return false; } } // 增加索引值,空的實現 public void incr() {} } // 值列表 private ArrayList<Value> valList; // 值長度 private int vLen; // 索引 private int vIdx; // 下一項 private Value next() throws IOException { if (vIdx < vLen) { // 當前索引值小於長度 // 獲取值 Value v = valList.get(vIdx); // 設定索引值為null valList.set(vIdx, null); // 增加索引值 vIdx++; return v; } else { throw new IOException("Error in deserialization."); } } // 獲取XmlInputArchive static XmlInputArchive getArchive(InputStream strm) throws ParserConfigurationException, SAXException, IOException { return new XmlInputArchive(strm); } /** Creates a new instance of BinaryInputArchive */ // 建構函式 public XmlInputArchive(InputStream in) throws ParserConfigurationException, SAXException, IOException { // 初始化XmlInputArchive的相應欄位 valList = new ArrayList<Value>(); DefaultHandler handler = new XMLParser(valList); SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse(in, handler); vLen = valList.size(); vIdx = 0; } // 讀取byte型別 public byte readByte(String tag) throws IOException { Value v = next(); if (!"ex:i1".equals(v.getType())) { throw new IOException("Error deserializing "+tag+"."); } return Byte.parseByte(v.getValue()); } // 讀取Boolean型別 public boolean readBool(String tag) throws IOException { Value v = next(); if (!"boolean".equals(v.getType())) { throw new IOException("Error deserializing "+tag+"."); } return "1".equals(v.getValue()); } // 讀取int型別 public int readInt(String tag) throws IOException { Value v = next(); if (!"i4".equals(v.getType()) && !"int".equals(v.getType())) { throw new IOException("Error deserializing "+tag+"."); } return Integer.parseInt(v.getValue()); } // 讀取long型別 public long readLong(String tag) throws IOException { Value v = next(); if (!"ex:i8".equals(v.getType())) { throw new IOException("Error deserializing "+tag+"."); } return Long.parseLong(v.getValue()); } // 讀取float型別 public float readFloat(String tag) throws IOException { Value v = next(); if (!"ex:float".equals(v.getType())) { throw new IOException("Error deserializing "+tag+"."); } return Float.parseFloat(v.getValue()); } // 讀取double型別 public double readDouble(String tag) throws IOException { Value v = next(); if (!"double".equals(v.getType())) { throw new IOException("Error deserializing "+tag+"."); } return Double.parseDouble(v.getValue()); } // 讀取String型別 public String readString(String tag) throws IOException { Value v = next(); if (!"string".equals(v.getType())) { throw new IOException("Error deserializing "+tag+"."); } return Utils.fromXMLString(v.getValue()); } // 讀取Buffer型別 public byte[] readBuffer(String tag) throws IOException { Value v = next(); if (!"string".equals(v.getType())) { throw new IOException("Error deserializing "+tag+"."); } return Utils.fromXMLBuffer(v.getValue()); } // 讀取Record型別 public void readRecord(Record r, String tag) throws IOException { r.deserialize(this, tag); } // 開始讀取Record public void startRecord(String tag) throws IOException { Value v = next(); if (!"struct".equals(v.getType())) { throw new IOException("Error deserializing "+tag+"."); } } // 結束讀取Record public void endRecord(String tag) throws IOException { Value v = next(); if (!"/struct".equals(v.getType())) { throw new IOException("Error deserializing "+tag+"."); } } // 開始讀取vector public Index startVector(String tag) throws IOException { Value v = next(); if (!"array".equals(v.getType())) { throw new IOException("Error deserializing "+tag+"."); } return new XmlIndex(); } // 結束讀取vector public void endVector(String tag) throws IOException {} // 開始讀取Map public Index startMap(String tag) throws IOException { return startVector(tag); } // 停止讀取Map public void endMap(String tag) throws IOException { endVector(tag); } }
2.2 OutputArchive
其是所有序列化器都需要實現此介面,其方法如下。
public interface OutputArchive { // 寫Byte型別 public void writeByte(byte b, String tag) throws IOException; // 寫boolean型別 public void writeBool(boolean b, String tag) throws IOException; // 寫int型別 public void writeInt(int i, String tag) throws IOException; // 寫long型別 public void writeLong(long l, String tag) throws IOException; // 寫float型別 public void writeFloat(float f, String tag) throws IOException; // 寫double型別 public void writeDouble(double d, String tag) throws IOException; // 寫String型別 public void writeString(String s, String tag) throws IOException; // 寫Buffer型別 public void writeBuffer(byte buf[], String tag) throws IOException; // 寫Record型別 public void writeRecord(Record r, String tag) throws IOException; // 開始寫Record public void startRecord(Record r, String tag) throws IOException; // 結束寫Record public void endRecord(Record r, String tag) throws IOException; // 開始寫Vector public void startVector(List v, String tag) throws IOException; // 結束寫Vector public void endVector(List v, String tag) throws IOException; // 開始寫Map public void startMap(TreeMap v, String tag) throws IOException; // 結束寫Map public void endMap(TreeMap v, String tag) throws IOException; }
OutputArchive的類結構如下
1. BinaryOutputArchive
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jute; import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.List; import java.util.TreeMap; /** * */ public class BinaryOutputArchive implements OutputArchive { // 位元組緩衝 private ByteBuffer bb = ByteBuffer.allocate(1024); // DataInput介面,用於從二進位制流中讀取位元組 private DataOutput out; // 靜態方法,用於獲取Archive public static BinaryOutputArchive getArchive(OutputStream strm) { return new BinaryOutputArchive(new DataOutputStream(strm)); } /** Creates a new instance of BinaryOutputArchive */ // 建構函式 public BinaryOutputArchive(DataOutput out) { this.out = out; } // 寫Byte型別 public void writeByte(byte b, String tag) throws IOException { out.writeByte(b); } // 寫boolean型別 public void writeBool(boolean b, String tag) throws IOException { out.writeBoolean(b); } // 寫int型別 public void writeInt(int i, String tag) throws IOException { out.writeInt(i); } // 寫long型別 public void writeLong(long l, String tag) throws IOException { out.writeLong(l); } // 寫float型別 public void writeFloat(float f, String tag) throws IOException { out.writeFloat(f); } // 寫double型別 public void writeDouble(double d, String tag) throws IOException { out.writeDouble(d); } /** * create our own char encoder to utf8. This is faster * then string.getbytes(UTF8). * @param s the string to encode into utf8 * @return utf8 byte sequence. */ // 將String型別轉化為ByteBuffer型別 final private ByteBuffer stringToByteBuffer(CharSequence s) { // 清空ByteBuffer bb.clear(); // s的長度 final int len = s.length(); for (int i = 0; i < len; i++) { // 遍歷s if (bb.remaining() < 3) { // ByteBuffer剩餘大小小於3 // 再進行一次分配(擴大一倍) ByteBuffer n = ByteBuffer.allocate(bb.capacity() << 1); // 切換方式 bb.flip(); // 寫入bb n.put(bb); bb = n; } char c = s.charAt(i); if (c < 0x80) { // 小於128,直接寫入 bb.put((byte) c); } else if (c < 0x800) { // 小於2048,則進行相應處理 bb.put((byte) (0xc0 | (c >> 6))); bb.put((byte) (0x80 | (c & 0x3f))); } else { // 大於2048,則進行相應處理 bb.put((byte) (0xe0 | (c >> 12))); bb.put((byte) (0x80 | ((c >> 6) & 0x3f))); bb.put((byte) (0x80 | (c & 0x3f))); } } // 切換方式 bb.flip(); return bb; } // 寫String型別 public void writeString(String s, String tag) throws IOException { if (s == null) { writeInt(-1, "len"); return; } ByteBuffer bb = stringToByteBuffer(s); writeInt(bb.remaining(), "len"); out.write(bb.array(), bb.position(), bb.limit()); } // 寫Buffer型別 public void writeBuffer(byte barr[], String tag) throws IOException { if (barr == null) { out.writeInt(-1); return; } out.writeInt(barr.length); out.write(barr); } // 寫Record型別 public void writeRecord(Record r, String tag) throws IOException { r.serialize(this, tag); } // 開始寫Record public void startRecord(Record r, String tag) throws IOException {} // 結束寫Record public void endRecord(Record r, String tag) throws IOException {} // 開始寫Vector public void startVector(List v, String tag) throws IOException { if (v == null) { writeInt(-1, tag); return; } writeInt(v.size(), tag); } // 結束寫Vector public void endVector(List v, String tag) throws IOException {} // 開始寫Map public void startMap(TreeMap v, String tag) throws IOException { writeInt(v.size(), tag); } // 結束寫Map public void endMap(TreeMap v, String tag) throws IOException {} }
2. CsvOutputArchive
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jute; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.util.List; import java.util.TreeMap; /** * */ public class CsvOutputArchive implements OutputArchive { // PrintStream為其他輸出流新增了功能,使它們能夠方便地列印各種資料值表示形式 private PrintStream stream; // 預設為第一次 private boolean isFirst = true; // 獲取Archive static CsvOutputArchive getArchive(OutputStream strm) throws UnsupportedEncodingException { return new CsvOutputArchive(strm); } // 私有函式,丟擲異常 private void throwExceptionOnError(String tag) throws IOException { if (stream.checkError()) { throw new IOException("Error serializing "+tag); } } // 私有函式,除第一次外,均列印"," private void printCommaUnlessFirst() { if (!isFirst) { stream.print(","); } isFirst = false; } /** Creates a new instance of CsvOutputArchive */ // 建構函式 public CsvOutputArchive(OutputStream out) throws UnsupportedEncodingException { stream = new PrintStream(out, true, "UTF-8"); } // 寫Byte型別 public void writeByte(byte b, String tag) throws IOException { writeLong((long)b, tag); } // 寫boolean型別 public void writeBool(boolean b, String tag) throws IOException { // 列印"," printCommaUnlessFirst(); String val = b ? "T" : "F"; // 列印值 stream.print(val); // 丟擲異常 throwExceptionOnError(tag); } // 寫int型別 public void writeInt(int i, String tag) throws IOException { writeLong((long)i, tag); } // 寫long型別 public void writeLong(long l, String tag) throws IOException { printCommaUnlessFirst(); stream.print(l); throwExceptionOnError(tag); } // 寫float型別 public void writeFloat(float f, String tag) throws IOException { writeDouble((double)f, tag); } // 寫double型別 public void writeDouble(double d, String tag) throws IOException { printCommaUnlessFirst(); stream.print(d); throwExceptionOnError(tag); } // 寫String型別 public void writeString(String s, String tag) throws IOException { printCommaUnlessFirst(); stream.print(Utils.toCSVString(s)); throwExceptionOnError(tag); } // 寫Buffer型別 public void writeBuffer(byte buf[], String tag) throws IOException { printCommaUnlessFirst(); stream.print(Utils.toCSVBuffer(buf)); throwExceptionOnError(tag); } // 寫Record型別 public void writeRecord(Record r, String tag) throws IOException { if (r == null) { return; } r.serialize(this, tag); } // 開始寫Record public void startRecord(Record r, String tag) throws IOException { if (tag != null && !"".equals(tag)) { printCommaUnlessFirst(); stream.print("s{"); isFirst = true; } } // 結束寫Record public void endRecord(Record r, String tag) throws IOException { if (tag == null || "".equals(tag)) { stream.print("\n"); isFirst = true; } else { stream.print("}"); isFirst = false; } } // 開始寫Vector public void startVector(List v, String tag) throws IOException { printCommaUnlessFirst(); stream.print("v{"); isFirst = true; } // 結束寫Vector public void endVector(List v, String tag) throws IOException { stream.print("}"); isFirst = false; } // 開始寫Map public void startMap(TreeMap v, String tag) throws IOException { printCommaUnlessFirst(); stream.print("m{"); isFirst = true; } // 結束寫Map public void endMap(TreeMap v, String tag) throws IOException { stream.print("}"); isFirst = false; } }
3. XmlOutputArchive
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jute; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.List; import java.util.Stack; import java.util.TreeMap; /** * */ class XmlOutputArchive implements OutputArchive { // PrintStream為其他輸出流新增了功能,使它們能夠方便地列印各種資料值表示形式 private PrintStream stream; // 縮排個數 private int indent = 0; // 棧結構 private Stack<String> compoundStack; // 存放縮排 private void putIndent() { StringBuilder sb = new StringBuilder(""); for (int idx = 0; idx < indent; idx++) { sb.append(" "); } stream.print(sb.toString()); } // 新增縮排 private void addIndent() { indent++; } // 減少縮排 private void closeIndent() { indent--; } // 列印檔案頭格式 private void printBeginEnvelope(String tag) { if (!compoundStack.empty()) { String s = compoundStack.peek(); if ("struct".equals(s)) { putIndent(); stream.print("<member>\n"); addIndent(); putIndent(); stream.print("<name>"+tag+"</name>\n"); putIndent(); stream.print("<value>"); } else if ("vector".equals(s)) { stream.print("<value>"); } else if ("map".equals(s)) { stream.print("<value>"); } } else { stream.print("<value>"); } } // 列印檔案尾格式 private void printEndEnvelope(String tag) { if (!compoundStack.empty()) { String s = compoundStack.peek(); if ("struct".equals(s)) { stream.print("</value>\n"); closeIndent(); putIndent(); stream.print("</member>\n"); } else if ("vector".equals(s)) { stream.print("</value>\n"); } else if ("map".equals(s)) { stream.print("</value>\n"); } } else { stream.print("</value>\n"); } } // private void insideVector(String tag) { printBeginEnvelope(tag); compoundStack.push("vector"); } private void outsideVector(String tag) throws IOException { String s = compoundStack.pop(); if (!"vector".equals(s)) { throw new IOException("Error serializing vector."); } printEndEnvelope(tag); } private void insideMap(String tag) { printBeginEnvelope(tag); compoundStack.push("map"); } private void outsideMap(String tag) throws IOException { String s = compoundStack.pop(); if (!"map".equals(s)) { throw new IOException("Error serializing map."); } printEndEnvelope(tag); } private void insideRecord(String tag) { printBeginEnvelope(tag); compoundStack.push("struct"); } private void outsideRecord(String tag) throws IOException { String s = compoundStack.pop(); if (!"struct".equals(s)) { throw new IOException("Error serializing record."); } printEndEnvelope(tag); } // 獲取Archive static XmlOutputArchive getArchive(OutputStream strm) { return new XmlOutputArchive(strm); } /** Creates a new instance of XmlOutputArchive */ // 建構函式 public XmlOutputArchive(OutputStream out) { stream = new PrintStream(out); compoundStack = new Stack<String>(); } // 寫Byte型別 public void writeByte(byte b, String tag) throws IOException { printBeginEnvelope(tag); stream.print("<ex:i1>"); stream.print(Byte.toString(b)); stream.print("</ex:i1>"); printEndEnvelope(tag); } // 寫boolean型別 public void writeBool(boolean b, String tag) throws IOException { printBeginEnvelope(tag); stream.print("<boolean>"); stream.print(b ? "1" : "0"); stream.print("</boolean>"); printEndEnvelope(tag); } // 寫int型別 public void writeInt(int i, String tag) throws IOException { printBeginEnvelope(tag); stream.print("<i4>"); stream.print(Integer.toString(i)); stream.print("</i4>"); printEndEnvelope(tag); } // 寫long型別 public void writeLong(long l, String tag) throws IOException { printBeginEnvelope(tag); stream.print("<ex:i8>"); stream.print(Long.toString(l)); stream.print("</ex:i8>"); printEndEnvelope(tag); } // 寫float型別 public void writeFloat(float f, String tag) throws IOException { printBeginEnvelope(tag); stream.print("<ex:float>"); stream.print(Float.toString(f)); stream.print("</ex:float>"); printEndEnvelope(tag); } // 寫double型別 public void writeDouble(double d, String tag) throws IOException { printBeginEnvelope(tag); stream.print("<double>"); stream.print(Double.toString(d)); stream.print("</double>"); printEndEnvelope(tag); } // 寫String型別 public void writeString(String s, String tag) throws IOException { printBeginEnvelope(tag); stream.print("<string>"); stream.print(Utils.toXMLString(s)); stream.print("</string>"); printEndEnvelope(tag); } // 寫Buffer型別 public void writeBuffer(byte buf[], String tag) throws IOException { printBeginEnvelope(tag); stream.print("<string>"); stream.print(Utils.toXMLBuffer(buf)); stream.print("</string>"); printEndEnvelope(tag); } // 寫Record型別 public void writeRecord(Record r, String tag) throws IOException { r.serialize(this, tag); } // 開始寫Record型別 public void startRecord(Record r, String tag) throws IOException { insideRecord(tag); stream.print("<struct>\n"); addIndent(); } // 結束寫Record型別 public void endRecord(Record r, String tag) throws IOException { closeIndent(); putIndent(); stream.print("</struct>"); outsideRecord(tag); } // 開始寫Vector型別 public void startVector(List v, String tag) throws IOException { insideVector(tag); stream.print("<array>\n"); addIndent(); } // 結束寫Vector型別 public void endVector(List v, String tag) throws IOException { closeIndent(); putIndent(); stream.print("</array>"); outsideVector(tag); } // 開始寫Map型別 public void startMap(TreeMap v, String tag) throws IOException { insideMap(tag); stream.print("<array>\n"); addIndent(); } // 結束寫Map型別 public void endMap(TreeMap v, String tag) throws IOException { closeIndent(); putIndent(); stream.print("</array>"); outsideMap(tag); } }
2.3 Index
其用於迭代反序列化器的迭代器。
public interface Index { // 是否已經完成 public boolean done(); // 下一項 public void incr(); }
Index的類結構如下
1. BinaryIndex
static private class BinaryIndex implements Index { // 元素個數 private int nelems; // 建構函式 BinaryIndex(int nelems) { this.nelems = nelems; } // 是否已經完成 public boolean done() { return (nelems <= 0); } // 移動一項 public void incr() { nelems--; } }
2. CsxIndex
private class CsvIndex implements Index { // 是否已經完成 public boolean done() { char c = '\0'; try { // 讀取字元 c = (char) stream.read(); // 推回緩衝區 stream.unread(c); } catch (IOException ex) { } return (c == '}') ? true : false; } // 什麼都不做 public void incr() {} }
3. XmlIndex
private class XmlIndex implements Index { // 是否已經完成 public boolean done() { // 根據索引獲取值 Value v = valList.get(vIdx); if ("/array".equals(v.getType())) { // 判斷是否值的型別是否為/array // 設定索引的值 valList.set(vIdx, null); // 索引加1 vIdx++; return true; } else { return false; } } // 什麼都不做 public void incr() {} }
2.4 Record
所有用於網路傳輸或者本地儲存的型別都實現該介面,其方法如下
public interface Record { // 序列化 public void serialize(OutputArchive archive, String tag) throws IOException; // 反序列化 public void deserialize(InputArchive archive, String tag) throws IOException; }
所有的實現類都需要實現seriallize和deserialize方法。
三、示例
下面通過一個示例來理解OutputArchive和InputArchive的搭配使用。
package com.leesf.zookeeper_samples; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Set; import java.util.TreeMap; import org.apache.jute.BinaryInputArchive; import org.apache.jute.BinaryOutputArchive; import org.apache.jute.Index; import org.apache.jute.InputArchive; import org.apache.jute.OutputArchive; import org.apache.jute.Record; public class ArchiveTest { public static void main( String[] args ) throws IOException { String path = "F:\\test.txt"; // write operation OutputStream outputStream = new FileOutputStream(new File(path)); BinaryOutputArchive binaryOutputArchive = BinaryOutputArchive.getArchive(outputStream); binaryOutputArchive.writeBool(true, "boolean"); byte[] bytes = "leesf".getBytes(); binaryOutputArchive.writeBuffer(bytes, "buffer"); binaryOutputArchive.writeDouble(13.14, "double"); binaryOutputArchive.writeFloat(5.20f, "float"); binaryOutputArchive.writeInt(520, "int"); Person person = new Person(25, "leesf"); binaryOutputArchive.writeRecord(person, "leesf"); TreeMap<String, Integer> map = new TreeMap<String, Integer>(); map.put("leesf", 25); map.put("dyd", 25); Set<String> keys = map.keySet(); binaryOutputArchive.startMap(map, "map"); int i = 0; for (String key: keys) { String tag = i + ""; binaryOutputArchive.writeString(key, tag); binaryOutputArchive.writeInt(map.get(key), tag); i++; } binaryOutputArchive.endMap(map, "map"); // read operation InputStream inputStream = new FileInputStream(new File(path)); BinaryInputArchive binaryInputArchive = BinaryInputArchive.getArchive(inputStream); System.out.println(binaryInputArchive.readBool("boolean")); System.out.println(new String(binaryInputArchive.readBuffer("buffer"))); System.out.println(binaryInputArchive.readDouble("double")); System.out.println(binaryInputArchive.readFloat("float")); System.out.println(binaryInputArchive.readInt("int")); Person person2 = new Person(); binaryInputArchive.readRecord(person2, "leesf"); System.out.println(person2); Index index = binaryInputArchive.startMap("map"); int j = 0; while (!index.done()) { String tag = j + ""; System.out.println("key = " + binaryInputArchive.readString(tag) + ", value = " + binaryInputArchive.readInt(tag)); index.incr(); j++; } } static class Person implements Record { private int age; private String name; public Person() { } public Person(int age, String name) { this.age = age; this.name = name; } public void serialize(OutputArchive archive, String tag) throws IOException { archive.startRecord(this, tag); archive.writeInt(age, "age"); archive.writeString(name, "name"); archive.endRecord(this, tag); } public void deserialize(InputArchive archive, String tag) throws IOException { archive.startRecord(tag); age = archive.readInt("age"); name = archive.readString("name"); archive.endRecord(tag); } public String toString() { return "age = " + age + ", name = " + name; } } }
執行結果:
true leesf 13.14 5.2 520 age = 25, name = leesf key = dyd, value = 25 key = leesf, value = 25
四、總結
本篇博文分析了序列化中涉及到的類,主要是org.zookeeper.jute包下的類,相對來說還是相對簡單,也謝謝各位園友的觀看~