Streams و NIO

في هذا الدرس، سنتعلم IO القائم على التيارات و NIO لعمليات الملفات منخفضة المستوى.

بنية IO Streams

TEXT
تيارات الإدخال (القراءة)
InputStream (إدخال بايتات)
├── FileInputStream (ملف)
├── BufferedInputStream (مخزن مؤقت)
├── ByteArrayInputStream (مصفوفة بايتات)
└── DataInputStream (أنواع بدئية)

Reader (إدخال أحرف)
├── FileReader (ملف)
├── BufferedReader (مخزن مؤقت)
└── InputStreamReader (تحويل)

تيارات الإخراج (الكتابة)
OutputStream (إخراج بايتات)
├── FileOutputStream (ملف)
├── BufferedOutputStream (مخزن مؤقت)
└── DataOutputStream (أنواع بدئية)

Writer (إخراج أحرف)
├── FileWriter (ملف)
├── BufferedWriter (مخزن مؤقت)
└── OutputStreamWriter (تحويل)

تيارات البايتات

FileInputStream للقراءة

JAVA
import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamDemo {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("test.txt")) {
            int data;
            while ((data = fis.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

FileOutputStream للكتابة

JAVA
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo {
    public static void main(String[] args) {
        try (FileOutputStream fos = new FileOutputStream("output.txt")) {
            String text = "مرحباً بالعالم!";
            fos.write(text.getBytes());
            System.out.println("الكتابة ناجحة");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

مثال: نسخ ملف بتيارات البايتات

JAVA
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteCopy {
    public static void copy(String src, String dest) throws IOException {
        try (FileInputStream fis = new FileInputStream(src);
             FileOutputStream fos = new FileOutputStream(dest)) {
            
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, length);
            }
        }
    }
    
    public static void main(String[] args) {
        try {
            copy("source.txt", "dest.txt");
            System.out.println("النسخ مكتمل");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
▶ جرّب الكود

تيارات المخازن المؤقتة

تيارات المخازن المؤقتة تحسن كفاءة IO بتقليل عدد عمليات الوصول للقرص.

BufferedInputStream/BufferedOutputStream

JAVA
import java.io.*;

public class BufferedStreamDemo {
    public static void main(String[] args) throws IOException {
        // الكتابة
        try (BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream("buffered.txt"))) {
            for (int i = 0; i < 1000; i++) {
                bos.write(("سطر " + i + "\n").getBytes());
            }
        }
        
        // القراءة
        try (BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream("buffered.txt"))) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = bis.read(buffer)) != -1) {
                System.out.write(buffer, 0, length);
            }
        }
    }
}

تيارات البيانات

DataInputStream/DataOutputStream يمكنهما قراءة وكتابة الأنواع البدئية.

مثال: تيارات البيانات

JAVA
import java.io.*;

public class DataStreamDemo {
    public static void main(String[] args) throws IOException {
        // الكتابة
        try (DataOutputStream dos = new DataOutputStream(
                new FileOutputStream("data.dat"))) {
            dos.writeInt(100);
            dos.writeDouble(3.14);
            dos.writeUTF("مرحباً");
        }
        
        // القراءة
        try (DataInputStream dis = new DataInputStream(
                new FileInputStream("data.dat"))) {
            int i = dis.readInt();
            double d = dis.readDouble();
            String s = dis.readUTF();
            
            System.out.println("int: " + i);      // 100
            System.out.println("double: " + d);    // 3.14
            System.out.println("string: " + s);    // مرحباً
        }
    }
}
▶ جرّب الكود

NIO (New IO)

Java NIO توفر عمليات IO أكثر كفاءة.

واجهة Path

JAVA
import java.nio.file.Path;
import java.nio.file.Paths;

public class PathDemo {
    public static void main(String[] args) {
        Path path = Paths.get("/home/user/test.txt");
        
        System.out.println("اسم الملف: " + path.getFileName());  // test.txt
        System.out.println("الأب: " + path.getParent());    // /home/user
        System.out.println("الجذر: " + path.getRoot());      // /
        System.out.println("عدد الأسماء: " + path.getNameCount());  // 3
    }
}

فئة Files المساعدة

JAVA
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

public class FilesDemo {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("test.txt");
        
        // التحقق
        System.out.println("يوجد: " + Files.exists(path));
        System.out.println("ملف: " + Files.isRegularFile(path));
        System.out.println("قابل للقراءة: " + Files.isReadable(path));
        
        // قراءة جميع الأسطر
        List<String> lines = Files.readAllLines(path);
        lines.forEach(System.out::println);
        
        // قراءة كمصفوفة بايتات
        byte[] bytes = Files.readAllBytes(path);
        System.out.println("الحجم: " + bytes.length);
        
        // الكتابة
        Files.write(Paths.get("output.txt"), "مرحباً".getBytes());
        
        // إنشاء مجلد
        Files.createDirectories(Paths.get("newdir/subdir"));
        
        // النسخ
        Files.copy(Paths.get("source.txt"), Paths.get("dest.txt"));
        
        // النقل
        Files.move(Paths.get("old.txt"), Paths.get("new.txt"));
        
        // الحذف
        Files.deleteIfExists(Paths.get("temp.txt"));
    }
}

سمات الملف

JAVA
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;

public class FileAttributes {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("test.txt");
        
        BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
        
        System.out.println("الحجم: " + attrs.size());
        System.out.println("أنشئ: " + attrs.creationTime());
        System.out.println("عُدل: " + attrs.lastModifiedTime());
        System.out.println("مجلد: " + attrs.isDirectory());
        System.out.println("ملف: " + attrs.isRegularFile());
    }
}

استعراض الملفات (NIO)

JAVA
import java.io.IOException;
import java.nio.file.*;
import java.util.stream.Stream;

public class NIODirectoryWalk {
    public static void main(String[] args) throws IOException {
        Path dir = Paths.get(".");
        
        // قائمة المجلد
        try (Stream<Path> stream = Files.list(dir)) {
            stream.forEach(path -> {
                String type = Files.isDirectory(path) ? "[مجلد]" : "[ملف]";
                System.out.println(type + " " + path.getFileName());
            });
        }
        
        // استعراض متكرر
        try (Stream<Path> stream = Files.walk(dir, 3)) {  // 3 مستويات كحد أقصى
            stream.forEach(path -> System.out.println(path));
        }
        
        // إيجاد الملفات
        try (Stream<Path> stream = Files.find(dir, 10, 
                (path, attrs) -> attrs.isRegularFile() && path.toString().endsWith(".txt"))) {
            stream.forEach(System.out::println);
        }
    }
}

IO مقابل NIO

الميزة IO NIO
النموذج موجه للتيارات موجه للمخازن المؤقتة
الحجب IO حابس IO غير حابس
المحددات لا نعم
API أقدم أحدث

دليل الاختيار

السيناريو التوصية
قراءة/كتابة ملفات بسيطة فئة Files
معالجة ملفات كبيرة تيارات مخازن مؤقتة
شبكة عالية التزامن NIO
صيانة كود قديم تيارات IO

❓ أسئلة شائعة

س كيف أختار بين تيارات البايتات وتيارات الأحرف؟
ج استخدم تيارات الأحرف للملفات النصية، تيارات البايتات للملفات الثنائية.
س ما فوائد تيارات المخازن المؤقتة؟
ج تقلل عدد عمليات الوصول للقرص، مما يحسن كفاءة IO.
س هل NIO أسرع من IO؟
ج ليس بالضرورة. الميزة الرئيسية لـ NIO هي عدم الحجب والمحددات.

📖 ملخص

📝 تمارين

  1. مقارنة: قارن ملفين للتحقق من أنهما متطابقان
  2. معالجة: اقرأ ملفات كبيرة بقطع، اعدد الأسطر
  3. مزامنة: مزامن مجلد إلى آخر

الدرس التالي

في الدرس التالي، سنتعلم Regex و JSON — تقنيات متقدمة لمعالجة النصوص.

100%