اذهب إلى المحتوى

ترميز النصوص والتعامل مع كائنات الملفات في جافاسكربت


ابراهيم الخضور

ماذا لو كانت البيانات الثنائية معلومات نصيةً؟ أي ماذا لو تلقينا ملفًا يحتوي على نص؟ سيسمح لنا الكائن 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 ويُوسَّع بإمكانيات تتعلق بنظام الملفات، وتوجد طريقتان لإنشائه:

  1. باستخدام الدالة البانية بشكل مشابه للكائن Blob:
   new File(fileParts, fileName, [options])

حيث:

  • fileparts: يمثل مصفوفةً قد تكون قيمها نصية أو blob أو BufferSource.
  • fileName: اسم الملف.
  • options: وتضم الكائن الاختياري التالي:
    • lastModified: تاريخ آخر تعديل (تاريخ من النوع الصحيح integer).
  1. الحصول على ملف باستخدام <"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.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...