Как преобразовать последовательность в байт [] в Clojure? - PullRequest
5 голосов
/ 10 августа 2010

Мне нужно записать необработанные байты в файл. Я делаю это с:

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

... где байты должны иметь тип 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))))

Ответы [ 3 ]

6 голосов
/ 10 августа 2010

Существует также функция байтового массива.

Если вам нужно упаковать байтовый массив, вы можете проверить http://github.com/geoffsalmon/bytebuffer или напрямую использовать базовый Java ByteBuffer.

3 голосов
/ 10 августа 2010

Обновление: новая часть вопроса ("ПРОДОЛЖЕНИЕ") получена в конце.


Просто чтобы прояснить, что на самом деле происходит здесь:

Этот вопрос на самом деле иллюстрирует интересный момент: функции приведения массива - bytes, ints, ... - не являются и не могут использоваться в качестве функций преобразования .Они приводятся только к целевому типу, что означает, в частности, что входные данные для bytes уже должны быть массивом соответствующего типа.

Это имеет смысл, поскольку преобразование из int[] в long[] не являетсяпросто посмотреть на цифры в ином свете - вам также нужно было бы выделить другое количество памяти для массива - чтобы можно было просто посмотреть, посмотрев на оператора, является ли рассматриваемая операция преобразованием илиприведение - хорошая вещь.

Причина, по которой приведение полезно в динамическом языке, таком как Clojure, связана с эффективностью (вы можете использовать приведение рядом с подсказками типов, чтобы ускорить процесс) и взаимодействием (где вам часто нужновещь просто правильного типа).Причина, по которой компилятор не может просто определить правильный тип массива, заключается в том, что не всегда достаточно информации для этого (не говоря уже о том, что может быть даже неясно, каким может быть «правильный» тип).

Чтобы исправить фрагмент, о котором идет речь, можно использовать либо Byte/TYPE (как предложено Йереном), либо пропустить into-array и bytes и вместо этого обернуть filter в bytes-array (как предлагает Брентон Эшворт).


Проблема с кодом, включенным в текст вопроса, заключается в том, что он открывает 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)))
3 голосов
/ 10 августа 2010
(into-array Byte/TYPE (filter #(not (= % 13)) (.getBytes (slurp "e:/vpn.bat"))))

Если вы не против иметь в качестве посредника строку, хотя я думаю, что вы можете заменить часть .getBytes на to-byte-array

Я думаю, проблема в том, что (bytes) ожидает массив примитивного типа. Если вы не укажете это для (into-array), он вернет упакованный тип.

...