Haskell Network.HTTP некорректно загружает изображение

Я пытаюсь загружать изображения с помощью модуля Network.HTTP и не имеет большого успеха.

import Network.HTTP

main = do
  jpg <- get "http://www.irregularwebcomic.net/comics/irreg2557.jpg"
  writeFile "irreg2557.jpg" jpg where
       get url = simpleHTTP (getRequest url) >>= getResponseBody

Выходной файл появляется в текущем каталоге, но не отображается под хром или ристретто. Отчеты Ristretto "Ошибка интерпретации файла изображения JPEG (Не файл JPEG: начинается с 0c3 0xbf)".

Ответ 1

writeFile :: FilePath -> String -> IO ()

String. Это ваша проблема, прямо здесь. String - для текста в Юникоде. Попытка хранить двоичные данные в нем приведет к коррупции. В этом случае неясно, выполняется ли коррупция с помощью simpleHTTP или writeFile, но в конечном итоге это неважно. Вы используете неправильный тип, и что-то искажает данные при столкновении с байтами, которые не образуют допустимую кодировку в формате Юникода.

Что касается исправления этого, более новые версии HTTP являются полиморфными по типу возвращаемого значения и могут обрабатывать возврат необработанных байтов в ByteString. Вам просто нужно изменить способ записи байтов в файл, чтобы он не сделал вывод, что вы хотите String.

import qualified Data.ByteString as B
import Network.HTTP
import Network.URI (parseURI)

main = do
    jpg <- get "http://www.irregularwebcomic.net/comics/irreg2557.jpg"
    B.writeFile "irreg2557.jpg" jpg
  where
    get url = let uri = case parseURI url of
                          Nothing -> error $ "Invalid URI: " ++ url
                          Just u -> u in
              simpleHTTP (defaultGETRequest_ uri) >>= getResponseBody

Конструкция для получения полиморфного запроса немного неуклюжа. Если проблема № 1 будет исправлена, то использование getRequest url будет достаточным.