Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

การบรรจุและการเปิดออก:คู่มือการอ่านข้อมูลไบนารีใน Ruby

ในบทความนี้ คุณจะได้เรียนรู้เกี่ยวกับวิธีการแพ็คและแกะ Ruby!

แต่ทำไมเราต้องใช้วิธีเหล่านี้?

การทำงานกับข้อความง่ายกว่าการทำงานกับข้อมูลไบนารีมาก .

ข้อความช่วยให้คุณใช้:

  • นิพจน์ทั่วไป
  • วิธีการเช่น scan &match
  • gsub

แต่ถ้าคุณต้องการทำงานกับข้อมูลไบนารี มีงานพิเศษที่ต้องทำ นั่นคือที่มาของวิธีการ Array#pack &String#unpack

ผมขอแสดงตัวอย่างให้คุณดู โดยเริ่มจากสตริงธรรมดาแล้วไปยังสิ่งที่น่าสนใจกว่านี้

สตริงเป็นค่า ASCII

การดำเนินการนี้จะแปลงอักขระทุกตัวในสตริงให้เป็นค่าทศนิยม:

str = "AABBCC"
str.unpack("c*")

# [65, 65, 66, 66, 67, 67]

สังเกต "c*" อาร์กิวเมนต์สำหรับ unpack .

นี่คือ “สตริงรูปแบบ” ซึ่งบอก unpack จะทำอย่างไรกับข้อมูล ในกรณีนี้ c หมายถึงนำอักขระหนึ่งตัว &แปลงเป็นค่าจำนวนเต็ม (วิธี String#ord ก็ทำสิ่งนี้ด้วย)

เครื่องหมายดอกจัน * เพียงพูดว่า "ทำซ้ำรูปแบบนี้สำหรับข้อมูลอินพุตทั้งหมด"

แปลงเลขฐานสิบหกเป็นสตริง

H ใช้กับ pack วิธีให้เลขฐานสิบหกในการแปลงสตริง

ตัวอย่าง :

["414243"].pack("H*")
# "ABC"

"ABC".unpack("H*")
# ["414243"]

วิธีการแปลงเลขฐานสิบหกเป็นจำนวนเต็ม

สตริงรูปแบบนี้ใช้ข้อมูล 4 ไบต์และส่งคืนจำนวนเต็ม สิ่งหนึ่งที่ควรสังเกตคือไบต์เหล่านี้อยู่ในรูปแบบ “little-endian”

ตัวอย่าง :

"\xff\x00\x00\x00".unpack("l").first
# 255
"\x90\xC0\xDD\x08".unpack("l").first
# 148750480

ฉันใช้ first ที่นี่เพราะ unpack ส่งกลับอาร์เรย์

การแยกวิเคราะห์ไฟล์ไบนารีด้วยวิธีแกะกล่อง

คุณอ่านไฟล์ไบนารีเช่น EXE, PNG หรือ GZIP ได้อย่างไร

หากคุณอ่านไฟล์เหล่านี้เป็นข้อความธรรมดา คุณจะเห็นบางอย่างที่ดูเหมือนข้อมูลแบบสุ่ม…

การบรรจุและการเปิดออก:คู่มือการอ่านข้อมูลไบนารีใน Ruby

ไม่ใช่เรื่องบังเอิญ

มี โครงสร้างเอกสาร สำหรับรูปแบบไฟล์เหล่านี้มากมาย &unpack วิธีคือสิ่งที่คุณสามารถใช้อ่านข้อมูลนั้นและแปลงเป็นสิ่งที่มีประโยชน์

นี่คือตัวอย่าง :

binary_data     = "\x05\x00\x68\x65\x6c\x6c\x6f"
length, message = binary_data.unpack("Sa*")

# [5, "hello"]

ในตัวอย่างนี้ ข้อมูลไบนารี (แสดงเป็นเลขฐานสิบหก ซึ่งมีขนาดกะทัดรัดกว่า 1 วินาทีและ 0 วินาที) มีฟิลด์ความยาวสองไบต์ (16 บิต) ที่ประกอบด้วยความยาวของสตริงต่อไปนี้ จากนั้นก็มีสตริงนั้นเอง

เป็นเรื่องปกติมากที่ไฟล์ไบนารีและโปรโตคอลเครือข่ายไบนารีจะมีฟิลด์ "ความยาว"

นี้บอก parser ว่าควรอ่านกี่ไบต์ .

ใช่.

ฉันรู้ในตัวอย่างนี้ ฉันอ่านทั้งความยาวและข้อมูลในขั้นตอนเดียว เพื่อให้ทุกอย่างง่ายขึ้น

วิธีใช้ BinData Gem

นอกจากนี้ยังมี Bindata gem ซึ่งสร้างขึ้นโดยเฉพาะเพื่อช่วยคุณแยกวิเคราะห์โครงสร้างไบนารี

นี่คือตัวอย่าง :

class BinaryString < BinData::Record
  endian :little
  uint16 :len
  string :name, :read_length => :len
end

สังเกต read_length พารามิเตอร์. สิ่งนี้จะบอก bindata ให้คำนวณความยาวจากสนาม ดังนั้นมันจะช่วยให้คุณไม่ต้องทำงานมาก 🙂

ดังนั้นหากคุณต้องการเขียน parser สำหรับรูปแบบไบนารีใด ๆ นี่คือขั้นตอน:

  1. ค้นหาข้อกำหนดสำหรับรูปแบบนี้ (หากไม่ใช่แบบสาธารณะ คุณจะต้องทำวิศวกรรมย้อนกลับ ซึ่งเป็นหัวข้อทั้งหมดด้วยตัวเอง)
  2. เขียนคลาส `bindata` สำหรับทุกส่วนของไฟล์ (โดยปกติคุณจะพบส่วนหัวก่อนด้วย metadata แล้วตามด้วยหลายส่วนข้อมูล)
  3. อ่านข้อมูลและประมวลผลตามที่คุณต้องการ (เช่น ใน PNG คุณสามารถเปลี่ยนสีของภาพได้)
  4. กำไร!

หากคุณต้องการดูตัวอย่างแบบเต็มของ bindata ลองดูที่ตัวแยกวิเคราะห์ PNG ของฉันบน GitHub

การเข้ารหัส Base64

มีการเข้ารหัสประเภทนี้ที่เรียกว่า "Base64" คุณอาจเคยเห็นมันมาก่อนใน URL

หน้าตาประมาณนี้ :

U2VuZCByZWluZm9yY2VtZW50cw==

ค่าสองเท่าที่ส่วนท้ายมักจะเป็นสัญญาณบ่งบอกว่าคุณกำลังจัดการกับ Base64 แม้ว่าอินพุตบางอย่างอาจส่งผลให้ไม่มีสัญญาณเท่ากับ (ใช้เป็นช่องว่างภายใน)

ทำไมฉันถึงบอกคุณเรื่องนี้…

นอกจากจะเป็นประโยชน์ที่ควรรู้ด้วยตัวเองแล้วหรือยัง?

ปรากฎว่าคุณสามารถแปลงสตริงเป็น Base64 โดยใช้ pack วิธีการ

อย่างที่คุณเห็นที่นี่ :

def encode64(bin)
  [bin].pack("m")
end

encode64 "abcd"

# "YWJjZA==\n"

อันที่จริง นี่เป็นวิธีการที่แน่นอนที่ใช้ใน Base64 โมดูลจากไลบรารีมาตรฐาน

สรุป

ในโพสต์นี้ คุณได้เรียนรู้เกี่ยวกับ pack &unpack เมธอด ซึ่งช่วยให้คุณทำงานกับข้อมูลไบนารี คุณสามารถใช้สิ่งนี้เพื่อแยกวิเคราะห์ไฟล์ไบนารี แปลงสตริงเป็นค่า ASCII และสำหรับการเข้ารหัส Base64

อย่าลืม แชร์และติดตาม เพื่อให้คุณสามารถเพลิดเพลินกับการโพสต์บล็อกแบบนี้ได้มากขึ้น! 🙂