2015-05-20 3 views
2

Я пытаюсь перенести некоторый код на Common Lisp (подробности, вероятно, не имеют значения, но я пытаюсь прочитать файл изображения rgb в блоке памяти, чтобы связать текстуру для использования с cl-opengl). Версия C, что я пытаюсь сделать, это:Что такое обычный Lisp-эквивалент F-функции?

void * data; 
FILE * file; 
int bytecount = width * height * 3; 
file = fopen (rgbfilepath, "rb"); 
data = malloc(bytecount); 
fread(data, bytecount, file); 
fclose(file); 
//do stuff with data... 

Прошло несколько лет с тех пор я сделал это, но мое понимание этого кода является то, что он читает кучу байт из файла в память malloc, не обращая внимания на содержимое этих байтов.

После некоторых поисковых запросов я нашел http://rosettacode.org/wiki/Read_entire_file#Common_Lisp и http://www.codecodex.com/wiki/Read_a_file_into_a_byte_array#Common_Lisp, которые очень похожи. Моя версия выглядит

(with-open-file (stream rgb-file-path) 
    (let ((data (make-string (file-length stream))) 
    (read-sequence data stream) 
    ;;do stuff with data... 

Когда я запускаю эту вещь на файл РГБ, я получаю жалобы от SBCL:

debugger invoked on a SB-INT:STREAM-DECODING-ERROR in thread 
#<THREAD "main thread" RUNNING {10055E6EA3}>: 
    :UTF-8 stream decoding error on 
    #<SB-SYS:FD-STREAM 
    for "file /home/john/code/lisp/commonlisp/opengl-practice/wall.rgb" 
    {1005A8EB53}>: 

    the octet sequence #(218 0) cannot be decoded. 

Моей спекулятивная интерпретация этого является то, что использование make-string ожидает байты чтобы быть символами, в то время как в файле rgb, который я загружаю, есть куча байтов, не обязательно действительный ASCII или любой другой набор символов. Но я мог бы уйти. Любые предложения о том, как дублировать то, что делает fread()?

Заранее благодарен!

ответ

0

Если вы действительно хотите сделать это сырое, вам нужно указать element-type к open (или with-open-file), который является подтипом integer (скорее всего, что-то вроде '(unsigned-byte 8) так, что читается как октет вместо символов.

Я бы использовал библиотеку для чтения изображений. В прошлом я использовал opticl, что довольно просто и использует двумерные или трехмерные простые массивы для представления данных изображения (два измерения плюс один для цветов).

+0

Я буду смотреть в opticl точно, но сейчас я просто пытаюсь получить такую ​​же функциональность от CL-OpenGL, что я знаю, как получить в C. –

+0

Спасибо за отзыв. Начиная с '(setf mystream (открыть« wall.rgb »: direction: input: element-type '(unsigned-byte 8)))' Кажется, что следующим шагом в этой аналогии будет сказать '(setf data (make-sequence '(unsigned-byte 8) (поток длины файла))) ' , но это дает мне ошибку ' (UNSIGNED-BYTE 8) является спецификатором плохого типа для последовательностей. ' Я буду вернемся скоро, если я что-то придумаю. –

+0

Прочитайте документацию CLHS для функций, которые вы используете. Я рекомендую использовать здесь 'make-array'. – Svante

0

Большое спасибо Сванте за то, что он вел меня в правильном направлении. Вот что сработало:

(setf mystream (open rgb-file-name :direction :input :element-type '(unsigned-byte 8))) 
(setf data (make-array (file-length mystream) :element-type '(unsigned-byte 8))) 
(read-sequence data mystream) 
(close mystream) 
+0

Если во время чтения указано условие, поток не будет закрыт. Лучше использовать 'open-file' вместо' open' и 'close'. Кроме того, похоже, что вы работаете с несвязанными переменными. Я бы ожидал привязки 'let' вместо форм' setf'. – Svante

+0

Итак, я предлагаю следующее улучшение: '(defun read-rgb-file (filename) (с открытым файлом (mystream filename: direction: input: element-type) (unsigned-byte 8): if-does-not -exist: error) (let ((data (make-array (file-length mystream): element-type '(unsigned-byte 8)))) (данные данных о чтении данных))) ' – Svante

Смежные вопросы