Sto cercando i tag id3 in un file di song. Un file può avere tag id3v1, id3v1 estesi (situati alla fine del file) e tag id3v2 (solitamente situati all'inizio). Per i tag id3v1, posso usare File.read (song_file) ed estrarre gli ultimi 355 byte (128 + 227 per il tag esteso). Tuttavia, per i tag id3v2, ho bisogno di cercare il file dall'inizio cercando un pattern id3v2 da 10 byte. Voglio evitare qualsiasi overhead dall'apertura e chiusura dello stesso file ripetutamente mentre cerco i vari tag, quindi ho pensato che il modo migliore sarebbe stato usare File.stream! (File_file) e inviare il flusso di file a diverse funzioni per cercare i diversi tag.Il modo più efficace per cercare file per i pattern di byte in Elixir
def parse(file_name) do
file_stream = File.stream!(file_name, [], 1)
id3v1_tags(file_stream)
|> add_tags(id3v2_tags(file_stream))
end
def id3v1_tags(file_stream) do
tags = Tags%{} #struct containing desired tags
<< id3_extended_tag :: binary-size(227), id3_tag :: binary-size(128) >> = Stream.take(file_stream, -355)
id3_tag = to_string(id3_tag)
if String.slice(id3_tag,0, 3) == "TAG" do
Map.put(tags, :title, String.slice(id3_tag, 3, 30))
Map.put(tags, :track_artist, String.slice(id3_tag, 33, 30))
...
end
if String.slice(id3_extended_tag, 0, 4) == "TAG+" do
Map.put(tags, :title, tags.title <> String.slice(id3_extended_tag, 4, 60))
Map.put(tags, :track_artist, tags.track_artist <> String.slice(id3_extended_tag, 64, 60))
...
end
end
def id3v2_tags(file_stream) do
search for pattern:
<<0x49, 0x44, 0x33, version1, version2, flags, size1, size2, size3, size4>>
end
1) Sto salvando qualsiasi runtime creando il file.stream! una volta e inviandolo alle diverse funzioni (eseguirò la scansione di decine di migliaia di file, quindi è importante risparmiare un po 'di tempo)? O dovrei semplicemente usare File.read per i tag id3v1 e File.stream! per i tag id3v2?
2) ottengo un errore nella riga:
<< id3_extended_tag :: binary-size(227), id3_tag :: binary-size(128) >> = Stream.take(file_stream, -355)
perché Stream.take (file_stream, -355) è una funzione, non un binario. Come faccio a trasformarlo in un file binario che posso associare?
Non ho una risposta per te ma se fossi in te, eviterei davvero i numeri magici. Sto assumendo che il -355 sia la somma di 128 e 227? Se fossi in te, imposterei un attributo di modulo chiamato "@ id_extended_tag_binsize" a 227 e "@ id3_tag_binsize" a 128 e quindi userei quegli attributi nello Stream.take in questo modo: Stream.take (file_stream, - ('@ id_extended_tag_binsize' + '@ id3_tag_binsize')) Meno errori inclini e molto più facili da leggere e capire. –
Prima di tutto, File.stream deve essere detto di leggere byte anziché righe usando la sintassi File.stream! (Path, [: read],: bytes). Quindi non penso che il -355 possa essere usato con Stream.take dal momento che stream non è una lista ma una lista potenziale che deve essere finalizzata con una chiamata Stream.to_list. – GavinBrelstaff
Grazie per i suggerimenti. Ho cambiato il mio codice di conseguenza. –