Alessandro Aguilar
Alessandro Aguilar

Reputation: 401

Write bytes to file from Huffman encoding algorithm

I'm learning Haskell and as first challenge I chose to write an implementation of Huffman coding, the algorithm is almost done, only the part of read and write the file to a byte file is missing. What I need to do is a way to write a file based on the binary string I build.

For example, If a read from a txt file the following string Hello, after the huffman algorithm, I get the following Map which map the symbol to his binary number as string

[
  ("H": "110"),
  ("e": "111"),
  ("l": "0"),
  ("o": "10")
]

And I need to replace that bytes in the readed string and write as Bytes that binary numbers to a file, I tried to use the ByteString package and the writeFile function, but the function write the binary numbers as plain text and not as Bytes.

So that way Hello pass to be 110111010 that should be write as Bytes to a file.

Upvotes: 1

Views: 196

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477666

You can write a string of '0's and '1's to a file with writeFile :: FilePath -> String -> IO (). For example:

main :: IO ()
main = writeFile "out.txt" "110111010"

You can also convert eight bits to a Word8 and then write the ByteString to a file with the WriteFile :: FilePath -> ByteString -> IO () of the Data.ByteString module:

import Data.ByteString(writeFile, pack)
import Data.Word(Word8)

writeWord8s :: [Word8] -> IO ()
writeWord8s = writeFile "out.txt" . pack

You can convert a list of Bools to Word8s, but then this has to be a multiple of eight. You can for example "pad" it with 0s (or 1s, or something else), but it should be a multiple of eight:

import Data.Bool(bool)
import Data.Bits((.|.), shiftL)
import Data.Word(Word8)

toWord8 :: [Bool] -> Word8
toWord8 = foldl ((. bool 0 1) . (.|.) . (`shiftL` 1)) 0

pack8pad0 :: [Bool] -> [Word8]
pack8pad0 [] = []
pack8pad0 xs
    | null ys = [toWord8 (y ++ replicate (8 - length y) False)]
    | otherwise = toWord8 y : pack8pad0 ys
    where (y, ys) = splitAt 8 xs

I leave mapping the input to a String of '0's and '1's as an exercise.

Upvotes: 1

Related Questions