أهلاً! سيتم تقسيم درس اليوم إلى قسمين للراحة. سنكرر بعض المواضيع القديمة التي تطرقنا إليها سابقًا، وسنأخذ في الاعتبار بعض الميزات الجديدة :) لنبدأ بالموضوع الأول. لقد قمت بالفعل بفصل دراسي مثل
BufferedReader
عدة مرات. أتمنى ألا يكون لديك الوقت لنسيان هذا البيان:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
قبل مواصلة القراءة، حاول أن تتذكر ما هو المسؤول عن كل مكون — System.in
, InputStreamReader
, BufferedReader
— وسبب الحاجة إليه. هل تذكرت؟ إذا لم يكن الأمر كذلك، فلا داعي للقلق. :) إذا نسيت شيئًا ما، فأعد قراءة هذا الدرس
المخصص لفصول القراء. سوف نتذكر بإيجاز ما يمكن أن يفعله كل منهم. System.in
- هذا دفق لتلقي البيانات من لوحة المفاتيح. من حيث المبدأ، سيكون هذا وحده كافيًا لتنفيذ المنطق المطلوب لقراءة النص. ولكن، كما تتذكر، System.in
يمكنه قراءة وحدات البايت فقط، وليس الأحرف:
public class Main {
public static void main(String[] args) throws IOException {
while (true) {
int x = System.in.read();
System.out.println(x);
}
}
}
إذا قمنا بتنفيذ هذا الرمز وأدخلنا الحرف السيريلي "Й"، فسيكون الناتج:
Й
208
153
10
تشغل الأحرف السيريلية 2 بايت في الذاكرة، ويتم عرضها على الشاشة. الرقم 10 هو التمثيل العشري لحرف تغذية السطر، أي من الضغط على Enter. تعد قراءة وحدات البايت أمرًا ممتعًا، لذا فإن استخدامها System.in
ليس مريحًا للغاية. من أجل قراءة الحروف السيريلية (وغيرها) بشكل صحيح، نستخدم InputStreamReader
كملف:
public class Main {
public static void main(String[] args) throws IOException {
InputStreamReader reader = new InputStreamReader(System.in);
while (true) {
int x = reader.read();
System.out.println(x);
}
}
}
ندخل نفس الحرف "Й"، لكن النتيجة مختلفة هذه المرة:
Й
1049
10
InputStreamReader
تحويل بايتين (208 و153) إلى الرقم الفردي 1049. هذا هو ما تعنيه قراءة الأحرف. 1049 يتوافق مع الحرف السيريلي "Й". يمكننا بسهولة إقناع أنفسنا بأن هذا صحيح:
public class Main {
public static void main(String[] args) throws IOException {
char x = 1049;
System.out.println(x);
}
}
إخراج وحدة التحكم:
Й
وكما forBufferedReader
(وبشكل عام BufferedAnythingYouWant
)، يتم استخدام الفئات المخزنة لتحسين الأداء. يعد الوصول إلى مصدر البيانات (ملف، وحدة تحكم، مورد ويب) مكلفًا للغاية من حيث الأداء. لذلك، من أجل تقليل عدد مرات الوصول، BufferedReader
نقوم بقراءة البيانات وتجميعها في مخزن مؤقت خاص، ونحصل عليها من هناك. ونتيجة لذلك، يتم تقليل عدد مرات الوصول إلى مصدر البيانات - ربما بعدة مراتب من حيث الحجم! إحدى BufferedReader
ميزات s وميزته على العادي InputStreamReader
هي readLine()
الطريقة المفيدة للغاية، والتي تقرأ أسطرًا كاملة من البيانات، وليس الأرقام الفردية. وهذا بالطبع ملائم للغاية عند التعامل مع النصوص الكبيرة. إليك ما تبدو عليه خطوط القراءة:
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String s = reader.readLine();
System.out.println ("The user entered the following text:");
System.out.println(s);
reader.close();
}
}
BufferedReader+InputStreamReader is faster than InputStreamReader alone
The user entered the following text:
BufferedReader+InputStreamReader is faster than InputStreamReader alone
وبطبيعة الحال، BufferedReader
مرنة للغاية. أنت لا تقتصر على العمل مع لوحة المفاتيح. على سبيل المثال، يمكنك قراءة البيانات مباشرة من الويب، وذلك ببساطة عن طريق تمرير عنوان URL المطلوب إلى القارئ:
public class URLReader {
public static void main(String[] args) throws Exception {
URL oracle = new URL("https://www.oracle.com/index.html");
BufferedReader in = new BufferedReader(
new InputStreamReader(oracle.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
يمكنك قراءة البيانات من ملف عن طريق تمرير مسار الملف:
public class Main {
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("testFile.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream));
String str;
while ((str = reader.readLine()) != null) {
System.out.println (str);
}
reader.close();
}
}
استبدال System.out
الآن دعونا نلقي نظرة على قدرة مثيرة للاهتمام لم نتطرق إليها من قبل. كما تتذكر بالتأكيد،System
يحتوي الفصل على حقلين ثابتين - System.in
و System.out
. هؤلاء الأخوة التوأم هم كائنات متدفقة. System.in
هو InputStream
. وهو . System.out
_ PrintStream
في الوقت الحالي، سنتحدث عن System.out
. إذا انتقلنا إلى System
الكود المصدري للفئة، فسنرى هذا:
public final class System {
……………...
public final static PrintStream out = null;
…………
}
وبالتالي، System.out
فهو مجرد متغير ثابت عادي للفئةSystem
. لا يوجد شيء سحري في هذا :) المتغير out
هو PrintStream
مرجع. إليك سؤال مثير للاهتمام: عندما System.out.println()
يتم التنفيذ، لماذا بالضبط يذهب الإخراج إلى وحدة التحكم وليس إلى مكان آخر؟ وهل يمكن تغيير هذا بطريقة أو بأخرى؟ على سبيل المثال، لنفترض أننا نريد قراءة البيانات من وحدة التحكم وكتابتها في ملف نصي. هل من الممكن تنفيذ هذا بطريقة أو بأخرى باستخدام System.out
فئات القارئ والكاتب الإضافية بدلاً من فئات إضافية؟ في الواقع، إنه :) ويمكننا القيام بذلك على الرغم من أن System.out
المتغير محدد بالمعدل final
! إذن ما الذي نحتاجه لتحقيق ذلك؟ أولا وقبل كل شيء، نحن بحاجة إلى PrintStream
كائن جديد ليحل محل الكائن الحالي. الكائن الحالي، الذي تم تعيينه في System
الفصل افتراضيًا، لا يخدم أغراضنا: فهو يشير إلى وحدة التحكم. تحتاج إلى إنشاء ملف جديد يشير إلى ملف نصي - "الوجهة" لبياناتنا. ثانيًا، علينا أن نفهم كيفية تعيين قيمة جديدة للمتغير System.out
. لا يمكنك استخدام عامل إسناد بسيط، لأنه تم وضع علامة على المتغير final
. دعونا نعمل إلى الوراء من النهاية. كما يحدث، فإن System
الفصل لديه الطريقة التي نحتاجها: setOut()
. يأخذ PrintStream
كائنًا ويحدده كوجهة للإخراج. هذا فقط ما نحتاجه! كل ما تبقى هو إنشاء PrintStream
كائن. وهذا أيضًا سهل:
PrintStream filePrintStream = new PrintStream(new File("C:\\Users\\Username\\Desktop\\test.txt"));
سيبدو الرمز الكامل كما يلي:
public class SystemRedirectService {
public static void main(String arr[]) throws FileNotFoundException
{
PrintStream filePrintStream = new PrintStream(new File("C:\\Users\\Username\\Desktop\\test.txt"));
/* Save the current value of System.out in a separate variable so that later
we can switch back to console output */
PrintStream console = System.out;
// Assign a new value to System.out
System.setOut(filePrintStream);
System.out.println("This line will be written to the text file");
// Restore the old value of System.out
System.setOut(console);
System.out.println("But this line will be output to the console!");
}
}
ونتيجة لذلك، تتم كتابة السلسلة الأولى في الملف النصي، ويتم عرض السلسلة الثانية في وحدة التحكم :) يمكنك نسخ هذا الرمز إلى IDE الخاص بك وتشغيله. افتح الملف النصي وسترى أن السلسلة قد تمت كتابتها هناك بنجاح :) وبهذا يكون درسنا قد وصل إلى النهاية. لقد تذكرنا اليوم كيفية العمل مع التدفقات والقراء. تذكرنا مدى اختلافها عن بعضها البعض وتعرفنا على بعض القدرات الجديدة System.out
التي استخدمناها في كل درس تقريبًا :) حتى الدروس التالية!
المزيد من القراءة: |
---|
GO TO FULL VERSION