如何在 Clojure 中将序列转换为 byte[]?

发布于 2024-09-13 17:16:22 字数 791 浏览 2 评论 0原文

我需要将原始字节写入文件。我这样做的是:

(.write (FileOutputStream "/path") bytes)

...其中字节必须是 byte[] 类型。请注意它不能是Byte[]。

我尝试使用(字节)和/或(到数组)函数转换我的序列,但感到沮丧,一个例子:

user=> (bytes (into-array (filter #(not (= % 13)) (to-byte-array (File. "e:/vpn.bat")))))
java.lang.ClassCastException: [Ljava.lang.Byte; cannot be cast to [B (NO_SOURCE_FILE:0)

继续:

带有 Byte/TYPE 的到数组工作正常。然而,字节数组却没有。文件变空:

(import 'FileOutputStream)
(use 'clojure.contrib.io)

(defn remove-cr-from-file [file]
  (with-open [out (FileOutputStream. file)]
    (let [dirty-bytes (to-byte-array file)
          clean-seq   (filter #(not (= 13 %)) dirty-bytes)
          clean-bytes (byte-array clean-seq)]
      (.write out clean-bytes))))

I need to write raw bytes to the file. I do it with:

(.write (FileOutputStream "/path") bytes)

...where bytes must be of type byte[]. Please note it cannot be Byte[].

I tried to convert my sequence with both (bytes) and/or (into-array) functions and got frustrated, one example:

user=> (bytes (into-array (filter #(not (= % 13)) (to-byte-array (File. "e:/vpn.bat")))))
java.lang.ClassCastException: [Ljava.lang.Byte; cannot be cast to [B (NO_SOURCE_FILE:0)

CONTINUED:

The into-array with Byte/TYPE works fine. However, the byte-array does not. The file gets empty:

(import 'FileOutputStream)
(use 'clojure.contrib.io)

(defn remove-cr-from-file [file]
  (with-open [out (FileOutputStream. file)]
    (let [dirty-bytes (to-byte-array file)
          clean-seq   (filter #(not (= 13 %)) dirty-bytes)
          clean-bytes (byte-array clean-seq)]
      (.write out clean-bytes))))

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

少女的英雄梦 2024-09-20 17:16:22

还有字节数组函数。

如果需要打包字节数组,您可以查看 http://github.com/geoffsalmon/bytebuffer 或者直接使用底层的 Java ByteBuffer 东西。

There is also the byte-array function.

If need to get into packing the byte array you can check out http://github.com/geoffsalmon/bytebuffer or use the underlying Java ByteBuffer stuff directly.

人事已非 2024-09-20 17:16:22

更新:问题的新部分(“继续”)在最后得到了回答。


只是为了弄清楚这里实际发生了什么:

这个问题实际上说明了一个有趣的点:数组转换函数 -- 字节整数、... -- 不是也不能用作转换函数。它们仅转换为目标类型,这特别意味着 bytes 的输入必须已经是适当类型的数组。

这是有道理的,因为从 int[] 转换为 long[] 并不是从不同角度查看数字的简单问题 - 您还必须分配数组的存储量不同——因此,只需查看运算符即可判断所讨论的操作是转换还是强制转换,这是一件好事。

强制转换在 Clojure 等动态语言中有用的原因与效率(您可以将强制转换与类型提示一起使用来加快速度)和互操作(您通常需要正确类型的东西)有关。编译器不能仅仅推断出正确的数组类型的原因是因为并不总是有足够的信息来这样做(更不用说甚至可能不清楚“正确”的类型可能是什么)。

要修复有问题的代码片段,可以使用 Byte/TYPE (如 Jieren 建议的那样)或跳过 into-arraybytes 和将 filter 包装在 bytes-array 中(按照 Brenton Ashworth 的建议)。


问题文本中新包含的代码的问题在于,它在读取文件内容之前在文件上打开一个 FileOutputStream 。打开 FOS 的行为已经清除了文件:

(with-open [out (FileOutputStream. some-file)]
  :foo)

; => :foo
; side effect: some-file is now empty

您必须从 with-open 之外的文件中读取:

(let [foo (byte-array
           (filter #(not= 13 %)
                   (to-byte-array some-file)))]
  (with-open [out (FileOutputStream. some-file)]
    (.write out foo)))

Update: the new part of the question ("CONTINUED") is answered towards the end.


Just to make it clear what actually happens here:

This question actually illustrates an interesting point: the array cast functions -- bytes, ints, ... -- are not and cannot be used as conversion functions. They only cast to the target type, meaning in particular that the input to bytes must already be an array of appropriate type.

This makes sense, since converting from int[] to long[] is not a simple matter of viewing the numbers in a different light -- you'd also have to allocate a different amount of storage for the array -- so being able to tell just by looking at the operator whether the operation in question is a conversion or a cast is a Good Thing.

The reason why casts are useful in a dynamic language such as Clojure has to do with efficiency (you can use casting alongside type hints to speed things up) and interop (where you often need a thing of just the right type). The reason why the compiler can't just infer the correct array type is because there is not always enough information to do so (not to mention it might not even be clear what the "correct" type might be).

To fix the snippet in question, one could use either Byte/TYPE (as suggested by Jieren) or skip the into-array and bytes and wrap the filter in bytes-array instead (as suggested by Brenton Ashworth).


The problem with the code newly included in the question text is that it opens a FileOutputStream on the file prior to reading its contents. The act of opening the FOS already clears the file:

(with-open [out (FileOutputStream. some-file)]
  :foo)

; => :foo
; side effect: some-file is now empty

You'll have to read from the file outside the with-open:

(let [foo (byte-array
           (filter #(not= 13 %)
                   (to-byte-array some-file)))]
  (with-open [out (FileOutputStream. some-file)]
    (.write out foo)))
哀由 2024-09-20 17:16:22
(into-array Byte/TYPE (filter #(not (= % 13)) (.getBytes (slurp "e:/vpn.bat"))))

如果您不介意使用字符串作为中介,尽管我认为您可以将 .getBytes 部分替换为 to-byte-array

我认为问题在于(bytes) 需要原始类型数组。如果您没有将其指定为(into-array),它将返回装箱类型。

(into-array Byte/TYPE (filter #(not (= % 13)) (.getBytes (slurp "e:/vpn.bat"))))

If you don't mind having a string as an intermediary, although I think you can replace the .getBytes part with your to-byte-array

I think the problem is that (bytes) expects the primitive type array. If you don't specify this to (into-array), it's going to return the boxed type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文