2015-05-27 15 views
5

Tôi đang tìm kiếm thẻ id3 trong tệp bài hát. Một tệp có thể có thẻ mở rộng id3v1, id3v1 (nằm ở cuối tệp) cũng như thẻ id3v2 (thường nằm ở đầu). Đối với các thẻ id3v1, tôi có thể sử dụng File.read (song_file) và kéo ra 355 byte cuối cùng (128 + 227 cho thẻ mở rộng). Tuy nhiên, đối với các thẻ id3v2, tôi cần phải tìm kiếm thông qua các tập tin từ đầu tìm kiếm một mẫu id3v2 10 byte. Tôi muốn tránh bất kỳ chi phí nào từ việc mở và đóng cùng một tệp khi tôi tìm kiếm các thẻ khác nhau, vì vậy tôi nghĩ cách tốt nhất là sử dụng File.stream! (Song_file) và gửi luồng tệp đến các chức năng khác nhau để tìm kiếm các thẻ khác nhau.Cách hiệu quả nhất để tìm kiếm tệp mẫu byte trong 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) Tôi có lưu bất kỳ thời gian chạy nào bằng cách tạo File.stream không! một lần và gửi nó đến các chức năng khác nhau (tôi sẽ quét hàng chục ngàn tập tin, vì vậy tiết kiệm một chút thời gian là quan trọng)? Hoặc tôi chỉ nên sử dụng File.read cho các thẻ id3v1 và File.stream! cho các thẻ id3v2?

2) Tôi nhận được một lỗi trong dòng:

<< id3_extended_tag :: binary-size(227), id3_tag :: binary-size(128) >> = Stream.take(file_stream, -355) 

vì Stream.take (file_stream, -355) là một chức năng, không phải là một nhị phân. Làm cách nào để biến nó thành dạng nhị phân mà tôi có thể khớp mẫu?

+0

Tôi không có câu trả lời cho bạn nhưng nếu tôi là bạn, tôi thực sự sẽ tránh được số ma thuật. Tôi giả định -355 là tổng của 128 và 227? Nếu tôi là bạn tôi muốn đặt một thuộc tính mô-đun gọi là '@ id_extended_tag_binsize' thành 227 và' @ id3_tag_binsize' thành 128 và sau đó sử dụng các thuộc tính đó trong Stream.take như sau: Stream.take (file_stream, - ('@ id_extended_tag_binsize' + '@ id3_tag_binsize')) Dễ bị lỗi và dễ đọc hơn nhiều. –

+0

Trước hết, File.stream cần được thông báo để đọc byte thay vì các dòng sử dụng cú pháp File.stream! (Đường dẫn, [: đọc],: byte). Tiếp theo, tôi không nghĩ rằng -355 có thể được sử dụng với Stream.take vì luồng không phải là danh sách mà là danh sách tiềm năng cần được hoàn thành với lệnh gọi Stream.to_list. – GavinBrelstaff

+0

Cảm ơn các đề xuất. Tôi đã thay đổi mã của mình cho phù hợp. –

Trả lời

6

Tôi tin rằng việc triển khai của bạn đang phức tạp không cần thiết do sự phụ thuộc vào luồng. Làm cho nó hoạt động, làm cho nó đẹp sau đó làm cho nó nhanh (nhưng chỉ khi cần thiết).

Để đơn giản, trước tiên tôi sẽ tải mọi thứ vào bộ nhớ. Chỉ cần sử dụng File.read!/1. Sau đó, bạn có thể sử dụng các hàm trong: mô-đun nhị phân để tìm kiếm các mẫu (:binary.match/2), tách nó (:binary.split/2) hoặc lấy một phần nhất định (:binary.part/3). Không cần phải trộn File.stream và File.read nữa, chỉ cần đọc nó một lần và vượt qua cùng một nhị phân xung quanh.

Ngoài ra, rất quan trọng, không sử dụng mô-đun Chuỗi. Chuỗi có nghĩa là làm việc mã nhị phân UTF-8. Bạn muốn sử dụng mô-đun nhị phân cho tất cả các hoạt động cấp byte.

Cuối cùng, Stream.take/2 luôn trả về các hàm do lười. Bạn muốn sử dụng Enum.take/2 thay vào đó (nó chấp nhận luồng dưới dạng luồng cũng được liệt kê). Mặc dù, như tôi đã nói, tôi sẽ bỏ qua toàn bộ nội dung của luồng.

+0

Tôi đánh giá cao câu trả lời. Tôi sẽ lấy lời khuyên của bạn và sử dụng File.read!/1. Tôi không biết điều đó về mô-đun Chuỗi. Tôi nghĩ rằng nếu các byte là ký tự, thì bạn có thể coi chúng là một trong hai tập tin nhị phân hoặc chuỗi. –

Các vấn đề liên quan