बाइनरी डेटा के साथ काम करने के लिए Elixir एक सुंदर सिंटैक्स देता है, जैसा हमने <<>> स्पेशल फॉर्म में देखा है, जो बिटस्ट्रिंग के साथ काम करने के लिए दिया गया है।
बाइनरी टाइप, बिटस्ट्रिंग टाइप का ही एक विशेष रूप है। बिटस्ट्रिंग किसी भी लंबाई की हो सकती हैं (किसी भी संख्या में बिट), जबकि बाइनरी में बिटों की संख्या 8 से पूरी तरह विभाजित हो सकती है। यानी बाइनरी के साथ काम करते समय हम चीज़ों को अक्सर बाइट (8 बिट) के रूप में सोचते हैं। एक बाइट 0 से 255 तक के पूर्णांक दर्शा सकता है। बाइट की वैल्यू के साथ हेक्साडेसिमल में काम करना आम बात है, 0x00 - 0xFF.
बाइनरी लिटरल, बिटस्ट्रिंग के स्पेशल फॉर्म <<>> की मदद से बनाए जाते हैं। बाइनरी लिटरल बनाते समय हम पूर्णांक और स्ट्रिंग लिटरल इस्तेमाल कर सकते हैं। 255 से बड़ी पूर्णांक वैल्यू ओवरफ्लो हो जाती है और तब पूर्णांक के सिर्फ अंतिम 8 बिट ही इस्तेमाल होते हैं। डिफ़ॉल्ट रूप से वैल्यू पर ::binary मॉडिफायर लागू होता है। हम <>/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>>
नल-बाइट <<0>> का दूसरा नाम है।
पैटर्न मैचिंग तो बाइनरी तक भी बढ़ा दी गई है, और हम बाइनरी डेटा के किसी एक हिस्से पर भी पैटर्न मैच कर सकते हैं, ठीक वैसे ही जैसे हम ऐरे पर कर सकते हैं।
# Ignore the first 8 bytes, match and bind the remaining to `body`
<<_::binary-size(8), body::binary>>
पैटर्न मैचिंग के बाकी तरीकों की तरह, हम इसे फंक्शन सिग्नेचर में भी इस्तेमाल कर सकते हैं, ताकि कई फंक्शन क्लॉज़ में से चुनते समय मैच किया जा सके।
आप एक ऐसे प्रोजेक्ट पर काम कर रहे हैं जिसमें उपयोगकर्ता सर्वर पर फाइलें अपलोड कर सकते हैं, ताकि वे उन्हें दूसरे उपयोगकर्ताओं के साथ साझा कर सकें। आपको एक फंक्शन लिखने का काम दिया गया है जो यह जाँचता है कि अपलोड की गई फाइल उसके मीडिया टाइप से मेल खाती है या नहीं। थोड़ी खोज करने पर आपको पता चलता है कि किसी फाइल के पहले कुछ बाइट आम तौर पर उसी फाइल टाइप के लिए खास होते हैं, यानी वे उस फाइल को एक तरह का सिग्नेचर देते हैं।
संदर्भ के लिए यह तालिका देखिए:
| फाइल टाइप | आम एक्सटेंशन | मीडिया टाइप | बाइनरी 'सिग्नेचर' |
|---|---|---|---|
| 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 |
type_from_extension/1 फंक्शन बनाइए। यह एक फाइल एक्सटेंशन (स्ट्रिंग) लेता है और उसका मीडिया टाइप (स्ट्रिंग) लौटाता है, या nil लौटाता है अगर एक्सटेंशन उन अपेक्षित एक्सटेंशन में से कोई न हो।
FileSniffer.type_from_extension("exe")
# => "application/octet-stream"
FileSniffer.type_from_extension("txt")
# => nil
type_from_binary/1 फंक्शन बनाइए। यह एक फाइल (बाइनरी) लेता है और उसका मीडिया टाइप (स्ट्रिंग) लौटाता है, या nil लौटाता है अगर फाइल का सिग्नेचर उन अपेक्षित सिग्नेचर में से किसी से मेल न खाए।
file = File.read!("application.exe")
FileSniffer.type_from_binary(file)
# => "application/octet-stream"
file = File.read!("example.txt")
FileSniffer.type_from_binary(file)
# => nil
फाइल को बाइनरी के रूप में पढ़ने की चिंता न कीजिए। मान लीजिए कि यह काम पहले ही आपके लिए किया जा चुका है और टेस्ट इसे आर्गुमेंट के रूप में देते हैं।
verify/2 फंक्शन बनाइए। यह एक फाइल (बाइनरी) और एक्सटेंशन (स्ट्रिंग) लेता है और एक :ok या :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."}
Exercism पर साइन अप कीजिए और Elixir को 58 कॉन्सेप्ट168 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।