ในโปรแกรมที่ผมกำลังทำอยู่ตอนนี้ จำเป็นต้องอ่านเท็กไฟล์ขนาดใหญ่เข้ามา แล้วเอามาแบ่งออกเป็นส่วนย่อยๆก็คือเอามา split นะแหละครับ แล้วทีนี้เวลาอ่านข้อมูลเอามาจากไฟล์ใน erlang จะใช้ฟังก์ชัน read_file จาก module file โดยผลลัพธ์ที่ได้จะอยู่ในรูปแบบประมาณนี้
{ok, <<"attaccggttaaccttgg">>}
คือได้ tuple ตัวแรกเป็น ok คืออ่านได้ปกติ ตัวหลังคือข้อมูลที่เป็นแบบ binary ใน erlang ข้อมูลแบบ binary จะอยู่ในสัญลักษณ์ <<>>
ตอนแรกทำโปรแกรมให้อ่านค่าจากไฟล์แล้วให้โปรแกรมส่งแค่ผลลัพธ์ข้างใน binary ออกมาเป็น string แล้วเอา string ไปใช้งานต่อ ผลที่ได้คือตอนทำการแบ่งสตริงออกเป็นลิสต์ของสตริงย่อยๆ ทำงานช้ามาก ขนาดที่ทดลองคือ ล้านกว่าตัวอักษร
ก็ลองค้นหาดูว่า มีวิธียังไงบ้างให้สามารถอ่านข้อมูลขนาดใหญ่เข้ามาจัดการได้อย่างรวดเร็ว ก็ไปเจอว่าส่วนใหญ่แล้วเขาจะไม่แปลงข้อมูลจาก binary ไปเป็น string แต่จะจัดการกับ binary เลย เช่นตรงนี้ก็คือ แบ่งตัว binary ที่ได้จากการอ่านไฟล์เลย โดยอาศัยการใช้ pattern matching กับข้อมูลแบบ binary เพื่อทำการ bind ค่าจาก binary ออกมาเป็น binary ย่อยๆตามจำนวนที่ต้องการ
ข้อมูลแบบ binary จะอยู่ใน pattern แบบนี้
<<"abc">>
ตัวอย่างคือมีข้อมูลอยู่ 3 bytes (24 bits แต่ละตัวอักษรใช้ 1 byte ใน 1 byte มี 8 bits)
ถ้าเราต้องการ binding ค่าของ a ออกมาจะทำได้แบบนี้
<> = <<"abc">>.
คือตรงส่วน pattern เราก็ทำให้อยู่ในฟอร์มของ binary มี <<>> ครอบเหมือนกัน ผลที่ได้คือ A จะถูก bound ค่าของ 8 bits แรกใน binary <<"abc">> ถ้าเราสั่ง
A.
97
จะเห็นว่าจะได้ค่า 97 ก็คือค่ารหัส ASCII ของอักษร a นั่นเอง ส่วน Rest/binary เป็นการบอกว่า Rest คือส่วนที่เหลือทั้งหมด และส่วนที่เหลือทั้งหมดนี้เป็น binary ทั้งก้อน ผลที่ได้คือ Rest จะเท่ากับ <<"bc">> นั่นเอง
Rest.
<<"bc">>
ถ้าเราต้องการนำ A กลับไปเป็น binary อีกครับก็สามารถทำได้โดยใช้ <<>> ครอบ A
<>.
<<"a">>
นอกจากนี้ เราสามารถกำหนดได้ว่าเราจะทำการ matching ค่าจาก binary เป็นจำนวนกี่บิต จะเห็นว่าปกติเป็น 8 บิต ตัวอย่างเช่น เราต้องการดึงค่าจาก <"abc"> ออกมา 2 ตัวหน้า คือ "ab" จะเห็นว่าตัวอักษรมีทั้งหมด 2 ตัวแสดงว่าใช้ทั้งหมด 16 bits เราสามารถ match ได้ด้วยวิธีแบบนี้
<> = <<"abc">>.
ผลที่ได้คือ Rest จะเหลือ
<<"c">>
ส่วน A จะได้ค่าเป็น
24930
คือเป็นค่าที่เกิดจาก bit ของ $a และ $b มาต่อกัน
ถ้าเราต้องการเอา A ไปสร้างเป็น binary ที่มี "ab" ทำได้โดยเอา A ไปครอบด้วย <<>> เหมือนเดิม แต่เราต้องใส่รายละเอียดจำนวนบิตเหมือนเดิมกับตอนที่เอา binding ค่าออกมาด้วยเช่น
<>.
<<"ab">>
ตัวอย่างที่ผมเอาไปใช้ใน my_split ฟังก์ชันที่แบ่ง binary แต่ผมจะแบ่งแบบคาบเกี่ยวกัน เช่น แบ่ง 2000 แต่หักออก 1000 แล้วแบ่งอีก 2000
-module(my_binary).
-export([my_split/2]).
my_split(BinList,N) -> my_split(BinList,N,[]).
my_split(<<>>,_,R) -> R;
my_split(BinList,N,R) -> Length = N*8,
BinListLength = bit_size(BinList),
CheckLength = Length =< BinListLength,
if CheckLength == true ->
<> = BinList,
DropLength = Length div 2,
<<_:DropLength,DropRest/binary>> = BinList,
my_split(DropRest,N,[<>|R]);
true ->
<> = BinList,
my_split(Rest,N,[<>|R])
end.
Roti (alpha) thinks you may like these
Recent comments
4 weeks 5 days ago
5 weeks 22 hours ago
12 weeks 2 days ago
14 weeks 4 days ago
22 weeks 2 hours ago