Percursos
/
Elixir
Elixir
/
Exercícios
/
Detetor de ficheiros
Detetor de ficheiros

Detetor de ficheiros

Exercício de aprendizagem

Introdução

Binários

O Elixir oferece uma sintaxe elegante para trabalhar com dados binários, como já vimos com a forma especial <<>> disponibilizada para trabalhar com bitstrings.

O tipo binário é uma especialização do tipo bitstring. Enquanto os bitstrings podem ter qualquer comprimento (qualquer número de bits), os binários são aqueles em que o número de bits é divisível por 8. Ou seja, quando trabalhamos com binários, pensamos muitas vezes em termos de bytes (8 bits). Um byte pode representar números inteiros de 0 a 255. É comum trabalhar com valores de byte em hexadecimal, 0x00 - 0xFF.

Os literais binários definem-se com a forma especial de bitstring <<>>. Ao definir um literal binário, podemos usar literais inteiros e de string. Valores inteiros superiores a 255 sofrem overflow e só os últimos 8 bits do inteiro são usados. Por predefinição, o modificador ::binary é aplicado ao valor. Podemos concatenar binários com o operador <>/2.

<<255>> == <<0xFF>>
# Overflowing bits are truncated
<<256>> == <<0>>
<<2, 4, 6, 8, 10, 12, 14, 16>> == <<0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10>>

Um null-byte é outro nome para <<0>>.

Pattern matching em dados binários

O pattern matching é até estendido aos binários, e podemos fazer pattern matching numa porção de dados binários, tal como faríamos com uma lista.

# Ignore the first 8 bytes, match and bind the remaining to `body`
<<_::binary-size(8), body::binary>>

Tal como acontece com outros tipos de pattern matching, podemos usar isto em assinaturas de funções para corresponder ao selecionar entre várias cláusulas de função.

Instruções

Tens estado a trabalhar num projeto que permite aos utilizadores carregar ficheiros para o servidor, para serem partilhados com outros utilizadores. Foi-te pedido que escrevas uma função para verificar se um carregamento corresponde ao seu tipo de media. Fazes alguma pesquisa e descobres que os primeiros bytes de um ficheiro são geralmente únicos desse tipo de ficheiro, o que lhe dá uma espécie de assinatura.

Usa a seguinte tabela como referência:

Tipo de ficheiro Extensão comum Tipo de media «assinatura» binária
ELF "exe" "application/octet-stream" 0x7F, 0x45, 0x4C, 0x46
BMP "bmp" "image/bmp" 0x42, 0x4D
PNG "png" "image/png" 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A
JPG "jpg" "image/jpg" 0xFF, 0xD8, 0xFF
GIF "gif" "image/gif" 0x47, 0x49, 0x46

1. Dada uma extensão, devolve o tipo de media esperado

Implementa a função type_from_extension/1. Deve receber uma extensão de ficheiro (string) e devolver o tipo de media (string), ou nil se a extensão não corresponder às esperadas.

FileSniffer.type_from_extension("exe")
# => "application/octet-stream"

FileSniffer.type_from_extension("txt")
# => nil

2. Dado um ficheiro binário, devolve o tipo de media esperado

Implementa a função type_from_binary/1. Deve receber um ficheiro (binário) e devolver o tipo de media (string), ou nil se a assinatura do ficheiro não corresponder às esperadas.

file = File.read!("application.exe")
FileSniffer.type_from_binary(file)
# => "application/octet-stream"

file = File.read!("example.txt")
FileSniffer.type_from_binary(file)
# => nil

Não te preocupes em ler o ficheiro como binário. Assume que isso já foi feito por ti e que é fornecido pelos testes como argumento.

3. Dada uma extensão e um ficheiro binário, verifica se o ficheiro corresponde ao tipo esperado

Implementa a função verify/2. Deve receber um ficheiro (binário) e uma extensão (string) e devolver um tuplo :ok ou :error.

file = File.read!("application.exe")

FileSniffer.verify(file, "exe")
# => {:ok, "application/octet-stream"}

FileSniffer.verify(file, "png")
# => {:error, "Warning, file format and file extension do not match."}
Editar via GitHub A ligação abre numa nova janela ou separador
Elixir Exercism

Estás pronto para começar Detetor de ficheiros?

Inscreve-te no Exercism para aprenderes e dominares Elixir com 58 conceitos168 exercícios, e mentoria humana real, tudo grátis.