English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

ملفات Rust وIO

هذا الفصل يقدم عملية I/O بلغة Rust.

استقبال معلمات سطر الأوامر

برنامج سطر الأوامر هو أكثر أشكال البرامج الأساسية،يدعم كل نظام تشغيل تقريبًا برامج سطر الأوامر ويقوم بتحويل تشغيل البرامج المرئية إلى آلية سطر الأوامر.

يجب أن يكون برنامج سطر الأوامر قادرًا على استقبال معلمات البيئة من سطر الأوامر،وغالبًا ما تكون هذه المعلمات منفصلة عن بعضها البعض بفواصل الفراغات في سطر الأوامر.

في العديد من اللغات (مثل Java و C/C++) يتم نقل معلمات البيئة إلى البرنامج عبر معلمات الدالة الرئيسية (غالبًا مجموعة من الأحرف المميزة)،لكن في Rust،يكون الدالة الرئيسية بدون معلمات،ويجب على المبرمجين استخراج معلمات البيئة عبر مكتبة std::env،والمسار بسيط جدًا:

fn main() {
    let args = std::env::args();
    println!("{:?}", args);
}

الآن أعد تشغيل البرنامج مباشرة:

Args { inner: ["D:\\rust\\greeting\\target\\debug\\greeting.exe"] }

قد تكون النتيجة التي حصلت عليها أطول بكثير من هذه،وهذا طبيعي،يوجد في بنية Args مجموعة inner تحتوي على دالة واحدة فقط،تمثل موقع البرنامج الذي يتم تشغيله حاليًا.

لكن هذا بنية بسيطة،لا مشكلة،يمكننا بسهولة تمريرها:

fn main() {
    let args = std::env::args();
    لـ arg في args {
        println!("{}", arg);
    }
}

نتيجة التنفيذ:

D:\rust\greeting\target\debug\greeting.exe

معظم المعلمات تستخدم لتكرارها،أليس كذلك.

الآن دعونا نفتح ملف launch.json الذي لم نلمسه منذ فترة طويلة،ونجد "args": [],يمكننا تعيين المعلمات عند تشغيل الوقت هنا،سنكتبها كـ "args": ["first", "second"]،ثم نحفظها ونشغل البرنامج الذي كتبناه للتو،نتيجة التشغيل:

D:\rust\greeting\target\debug\greeting.exe
first
second

كبرنامج سطر أوامر حقيقي،لم نستخدمه أبدًا،كدليل لغة،لا يتم شرح كيفية تشغيل برامج Rust بسطر الأوامر هنا.لكن إذا كنت مبرمجًا مؤهلاً،يمكنك العثور على موقع ملف التنفيذ،ويمكنك محاولة الدخول إلى الدليل واستخدام أوامر سطر الأوامر لاختبار استقبال البرنامج للمعلمات البيئية.

إدخال سطر الأوامر

في الفصول المبكرة،تم شرح تفصيلي حول كيفية استخدام إخراج سطر الأوامر،وذلك بسبب الحاجة إلى تعلم اللغة،لا يمكن调试 البرنامج بدون إخراج،لكن الحصول على معلومات الإدخال من سطر الأوامر يظل مهمًا جدًا لبرنامج سطر الأوامر.

في Rust،يقدم مكتبة std::io وظائف التدفق العادي (يمكن اعتبارها إدخال سطر الأوامر):

استخدام std::io::stdin;
fn main() {
let mut str_buf = String::new()
    stdin().read_line(&mut str_buf)
        .expect("Failed to read line.");
    println!("Your input line is 
{}", str_buf);
}

دعم بيئة VSCode للإدخال من سطر الأوامر عملية معقدة للغاية، تتعلق بمشاكل متعددة المنصات وعدم القدرة على التتبع، لذا نختار تشغيل البرنامج مباشرة في واجهة VSCode النصية. في سطر الأوامر، قم بتشغيل:

D:\rust\greeting> cd ./target/debug
D:\rust\greeting\target\debug> ./greeting.exe
w3codebox
خطتك النصية هي 
w3codebox

يحتوي std::io::Stdio على دالة read_line لقراءة سطر نصي إلى منطق التخزين، والقيم المعدة هي كائن Result الذي يستخدمه لنقل الأخطاء التي تحدث أثناء القراءة، لذا نستخدم عادة دوال expect أو unwrap للتعامل مع الأخطاء.

ملاحظة:لم يقدم مكتبة Rust القياسية حتى الآن طريقة مباشرة لقراءة أرقام أو بيانات تنسيق من سطر الأوامر، لذا يمكننا قراءة سطر نصي واحد واستخدام دوال التعرف على النص لمعالجة البيانات.

قراءة الملف

قمنا بإنشاء ملف text.txt في مجلد D:\ على جهاز الكمبيوتر، ويكون المحتوى كالتالي:

هذا ملف نصي.

هذه برنامج يقرأ محتويات ملف نصي:

use std::fs;
fn main() {
    let text = fs::read_to_string("D:\\text.txt").unwrap();
    println!("{}", text);
}

نتيجة التنفيذ:

هذا ملف نصي.

قراءة ملف يمكن أن يتسع في ذاكرة الحاسوب بأكمله في Rust أمر بسيط للغاية، يمكن لطريقة read_to_string في مكتبة std::fs بسهولة قراءة ملف نصي.

لكن إذا كان الملف الذي نريد قراءته ملفًا ثنائيًا، يمكننا استخدام دالة std::fs::read لقراءة مجموعة أنواع u8:

use std::fs;
fn main() {
    let content = fs::read("D:\\text.txt").unwrap();
    println!("{:?}", content);
}

نتيجة التنفيذ:

[84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 116, 101, 120, 116, 32, 102, 105, 108, 101, 46]

هذه الطريقتان هما قراءة مرة واحدة، وتتناسب بشكل جيد لتطوير تطبيقات الويب. ولكن بالنسبة لبعض البرامج الأساسية، لا يزال الطريقة التقليدية للقراءة المتدفقة غير قابلة للإزالة، لأن في معظم الحالات قد يكون حجم الملف أكبر بكثير من قدرة الذاكرة.

طريقة قراءة التدفق في Rust:

use std::io::prelude::*;
use std::fs;
fn main() {
    let mut buffer = [0u8; 5];
    let mut file = fs::File::open("D:\\text.txt").unwrap();
    file.read(&mut buffer).unwrap();
    println!("{:?}", buffer);
    file.read(&mut buffer).unwrap();
    println!("{:?}", buffer);
}

نتيجة التنفيذ:

[84, 104, 105, 115, 32] 
[105, 115, 32, 97, 32]

القسم File في مكتبة std::fs هو فئة وصف ملف، يمكن استخدامها لفتح الملف، بعد فتح الملف، يمكننا استخدام طريقة read في File لقراءة بعض البايتات من أسفل الملف إلى منطقة التخزين (منطقة التخزين هي مصفوفة u8)، وعدد البايتات المقراءة يساوي طول منطقة التخزين.

ملاحظة: لا تزال VSCode غير مهيئة لإضافة مراجع مكتبات القياسية تلقائيًا، لذا قد تكون الأخطاء مثل "عدم وجود دالة أو طريقة" ناتجة عن مشكلة مراجع مكتبات القياسية. يمكننا النظر في وثائق التعليقات الخاصة بالمكتبة القياسية (سيظهر التعليق عند وضع الماوس فوقه) لإنشاء مكتبة قياسية يدويًا.

طريقة open الخاصة بـ std::fs::File هي فتح الملف بالقراءة فقط، وليس لديها طريقة إغلاق مصاحبة، لأن محرر Rust يمكنه إغلاق الملف تلقائيًا عند عدم استخدامه.

كتابة ملف

كتابة ملف يتكون من كتابة مرة واحدة وكتابة متدفقة. الكتابة المتدفقة تتطلب فتح الملف، حيث تتوفر طرق فتح مثل "إنشاء جديد" (create) و "إضافة" (append).

الكتابة مرة واحدة:

use std::fs;
fn main() {
    fs::write("D:\\text.txt", "FROM RUST PROGRAM")
        .unwrap();
}

هذا بسيط ومريح مثل قراءة مرة واحدة. بعد تنفيذ البرنامج، محتوى ملف D:\text.txt سيتم استبداله بـ FROM RUST PROGRAM. لذا، استخدم الكتابة مرة واحدة بحذر لأنها ست�除 محتوى الملف مباشرة (على الرغم من أن حجم الملف يمكن أن يكون كبيرًا جدًا). إذا لم يكن الملف موجودًا، سيتم إنشاؤه.

إذا كنت ترغب في استخدام الطريقة المتدفقة للكتابة إلى محتوى الملف، يمكنك استخدام طريقة create الخاصة بـ std::fs::File:

use std::io::prelude::*;
use std::fs::File;
fn main() {
    let mut file = File::create("D:\\text.txt").unwrap();
    file.write(b"FROM RUST PROGRAM").unwrap();
}

هذا البرنامج متساوي مع البرنامج السابق.

ملاحظة!: يجب أن تكون الملفات المفتوحة موجودة في متغيرات متغيرة لتتمكن من استخدام طرق File!

لا توجد دالة ثابتة append في فئة File، ولكن يمكننا استخدام OpenOptions لتحقيق فتح الملف باستخدام طريقة معينة:

use std::io::prelude::*;
use std::fs::OpenOptions;
fn main() -> std::io::Result<()> {
    
    let mut file = OpenOptions::new()
            .append(true).open("D:\\text.txt")?;
    file.write(b" APPEND WORD")?;
    Ok(())
}

بعد تشغيله، محتويات ملف D:\text.txt سيصبح كالتالي:

FROM RUST PROGRAM APPEND WORD

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

use std::io::prelude::*;
use std::fs::OpenOptions;
fn main() -> std::io::Result<()> {
    
    let mut file = OpenOptions::new()
            .read(true).write(true).open("D:\\text.txt")?;
    file.write(b"COVER")?;
    Ok(())
}

بعد تشغيله، محتويات ملف D:\text.txt سيصبح كالتالي:

COVERRUST PROGRAM APPEND WORD