Zookeeper-Binary OutputArchive의utf-8의 실현

9022 단어
Binary OutputArchive 클래스는 org에 있습니다.apache.jute 패키지는 정렬화된 구성 요소의 클래스입니다.글자의 뜻으로 이해하면 출력류다.이 클래스는 OutputArchive 인터페이스를 구현합니다.또한 구조 함수에서 Data Output 인터페이스의 실현 클래스를 전달해야 한다.
이 코드 중 하나가 나의 주의를 끌었다.
/**
     * 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.
     */
    final private ByteBuffer stringToByteBuffer(CharSequence s) {
        bb.clear();
        final int len = s.length();
        for (int i = 0; i < len; i++) {
            if (bb.remaining() < 3) {
                ByteBuffer n = ByteBuffer.allocate(bb.capacity() << 1);
                bb.flip();
                n.put(bb);
                bb = n;
            }
            char c = s.charAt(i);
            //    
            if (c < 0x80) {
                bb.put((byte) c);
            }
            else if (c < 0x800) {
                bb.put((byte) (0xc0 | (c >> 6)));
                bb.put((byte) (0x80 | (c & 0x3f)));
            } else {
                bb.put((byte) (0xe0 | (c >> 12)));
                bb.put((byte) (0x80 | ((c >> 6) & 0x3f)));
                bb.put((byte) (0x80 | (c & 0x3f)));
            }
        }
        bb.flip();
        return bb;
    }

 
코드의 주석에 의하면 이곳의 실현은 자바 자체보다 효율적이라고 한다.그렇다면 과연 어떨까?비교해서 한 번 배울 만하다.
우선 비교하기 전에 그들이 무엇을 하고 있는지 제거해야 한다.이 방식은 하나의 문자열이utf-8 인코딩 형식의 바이트 그룹으로 바뀌는 것을 실현했다.그러면utf-8 인코딩 형식은 어떻게 변환해야 합니까?일반적인 규칙은 다음과 같습니다.
   1.단자 바이트의 기호에 대해 바이트의 첫 번째 자리는 0이고, 다음 7자리는 이 기호의 유니버설 코드이다.따라서 영어 문자의 경우 UTF-8 코드와 ASCII 코드가 동일합니다.
         2.n 바이트의 기호(n>1)에 대해 첫 번째 바이트의 앞 n자리는 모두 1이고 n+1자리는 0이며 뒤 바이트의 앞 두 자리는 일률적으로 10이다.나머지 언급되지 않은 이진 비트는 모두 이 기호의 유니버설 코드입니다.
예는 다음과 같습니다.
1 바이트 0000 0000-0000 007F | 0xxxx
2바이트 0000 0080-0000 07FF | 110xxxx 10xxxx
3바이트 0000 08000-0000 FFF | 1110xxx 10xxx 10xxxx
4바이트0001 0000-0010 FFF | 11110xxx 10xxx 10xxx 10xxx 10xxx 10xxx
위의 규칙에 따라 코드를 이해하면 좀 편리할 것이다.stringToByteBuffer 메서드의 논리는 다음과 같습니다.
  • 순환 문자의 길이입니다.버퍼 바이트 클래스 ByteBuffer의 여유 공간이 부족하면 1배 확장됩니다.(여기 비트 연산 사용)
  • 1바이트 직접 저장
  • 2바이트라면 문자의 앞부분을 규칙에 따라 첫 번째 바이트에 넣고 뒷부분을 두 번째 바이트에 넣는다.0xc0-->11000000.그것이나 문자로 위 규칙의 110xxxx 요구를 충족시키십시오.코드 c>>6은 나로 하여금 한참 동안 이해하게 했다.마지막으로 나는 규칙에 따라 첫 번째 바이트를 제외하고 다른 바이트는 모두 앞의 두 자리인 것을 발견했다.그럼 여섯 분밖에 안 남았어요.그래서 위치 이동 계산의 숫자는 6의 배수로 진행된다.0x80-->10000000、0x3f-->00111111.코드 0x80 | (c & 0x3f)는 두 번째 바이트의 조건을 충족시켰다
  • 3바이트 코드와 2바이트 코드가 유사
  • stringToByteBuffer라는 방법을 이해한 후에 자바의 실현을 살펴보자.
     
    public byte[] getBytes(String charsetName)
                throws UnsupportedEncodingException {
            if (charsetName == null) throw new NullPointerException();
            return StringCoding.encode(charsetName, value, 0, value.length);
        }
    

     
    더 이상 할 말이 없습니다. StringCoding 방법을 사용했습니다.코드 추적을 계속하려면:
    static byte[] encode(String charsetName, char[] ca, int off, int len)
            throws UnsupportedEncodingException
        {
            StringEncoder se = deref(encoder);
            String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
            if ((se == null) || !(csn.equals(se.requestedCharsetName())
                                  || csn.equals(se.charsetName()))) {
                se = null;
                try {
                    Charset cs = lookupCharset(csn);
                    if (cs != null)
                        se = new StringEncoder(cs, csn);
                } catch (IllegalCharsetNameException x) {}
                if (se == null)
                    throw new UnsupportedEncodingException (csn);
                set(encoder, se);
            }
            return se.encode(ca, off, len);
        }
    

     
    이 코드의 대략적인 의미는 전달된 문자 집합의 이름에 따라 문자 집합을 찾은 다음에 문자 집합에 따라 StringEncoder 형식의 대상을 만드는 것으로 추측된다.그리고 대상의 encode 방법을 호출합니다.코드 추적을 계속하려면:
    byte[] encode(char[] ca, int off, int len) {
                int en = scale(len, ce.maxBytesPerChar());
                byte[] ba = new byte[en];
                if (len == 0)
                    return ba;
                if (ce instanceof ArrayEncoder) {
                    int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
                    return safeTrim(ba, blen, cs, isTrusted);
                } else {
                    ce.reset();
                    ByteBuffer bb = ByteBuffer.wrap(ba);
                    CharBuffer cb = CharBuffer.wrap(ca, off, len);
                    try {
                        CoderResult cr = ce.encode(cb, bb, true);
                        if (!cr.isUnderflow())
                            cr.throwException();
                        cr = ce.flush(bb);
                        if (!cr.isUnderflow())
                            cr.throwException();
                    } catch (CharacterCodingException x) {
                        // Substitution is always enabled,
                        // so this shouldn't happen
                        throw new Error(x);
                    }
                    return safeTrim(ba, bb.position(), cs, isTrusted);
                }
            }
    

     
    이 코드는 StringEncoder의 유형을 판단합니다.나는 테스트 용례byte[]x="a"를 쓴다.getbytes("utf-8"); 추적 코드가 여기까지 왔는데 Array Encoder가 논리적으로 갔어요.계속해서 추적하여 Array Encoder의 여러 가지 실현을 발견하다.그중에 UTF 가 하나 있어요.8종류.이 종류는nio 가방에 있습니다.이 코드는 역컴파일링을 통해서만 볼 수 있으며 원본 패키지를 찾을 수 없습니다.
    /*     */     public int encode(char[] paramArrayOfChar, int paramInt1, int paramInt2, byte[] paramArrayOfByte)
    /*     */     {
    /* 627 */       int i = paramInt1 + paramInt2;
    /* 628 */       int j = 0;
    /* 629 */       int k = j + Math.min(paramInt2, paramArrayOfByte.length);
    /* 632 */       while ((j < k) && (paramArrayOfChar[paramInt1] < '€')) {
    /* 633 */         paramArrayOfByte[(j++)] = ((byte)paramArrayOfChar[(paramInt1++)]);
    /*     */       }
    /* 635 */       while (paramInt1 < i)
    /*     */       {
    /* 636 */         char c = paramArrayOfChar[(paramInt1++)];
    /* 637 */         if (c < '€-')
    /*     */         {
    /* 639 */           paramArrayOfByte[(j++)] = ((byte)c);
    /*     */         }
    /* 640 */         else if (c < 'ࠀ')
    /*     */         {
    /* 642 */           paramArrayOfByte[(j++)] = ((byte)(0xC0 | c >> '\006'));
    /* 643 */           paramArrayOfByte[(j++)] = ((byte)(0x80 | c & 0x3F));
    /*     */         }
    /* 644 */         else if (Character.isSurrogate(c))
    /*     */         {
    /* 645 */           if (this.sgp == null) {
    /* 646 */             this.sgp = new Surrogate.Parser();
    /*     */           }
    /* 647 */           int m = this.sgp.parse(c, paramArrayOfChar, paramInt1 - 1, i);
    /* 648 */           if (m < 0)
    /*     */           {
    /* 649 */             if (malformedInputAction() != CodingErrorAction.REPLACE) {
    /* 650 */               return -1;
    /*     */             }
    /* 651 */             paramArrayOfByte[(j++)] = replacement()[0];
    /*     */           }
    /*     */           else
    /*     */           {
    /* 653 */             paramArrayOfByte[(j++)] = ((byte)(0xF0 | m >> 18));
    /* 654 */             paramArrayOfByte[(j++)] = ((byte)(0x80 | m >> 12 & 0x3F));
    /* 655 */             paramArrayOfByte[(j++)] = ((byte)(0x80 | m >> 6 & 0x3F));
    /* 656 */             paramArrayOfByte[(j++)] = ((byte)(0x80 | m & 0x3F));
    /* 657 */             paramInt1++;
    /*     */           }
    /*     */         }
    /*     */         else
    /*     */         {
    /* 661 */           paramArrayOfByte[(j++)] = ((byte)(0xE0 | c >> '\f'));
    /* 662 */           paramArrayOfByte[(j++)] = ((byte)(0x80 | c >> '\006' & 0x3F));
    /* 663 */           paramArrayOfByte[(j++)] = ((byte)(0x80 | c & 0x3F));
    /*     */         }
    /*     */       }
    /* 666 */       return j;
    /*     */     }
    

     
     
     
     
     
     
    zookeeper와 차이가 많지 않고 비트 연산으로utf-8의 규칙을 실현한다.
    비교 코드에 대한 이해는 다음과 같습니다.
  • zookeeper에서는 3바이트의 변환을 실현했고java의 클래스는 4바이트의 변환을 실현했다.
  • 코드의 복잡도에서java는zookeeper보다 높다
  • 직관적으로 나는 구체적인 실현에 있어서 조키퍼가 비교적 높다는 것을 발견하지 못했다.
    여기까지utf-8의 실현은 끝났지만 여기는 나의 생각을 불러일으켰다.
  • zookeeper는 왜 스스로 서열화를 실현하고utf-8의 전환을 실현해야 하는가
  • 분포식 시스템을 스스로 개발하려면 이런 것들을 실현해야 하는가
  • 아마도 내가 끊임없이 zookeeper의 원본을 배우면 새로운 체험과 깨달음이 있을 것이다!목표를 세우고 꾸준히 하며 자신의 이해와 깨달음을 끊임없이 높여야만 과거의 자신을 뛰어넘을 수 있다!

    좋은 웹페이지 즐겨찾기