Szukam tagów id3 w pliku piosenki. Plik może zawierać znaczniki rozszerzone id3v1, id3v1 (znajdujące się na końcu pliku) oraz znaczniki id3v2 (zwykle umieszczone na początku). W przypadku znaczników id3v1 mogę użyć pliku File.read (plik_pliku) i wyciągnąć ostatnie 355 bajtów (128 + 227 dla rozszerzonego znacznika). Jednak w przypadku znaczników id3v2 muszę od początku przeszukać plik, szukając 10 bajtowego wzorca id3v2. Chciałbym uniknąć wielokrotnego otwierania i zamykania tego samego pliku wielokrotnie, gdy szukam różnych znaczników, więc pomyślałem, że najlepiej będzie użyć File.stream! (Song_file) i wysłać strumień plików do różnych funkcji, aby wyszukać różne tagi.Najbardziej efektywny sposób wyszukiwania plików dla wzorów bajtów w 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) Czy zapisuję dowolny plik wykonywalny, tworząc plik File.stream! raz i wysłanie go do różnych funkcji (będę skanował dziesiątki tysięcy plików, więc ważne jest zaoszczędzić trochę czasu)? Czy powinienem po prostu użyć File.read dla tagów id3v1 i File.stream! dla tagów id3v2?
2) pojawia się błąd w linii:
<< id3_extended_tag :: binary-size(227), id3_tag :: binary-size(128) >> = Stream.take(file_stream, -355)
ponieważ Stream.take (file_stream, -355) jest funkcją, a nie binarny. Jak mogę przekształcić go w plik binarny, który mogę dopasować do wzorca?
Nie mam dla ciebie odpowiedzi, ale gdybym był tobą, naprawdę unikałbym magicznych liczb. Zakładam, że -355 to suma 128 i 227? Gdybym był tobą, ustawiłbym atrybut modułu o nazwie "@ id_extended_tag_binsize" na 227 i "@ id3_tag_binsize" na 128, a następnie użyłbym tych atrybutów w Stream.take w ten sposób: Stream.take (strumień plików, - ('@ id_extended_tag_binsize' + '@ id3_tag_binsize')) Mniej podatny na błędy i znacznie łatwiejszy do odczytania i zrozumienia. –
Po pierwsze, File.stream musi zostać poinformowany, aby czytać bajty, a nie wiersze, używając składni File.stream! (Path, [: read],: bytes). Następnie nie sądzę, że -355 może być używany z Stream.take, ponieważ strumień nie jest listą, ale potencjalną listą, która musi zostać sfinalizowana za pomocą wywołania Stream.to_list. – GavinBrelstaff
Dzięki za sugestie. Zmieniłem odpowiednio swój kod. –