ماذا لو كانت البيانات الثنائية معلومات نصيةً؟ أي ماذا لو تلقينا ملفًا يحتوي على نص؟ سيسمح لنا الكائن TextDecoder المدمج ضمن JavaScript بقراءة البيانات وتحويلها إلى نص فعلي، بعد تزويده بالمخزن المؤقت buffer الذي يحتوي البيانات الثنائية وطريقة فك الترميز، حيث علينا أوّلًا إنشاء مفكك الترميز Decoder:
let decoder = new TextDecoder([label], [options]);
حيث:
-
label
: يمثل طريقة الترميز، والتي ستكونutf-8
افتراضيًا، كما تدعم كلًا من الطريقتينbig5
وwindows-1251
وغيرها. -
options
: وتضم كائنات اختياريةً هي:-
fatal
: قيمة منطقية boolean، حيث عندما تأخذ القيمة "true"، فسترمي استثناءً عند وجود محارف غير صالحة أي لا يمكن فك ترميزها، وإلا -وهي الحالة الافتراضية- فستستبدلها بالمحرف "uFFFD\". -
ignoreBOM
: وهي قيمة منطقية ستتجاهل BOM (وهي علامة Unicode خاصة بترتيب البايتات) التي تُستخدم نادرًا، ويحدث ذلك عندما تأخذ القيمة "true".
-
ومن ثم عملية فك الترميز Decoding:
let str = decoder.decode([input], [options]);
-
input
: ويمثل كائنBufferSource
الذي يحتوي البيانات الثنائية. -
options
: وتضم كائنًا اختياريًا هو:-
stream
: وتأخذ القيمة "true" عندما نريد فك ترميز مجرى تدفق دخل، وذلك عند استدعاء مفكك الترميز باستمرار عن طريق مجموعات البيانات القادمة، وفي هذه الحالة قد يوضع محرف من عدة بايتات multi-byte charecter ليفصل بين هذه المجموعات، ويخبر هذا الخيار مفكك الترميز بتذكر المحارف غير المرمزة، وأن يفك ترميزها عندما تصل المجموعة الجديدة من البيانات. فمثلًا:
-
let uint8Array = new Uint8Array([72, 101, 108, 108, 111]); alert( new TextDecoder().decode(uint8Array) ); // Hello
let uint8Array = new Uint8Array([228, 189, 160, 229, 165, 189]); alert( new TextDecoder().decode(uint8Array) ); // 你好
يمكن فك ترميز جزء من المخزن المؤقت بإنشاء مصفوفة ثانوية subarray بالطريقة التالية:
let uint8Array = new Uint8Array([0, 72, 101, 108, 108, 111, 0]); // النص في الوسط // أنشئ تمثيلًا جديدًا دون نسخ أي شيء let binaryString = uint8Array.subarray(1, -1); alert( new TextDecoder().decode(binaryString) ); // Hello
مرمز النصوص TextEncoder
مهمته معاكسة لمهمة مفكك الترميز، إذ يحوّل المُرمِّز TextEncoder النص إلى بايتات.
ويُستخدم كالتالي:
let encoder = new TextEncoder();
كما يدعم طريقة الترميز "utf-8" فقط. وله تابعان هما:
-
(encode(str
: ويعيد كائنًا من النوعUint8Array
انطلاقًا من نص. -
(encodeInto(str, destination
: يُرمزstr
إلىdestination
والتي ينبغي أن تكون من النوعUint8Array
.
let encoder = new TextEncoder(); let uint8Array = encoder.encode("Hello"); alert(uint8Array); // 72,101,108,108,111
الكائنان File وFileReader
يرث الكائن File الكائن Blob
ويُوسَّع بإمكانيات تتعلق بنظام الملفات، وتوجد طريقتان لإنشائه:
-
باستخدام الدالة البانية بشكل مشابه للكائن
Blob
:
new File(fileParts, fileName, [options])
حيث:
-
fileparts
: يمثل مصفوفةً قد تكون قيمها نصية أوblob
أوBufferSource
. -
fileName
: اسم الملف. -
options
: وتضم الكائن الاختياري التالي:-
lastModified
: تاريخ آخر تعديل (تاريخ من النوع الصحيح integer).
-
-
الحصول على ملف باستخدام
<"input type="file>
أو أسلوب الجر والإفلات، أو غيرها من الواجهات التي يؤمنها المتصفح، حيث يأخذ الملف في هذه الحالات المعلومات السابقة التي استخدمَت بمثابة وسطاء من نظام التشغيل.
بما أن الكائن File يرث الكائن Blob
، فله خصائصه نفسها، بالإضافة إلى الآتي:
-
name
: اسم الملف. -
lastModified
: تاريخ آخر تعديل.
إليك مثالًا يصف الحصول على الكائن File
باستخدام <"input type="file>
:
<input type="file" onchange="showFile(this)"> <script> function showFile(input) { let file = input.files[0]; alert(`File name: ${file.name}`); // e.g my.png alert(`Last modified: ${file.lastModified}`); // e.g 1552830408824 } </script>
اقتباسملاحظة:
يمكن اختيار عدة ملفات، لذلك نستخدم الأمر
input.files
الذي يمثل كائنًا يشبه المصفوفة يضم هذه الملفات، وسنتعامل في مثالنا مع كائن واحد لذلك نرى الأمر السابق على الشكل[input.files[0
.
الكائن FileReader
يمثل FileReader كائنًا يخدم غرضًا وحيدًا هو قراءة البيانات من الكائن Blob
(وبالتالي من الكائن File
أيضًا)، وينقل البيانات مستخدمًا الأحداث، لأن القراءة من القرص قد تستغرق وقتًا، وصيغة الدالة البانية له هي بالشكل:
let reader = new FileReader(); // لا وسطاء
لهذا الكائن عدة توابع، أهمها:
-
(readAsArrayBuffer(blob
: يقرأ البيانات بالصيغة الثنائية على شكلArrayBuffer
. -
([readAsText(blob, [encoding
: يقرأ البيانات مثل نص مستعمل للتشفير المحدد، وهوutf-8
افتراضيًا. -
(readAsDataURL(blob
: يقرأ البيانات الثنائية ويحولها إلى عنوان بيانات data url مشفر بطريقة base64. -
()abort
: يلغي العملية.
نحدد التابع الذي سيستعمَل في القراءة وفقًا لصيغة البيانات التي نفضلها، وكيف سنستخدمها.
-
readAsArrayBuffer
: يُستخدم لقراءة الملفات الثنائية وتنفيذ عمليات ثنائية منخفضة المستوى، بينما نستدعي الكائنFile
مباشرةً دون قراءة عند تنفيذ عمليات عالية المستوى (ليست ثنائيةً) مثل اقتطاع شرائح من البيانات slicing. -
readAsText
: يُستخدم عند قراءة ملفات نصية والحصول على قيم نصية. -
readAsDataURL
: يُستخدم عندما نريد استخدام البيانات المقروءة في الخاصيةsrc
للمعرفimg
وغيره من المعرّفات، كما توجد طريقة أخرى لقراءة الملف تعرفنا عليها في مقال "كائن البيانات الثنائية Blob"، وهي استخدام التابع(URL.createObjectURL(file
يمكن الاستفادة من عدة أحداث تقع أثناء عملية القراءة:
-
loadstart
: يقع عند بداية التحميل. -
progress
: يقع خلال القراءة. -
load
: يقع عند انتهاء القراءة دون أخطاء. -
abort
: يقع عند استدعاء التابع()abort
. -
error
: يقع عند حدوث خطأ. -
loadend
: يقع عند انتهاء القراءة بنجاح أو بفشل.
يمكن الوصول إلى النتيجة عند انتهاء القراءة بالشكل التالي:
-
reader.result
: للحصول على النتيجة عند نجاح العملية. -
reader.error
: للحصول على الخطأ عند إخفاق القراءة.
وأكثر الأحداث استخدامًا هما الحدثان load
وerror
.
إليك مثالًا عن قراءة ملف:
<input type="file" onchange="readFile(this)"> <script> function readFile(input) { let file = input.files[0]; let reader = new FileReader(); reader.readAsText(file); reader.onload = function() { console.log(reader.result); }; reader.onerror = function() { console.log(reader.error); }; } </script>
اقتباساستخدام الكائن FileReader مع الكائن blob أشرنا في "كائن البيانات الثنائية Blob" إلى إمكانية استخدام
FileReader
في قراءة كائناتBlob
، وبالتالي تحويلها إلى صيغة أخرى، وهي:
ArrayBuffer
باستخدام(readAsArrayBuffer(blob
TextDecoder
باستخدام([readAsText(blob, [encoding
عنوان بيانات data URL
بتشفير base64 باستخدام(readAsDataURL(blob
الكائن
FileReaderSync
متاح لعمال ويب Web Workers ويوجد بديل متزامن للكائنFileReader
يستخدم مع عمال الويب Web Workers يُدعى FileReaderSync. حيث لا تولّد توابع القراءة الخاصة به*read
أية أحداث، بل تعيد نتيجةً نظاميةً كما تفعل الدوال، ويجري ذلك فقط ضمن شيفرة عامل الويب، لأنّ التأخير في الاستدعاءات المتزامنة التي قد تحدث أثناء قراءة الملفات أقل أهميةً في عامل الويب، لذا لن تؤثر في الصفحة.
خلاصة
تعرفنا في هذا المقال على كيفية ترميز النصوص وفك ترميزها بجافاسكريبت، مركزين على مرمز النصوص TextEncoder، بعدها انتقلنا للحديث عن كيفية التعامل مع كائنات الملفات، حيث توصلنا إلى الآتي:
-
يرث الكائن
File
والكائنBlob
. -
للكائن
File
الخاصيتينname
وlastModified
بالإضافة إلى خصائص الكائنBlob
وتوابعه، مع إمكانية القراءة من نظام الملفات المرتبط بنظام التشغيل. -
يمكن الحصول على الكائنات
File
عن طريق مُدخلات المستخدم مثل<input>
أو أحداث الجر والإفلات مثلondragend
. -
يمكن لكائن
FileReader
القراءة من ملف أوBlob
بإحدى التنسيقات التالية: -
نص باستخدام التابع
readAsText
. -
ArrayBuffer
باستخدام التابعreadAsArrayBuffer
. -
عنوان بيانات بتشفير base64 باستخدام التابع
readAsDataURL
. -
لا نحتاج في بعض الحالات إلى قراءة محتويات ملف، لذا وكما فعلنا مع الكائن
blob
سننشئ عنوانًا قصيرًا باستخدام الأمر(URL.createObjectURL(file
ونسنده إلى المعرف<a>
أو<img>
، وبهذا يمكن تنزيل الملف أو عرضه كصورة أو كجزء من لوحة رسمcanvas
. -
سيكون الأمر بسيطًا إذا كنا سنرسل ملفًا عبر الشبكة، إذ يقبل الكائنان
XMLHttpRequest
وfetch
الكائنFile
مباشرةً.
ترجمة -وبتصرف- للفصلين text decoder and text encoder وFile and FileReader من سلسلة The Modern JavaScript Tutorial.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.