كيف تقرأ من وتكتب في ملف نصي باستخدام [java.io] و [java.nio]

عندما تتعلم طريقة التعامل مع الملفات (والتي تعني أن تقرأ وتكتب في الملفات) تكون قد انتقلت نقلة نوعية في مسيرتك البرمجية، تتحول من كتابة البرامج التي تؤدي عملياتٍ حسابية في ذاكرة الحاسب فقط إلى تخزين البيانات في القرص الصلب للحاسب وقراءتها مرة أخرى ولا تُفقد بيانات برنامجك بعد اغلاقه.

مثلاً بمعرفتك لطريقة التعامل مع الملفات تستطيع أن تطور برنامجاً يُخزن اسم المستخدم وكلمة المرور، كما يستطيع البرنامج تخزين البيانات التي يدخلها المستخدم مثلما يحدث في برامج الحسابات (فواتير، عمليات بيع وشراء، ميزانية،…إلخ) وما شابه ذلك من البرامج.

هذه التدوينة تضعك في بداية طريق التعامل مع الملفات وتشحنك بالأساسيات التي تحتاجها حتى تطور من برامجك المتعلقة بالقراءة من والكتابة في الملفات.

التعامل مع الملفات عبر مكتبة java.io

عندما تتعامل مع الملفات فإنك تريد أن تجري إحدى عمليتين:

  • قراءة
  • كتابة

مكتبة java.io مجهزة بالعديد من الأصناف Classes التي تسهل إجراء عمليات الكتابة والقراءة. لتتضح الصورة لديك تخيل أن كل صنف يُنشئ نفقاً بينه وبين الملف بحيث يستقبل البيانات عبر النفق عندما يكون الهدف هو القراءة، ويرسل البيانات إلى الملف عبر النفق عندما يكون الهدف هو الكتابة.

وقبل أن أعرفك على هذه الأصناف، يجب أن تعلم أنه توجد طريقتان لإجراء عمليات الكتابة أو الكتابة:

  • القراءة أو الكتابة نصياً (في شكل حروف).
  • القراءة والكتابة ثنائياً (بايتات).

القراءة والكتابة ثنائياً Binary

(1) الكتابة ثنائياً

بعض الأصناف الشائعة للكتابة في الملفات ثنائياً
بدأت بعملية الكتابة لسبب مهم. عندما تبدأ عملية إنشاء صنف الكتابة يُنشأ الملف ومن ثم تستطيع استخدام نفس الملف في عملية القراءة.

كل صنف من الأصناف المذكورة أعلاه له صفات تميزه وأماكن وأوقات يفضل استخدامه فيها. ولكن بما أنك في البداية فلنستعرض أكثرها شيوعاً وهو FileOutputStream

استورد مكتبة java.io

import java.io.*;

هذا البرنامج البسيط يقوم بالبحث عن ملف يسمى oolom.txt، إذا كان موجوداً فإن البرنامج يقرأه، وإذا لم يكن موجوداً يقوم بإنشاءه. ثم يكتب الرقم 65 في بايت واحد Byte في الملف. وبعدها يغلق النفق بين الصنف والملف.

public static void main(String[] args) {

    try {
        File file = new File("E://oolom.txt");
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(65);
        fos.close();

    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}

فتح الأنفاق للتعامل مع الملفات يجب أن يتم دوماً بين قوسي try للتحقق من أخطاء الإدخال والإخراج IOExceptions على الأقل.

(2) القراءة ثنائياً

بعض الأصناف الشائعة للقراءة من الملفات ثنائياً

في الشفرة المصدرية السابقة قمت بكتابة بايت واحد في الملف يحتوي على 65.

في الشفرة المصدرية التالي ستقرأ ما كتبته في الملف السابق

try {
    File file = new File("E://oolom.txt");
     FileInputStream fis = new FileInputStream(file);
    System.out.println(fis.read());
    fis.close();

} catch (IOException e) {
    System.out.println(e.getMessage());
}

ربما تتساءل، ما الفائدة من كتابة رقم فقط؟ وكيف أخزن المعلومات المفيدة عبر OutputStream وأقرأها عبر InputStream؟

الرقم 65 والذي خزنته في الملف هو ترميز الحرف A. فإذا قمت بعملية تحويل بسيطة ستجد أنك قد خزنت حرفاً بالملف

 System.out.println((char)fis.read());
لتكون نتيجة القراءة

كما توجد طرق أخرى لكتابة وقراءة العديد من البايتات في سطر واحدة، مثل إرسال مصفوفة بايتات إلى دالة read أو write.

القراءة والكتابة نصياً Text

(1) الكتابة نصياً

بعض الأصناف الشائعة للقراءة من الملفات نصياً

لا يختلف الأمر كثيراً عن الكتابة ثنائياً. غير أن دالة الكتابة تخزن حروف طبيعية بالملف.

في الشفرة المصدرية التالية نخزن الحرف A في الملف عبر FileWriter

try {
    File file = new File("E://oolom.txt");
    FileWriter fr = new FileWriter(file);
    fr.write("oolom");
    fr.close();

} catch (IOException e) {
    System.out.println(e.getMessage());
}

(2) القراءة نصياً

بعض الأصناف الشائعة للكتابة في الملفات نصياً

في الشفرة المصدرية التالية نقرأ النص الكامل الذي خزنتة في الملف oolom.txt، وحتى نقرأ النص كاملاً أرسلنا مصفوفة (ونحن نعلم أن طولها أطول من النص) إلى الدالة read فقامت بتعبئتها بالنص الموجود.

try {
    File file = new File("E://oolom.txt");
    FileReader fr = new FileReader(file);
    char[] charBuffer = new char[10];
    fr.read(charBuffer);
    System.out.println(charBuffer);
    fr.close();

} catch (IOException e) {
    System.out.println(e.getMessage());
}

عند طباعة المصفوفة تكون النتيجة

المكتبة الجديدة للتعامل مع الملفات java.nio

في هذه المكتبة أصدرت أصناف مهمة تتعلق بالكتابة في المفات بعد أن تم التخلي عن الأصناف المتعلقة بالتعامل مع الملفات في مكتبة java.io.

انتبه إلى أن عبارة التخلي عن بعض الأصناف لا يعني أنها لن تعمل مستقبلاً، فهناك ما لا يقل عن عشرات الملايين من الأسطر حول العالم تعتمد على مكتبة java.io في التعامل مع الملفات، وإنما يعني التخلي أنه يوصى بأن لا تستخدم هذه المكتبات في عملك المستقبلي.

أصناف مهمة في مكتبة java.nio

  • Paths: هذا الصنف Static ويحتوي على العديد من الدوال المتعلقة بالمسارات والجاهزة للاستخدام.
  • Files: هذا الصنف Static ويحتوي على العديد من الدوال المتعلقة بالمسارات والجاهزة للاستخدام.

القراءة والكتابة نصياً

في الشفرة المصدرية التالية سنجري الآتي:

  • ننشئ مساراً path عير استخدام احدى الدوال الجاهزة في الصنف Paths.
  • ننشئ BufferedWriter للكتابة في الملف عبر استخدام احدى الدوال الجاهزة في الصنف Files.
  • نكتب عبارة hello file في الملف.
  • نغلق نفق الكتابة.
  • ننشئ BufferedRedear للقراءة من الملف عبر احدى الدوال الجاهزة في الصنف Files.
  • نقرأ سطراً من الملف ونطبعه على الشاشة.
  • نغلق نفق القراءة.
 try {
            
    Path p = Paths.get("file.txt");
    BufferedWriter bw = Files.newBufferedWriter(p);
    bw.write("hello file");
    bw.close();

    BufferedReader br = Files.newBufferedReader(p);
    System.out.println(br.readLine());
    br.close();

} catch (IOException e) {
    System.out.println(e.getMessage());
}
نتيجة تنفيذ البرنامج

توجد العديد من الدوال المتعلقة بالملفات، وما يوجد في هذه التدوينة يمثل شرارة بداية التعامل مع الملفات. جّرب كثيراً ستصل إلى أشياء جيدة جداً.

مصطفى الطيب

صديقٌ لنُظمِ المعلُومات و عُلومِ الحَاسِب و مُختصٌ بهما، مُحبٌ للعِلمِ و نَشرِه. أُشاركُ معارفي و تَجاربي و خِبراتي في تَدويناتٍ و دوراتٍ من خلال مُدونةِ عُلوم.

‫2 تعليقات

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

زر الذهاب إلى الأعلى