thrift hdfs api read/write binary error

環境:hadoop-0.20.2

當透過 HDFS Thrift 用 PHP/Python 寫檔案再讀二進制檔案時,會無法順利開啟讀出的檔案。

似乎是因為 Thrift 有支援一種 Binrary 的型態但是 hdfs 的 read/write[1] 都是用 String 的型態所造成的,

而在 hdfs 的 issue 中[2]有看到類似的問題,內文回覆的 Stuart Smith 提到相關的問題,並提供對應修改過的檔案供下載,

我沒仔細看他附檔的內容與回應,但在最後兩篇回覆中他提到了,可以在 read/write 透過 base64 encode/decode 來避免這個問題,

且他附上修改過的函式原始碼,應該跟附檔內修改的地方一樣,並且要多 import base64 的 library ,

按照他的修改,並且重新編譯後,接著修改 client(php/python) 端,在 write 前先 base64_encode() ,read 時 base64_decode(),問題就解決了。

額外一提他附檔的 hdfs.Thrift 就是將 read/write api 參數改成 binary 格式,但在此透過base64 以後編碼解碼以後就可以不必自行編譯 thrift 的 client 檔案了…


import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.EncoderException;
    /**
     * write to a file
     */
    public boolean write(ThriftHandle tout, String encodedData) throws ThriftIOException {
      try {
        now = now();
        HadoopThriftHandler.LOG.debug("write: " + tout.id);
        FSDataOutputStream out = (FSDataOutputStream)lookup(tout.id);
        Base64 base64 = new Base64();
        byte[] tmp = null;
        tmp = (byte[])base64.decode( (byte[]) encodedData.getBytes("UTF-8") );

        out.write(tmp, 0, tmp.length);
        HadoopThriftHandler.LOG.debug("wrote: " + tout.id);
        return true;
      } catch (IOException e) {
        throw new ThriftIOException(e.getMessage());
      }
    }

    /**
     * read from a file
     */
    public String read(ThriftHandle tout, long offset,
                       int length) throws ThriftIOException {
      try {
        now = now();
        HadoopThriftHandler.LOG.debug("read: " + tout.id +
                                     " offset: " + offset +
                                     " length: " + length);
        FSDataInputStream in = (FSDataInputStream)lookup(tout.id);
        if (in.getPos() != offset) {
          in.seek(offset);
        }
        byte[] tmp = new byte[length];
        int numbytes = in.read(offset, tmp, 0, length);
        HadoopThriftHandler.LOG.debug("read done: " + tout.id);
        try
        {
            Base64 base64 = new Base64();
            return new String( (byte[])base64.encode( (Object)tmp ), "UTF-8");
        }
        catch( EncoderException e )
        {
            e.printStackTrace();
            System.exit(0);
            return "";
        }
      } catch (IOException e) {
        throw new ThriftIOException(e.getMessage());
      }
    }

參考資源:

3 comments on “thrift hdfs api read/write binary error

  1. 😯 it is very helpful, but I am not sure what’s the use of hadoopfs.thrift, could u give me some clues? thanks.

  2. 你好,小弟我也想利用thrift透過php語法讀取HDFS上的東西
    ,可以麻煩你寄範例給我嗎?? 謝謝你。 🙂

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *