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 هي عدم الحجب والمحددات.
📖 ملخص
- تيارات IO تنقسم لتيارات بايتات وأحرف
- تيارات المخازن المؤقتة تحسن كفاءة IO
- NIO توفر عمليات ملفات أكثر كفاءة
- فئة Files تبسط عمليات الملفات
📝 تمارين
- مقارنة: قارن ملفين للتحقق من أنهما متطابقان
- معالجة: اقرأ ملفات كبيرة بقطع، اعدد الأسطر
- مزامنة: مزامن مجلد إلى آخر
الدرس التالي
في الدرس التالي، سنتعلم Regex و JSON — تقنيات متقدمة لمعالجة النصوص.



