将java currentTimeMillis转换为字节的clojure向量

时间:2014-05-05 03:14:51

标签: java clojure bytebuffer

我有一个函数试图将从JVM上可用的currentTimeMillis方法获得的时间(以毫秒为单位)转换为带符号字节的向量。它在大多数情况下看起来很好,除了一个小问题 - 在达到前8位的最大字节值后,并不总是正确地增加第n个字节位置。这是一个示例字节序列:

[0 0 1 69 74 87 123 56]
[0 0 1 69 74 87 123 56]
[0 0 1 69 74 87 123 56]
[0 0 1 69 74 87 123 56]
[0 0 1 69 74 87 123 57]
[0 0 1 69 74 87 123 57]
[0 0 1 69 74 87 123 57]
[0 0 1 69 74 87 123 57]
[0 0 1 69 74 87 123 57]
[0 0 1 69 74 87 123 57]
[0 0 1 69 74 87 1 64]
[0 0 1 69 74 87 1 64]
[0 0 1 69 74 87 1 64]
[0 0 1 69 74 87 1 64]
[0 0 1 69 74 87 1 65]
[0 0 1 69 74 87 1 65]
[0 0 1 69 74 87 1 65]
[0 0 1 69 74 87 1 65]
[0 0 1 69 74 87 1 65]
[0 0 1 69 74 87 1 66]
[0 0 1 69 74 87 1 66]

糟糕。正如您所看到的,右边的第六个字节没有增加到88.这似乎并不是一直发生 - 有时它会正确地增加字节。这将是一个问题,因为我将此值发送到服务器,该服务器要求将时间间隔作为必须不断递增的字节值序列。

以下是我用来生成此代码的代码:

(def max-signed-bytes 128)

(defn byte-at
  "Shifts x by a given number of bits"
  [x offset]
  (mod (bit-shift-right x offset) max-signed-bytes))

(defn Long->bytes
  "Convert a 64-bit integer into a byte vector"
  [^Long x]
  (conj []
        (byte-at x 56)
        (byte-at x 48)
        (byte-at x 40)
        (byte-at x 32)
        (byte-at x 24)
        (byte-at x 16)
        (byte-at x 8)
        (mod x max-signed-bytes)))

(defn time->bytes
  "Returns the current time in milliseconds as a byte vector"
  []
  (Long->bytes (System/currentTimeMillis)))

我尝试使用256对无符号字节值进行修改,但它似乎不会遇到此问题。但是,我需要一个带符号的字节值才能将内容填充到字节数组中,因为我最终需要使用DataOutputStream的{​​{1}}方法编写一个字节数组。

1 个答案:

答案 0 :(得分:3)

从long获取字节数组的最简单方法可能是

(defn num->bytes [n] (.toByteArray (biginteger n)))

但是,由于您的修改指定您使用的是DataOutputStream,因此请直接使用writeLong method

so.core=>(def buffer (java.io.ByteArrayOutputStream.))
#'so.core/buffer
so.core=> (def data-stream (java.io.DataOutputStream. buffer))
#'so.core/data-stream
so.core=> (.writeLong data-stream 257)
nil
so.core=> (.toByteArray buffer)
#<byte[] [B@6ea4b78b>
so.core=> (vec *1)
[0 0 0 0 0 0 1 1]

您的代码问题与您在编辑中诊断出的一样。您需要模数超过可能的字节值数256,而不是最大有符号值128.否则,您将两个字节值映射到相同的数字(= (mod 127 128) (mod -1 128)) ;=> true。转换为字节将签名(.byteValue (mod 255 256)) ;=> -1