مقدمة
في المقالة السابقة ، قدمنا نوع ملف ملفات القرص المجردة. يتم استخدامه فقط لوصف ملف أو دليل قرص مجردة ، ولكن ليس لديه القدرة على الوصول إلى محتوى الملف وتعديله.
Java IO Stream هو تصميم يستخدم لقراءة وكتابة محتويات الملف. يمكنه إكمال نقل البيانات لمحتويات ملف قرص الإخراج إلى بيانات الذاكرة أو إخراج بيانات Disk.
تصميم تدفقات Java IO ليس مثاليًا. لقد صمم عددًا كبيرًا من الفصول ، مما زاد من فهمنا لتيارات IO ، ولكن هناك فئتان رئيسيتان فقط: إحداها هي تدفقات البايت للملفات الثنائية ، والآخر هو تدفقات الأحرف للملفات النصية. في هذه المقالة ، سنتعلم أولاً مبادئ وسيناريوهات الاستخدام لأنواع تدفقات البايت ذات الصلة. أنواع الدفق المحددة المعنية بشكل أساسي هي على النحو التالي:
دفق بايت الفئة الأساسية/الإخراج
InputStream و OutputStream هي الفئات الأساسية لقراءة تدفقات البايت وكتابة تدفقات البايت على التوالي. يجب أن ترث جميع الجداول المتعلقة بالبايت من أي منها. كطبقة مجردة ، يحددون أيضًا عمليات القراءة والكتابة الأساسية. لنلقي نظرة:
خذ inputstream كمثال:
الملخص العام int read () يلقي ioException ؛
هذه طريقة مجردة ، ولا توفر تطبيقًا افتراضيًا ، تتطلب تنفيذ الفئات الفرعية. الغرض من هذه الطريقة هو إرجاع البايت التالي للملف الحالي لك.
بالطبع ، ستجد أيضًا أن قيمة إرجاع هذه الطريقة يتم استلامها باستخدام نوع INTEGER "int" ، فلماذا لا تستخدم "بايت"؟
بادئ ذي بدء ، يجب أن تكون القيمة التي يتم إرجاعها بواسطة طريقة القراءة ثنائية الثمانية بت ، والفاصل الزمني للقيمة الذي يمكن أن يؤخذ بواسطة ثنائية الثمانية أرق هي: "0000 0000 ، 1111 1111" ، أي النطاق [-128 ، 127].
تحدد طريقة القراءة أيضًا أنه عند قراءة الملف حتى النهاية ، أي أن الملف ليس له بايت التالي للقراءة ، فسيتم إرجاع القيمة -1. لذا ، إذا تم استخدام البايت كنوع قيمة الإرجاع ، فحينئذٍ عند إرجاع الطريقة A -1 ، هل يجب أن نحدد ما إذا كان هذا هو محتوى البيانات في الملف أو نهاية الدفق؟
يحتل النوع الداخلي أربعة بايت ، والبايت الثلاثة في البت المرتفع كلها 0. نستخدم فقط أقل بايت لها. عند مواجهة نهاية علامة الدفق ، يعود -1 (32 1S) ممثلة بأربعة بايت ، وهو ما يختلف بشكل طبيعي عن القيمة -1 (24 0 + 8 1S) التي تمثل البيانات.
التالي هو أيضًا طريقة قراءة ، لكن InputStream يوفر تطبيقًا افتراضيًا:
رمي القراءة العامة (البايت B []) ioException {return read (b ، 0 ، b.length) ؛} public int read (byte b [] ، int stow ، int len) يرمي ioException {// من أجل عدم جعل الطول طويلًا جدًا ، يمكنك عرض رمز مصدر JDK بنفسك}}هاتان الطريقتان متماثلتان بشكل أساسي. الطريقة الأولى هي نموذج خاص للطريقة الثانية ، والذي يسمح بتمرير مجموعة من البايتات وتتطلب من البرنامج ملء البايتات القراءة في الملف بدءًا من موضع فهرس الصفيف 0 لملء عدد البايتات في طول المصفوفة.
الطريقة الثانية هي أوسع قليلاً ، مما يتيح لك تحديد موضع البداية والعدد الإجمالي للبايت.
هناك العديد من الطرق الأخرى في InputStream ، والتي لا يتم تنفيذها بالتفصيل بشكل أساسي. دعونا نلقي نظرة عليه لفترة وجيزة.
ستقوم طريقة Mark بتوسيم العلم في موضع قراءة الدفق الحالي ، وستقوم طريقة إعادة الضبط بإعادة ضبط مؤشر القراءة على العلم.
في الواقع ، من المستحيل إعادة تعيين القراءة مرة أخرى لقراءة الملفات ، ولكن يتم حفظ جميع البايتات بين موضع العلم بشكل عام ونقطة إعادة التعيين مؤقتًا. عندما يتم استدعاء طريقة إعادة الضبط ، يتم تكرار القراءة في الواقع من مجموعة البايت المؤقتة المحفوظة ، لذلك يتم استخدام ReadLimit للحد من سعة ذاكرة التخزين المؤقت القصوى.
يتم استخدام الطريقة التي تدعمها Marksupported لتحديد ما إذا كان الدفق الحالي يدعم عملية القراءة "الاحتياطية" هذه.
تتشابه OutputStream و InputStream ، إلا أنه يتم كتابة أحدهما والآخر. لن نكررها هنا.
ملف بايت دفق fileinput/outputStream
ما زلنا نركز على FileInputStream ، وملف FileOutputStream متشابه.
أولاً ، يحتوي FileInputStream على المُنشئين التاليين لإنشاء كائن ما:
Public FileInputStream (اسم السلسلة) يلقي FileNotfoundException {this (name! = null؟ ملف جديد (اسم): null) ؛} Public FileInputStream (ملف الملف) يلقي FileNotFoundException {string name = (file! = null؟ file.getPath (): null) ؛ SecurityManager Security = System.GetSecurityManager () ؛ if (security! = null) {security.CheckRead (name) ؛ } if (name == null) {رمي nullpointerxception () ؛ } if (file.isinvalid ()) {رمي new fileNotfoundException ("مسار الملف غير صالح") ؛ } fd = new FileDescriptor () ؛ fd.attach (هذا) ؛ المسار = الاسم ؛ افتح (الاسم) ؛}هذان المُنشئان متماثلان بشكل أساسي ، الأول هو الشكل الخاص للأخير. في الواقع ، لا تنظر إلى الطريقة الأخيرة ، معظمها يقوم فقط بالتحقق من الأمان. النواة هي طريقة مفتوحة ، يتم استخدامها لفتح ملف.
في الأساس هذين المُنشئين ، إذا لم يكن الملف موجودًا أو مسار الملف والاسم غير قانونيين ، فسيتم إلقاء FileNotfoundException.
تذكر أننا قلنا أن هناك طريقة مجردة قراءة في الفئة الأساسية InportStream تتطلب تنفيذ جميع الفئات الفرعية ، ويتم تنفيذ FileInputStream باستخدام طريقة محلية:
public int read () remrows ioException {return read0 () ؛} private native int read0 () rems ioexception ؛ليس لدينا طريقة لاستكشاف التنفيذ المحدد لـ read0 في الوقت الحالي ، ولكن يجب أن تكون واضحًا أن وظيفة طريقة القراءة هذه تستخدم لإرجاع البايت التالي في الدفق ، والعودة -1. وهذا يعني أنه تتم قراءته حتى نهاية الملف ولا توجد بايت للقراءة.
بالإضافة إلى ذلك ، هناك بعض الأساليب الأخرى المتعلقة بالقراءة في FileInputStream ، ولكن يتم تنفيذ معظمها باستخدام الأساليب المحلية. لنلقي نظرة هنا:
الأساليب الداخلية لـ FileInputStream هي في الأساس مثل هذا ، وهناك بعض الطرق المتقدمة والمعقدة التي لا يمكننا استخدامها في الوقت الحالي. سوف نتعلمه لاحقًا. دعنا نلقي نظرة موجزة على مثال على قراءة الملف:
يبرز الفراغ الثابت العام (سلسلة [] args) ioException {fileInputStream input = new FileInputStream ("C: //users//yanga//desktop//test.txt") ؛ Byte [] Buffer = New Byte [1024] ؛ int len = input.Read (buffer) ؛ سلسلة str = سلسلة جديدة (مخزن المؤقت) ؛ system.out.println (str) ؛ system.out.println (len) ؛ input.close () ؛}نتيجة الإخراج بسيطة للغاية. سيقوم بطباعة المحتوى في ملف الاختبار الخاص بنا والعدد الفعلي للبايت القراءة ، ولكن سيكتشف الطلاب الحذرون ، كيف يمكنك التأكد من أن المحتوى في ملف الاختبار لن يتجاوز 1024 بايت؟
من أجل قراءة محتويات الملف بالكامل ، يتمثل أحد الحلول في تحديد المخزن المؤقت الكبير بما يكفي لتوقع تخزين جميع محتويات الملف قدر الإمكان.
من الواضح أن هذه الطريقة غير مرغوب فيها لأنه من المستحيل بالنسبة لنا أن ندرك الحجم الفعلي للملف المراد قراءته. إنه حل سيء للغاية لإنشاء صفيف بايت كبير.
الطريقة الثانية هي استخدام دفق صفيف البايت الديناميكي ، والذي يمكنه ضبط حجم صفيف البايت الداخلي ديناميكيًا لضمان السعة المناسبة ، والتي سنقدمها بالتفصيل لاحقًا.
بخصوص FileOutputStream ، هناك شيء آخر يجب التأكيد عليه هو مُنشئه ، والذي يحتوي على مُنشئين التاليةين:
Public FileOutputStream (اسم السلسلة ، إلحاق منطقي) FileOutputStream (ملف الملف ، إلحاق منطقي)
يشير إلحاق المعلمة إلى ما إذا كانت عملية كتابة هذا الدفق مكتوبة أو تم إلحاقها ، وسعط حقيقي ، وسائل خاطئة ، وسائل خاطئة.
bytearrayinput/outputstream
ما يسمى "تيار صفيف البايت" هو دفق يعمل حول مجموعة بايت. لا يقرأ ويكتب تدفقات إلى ملفات مثل التدفقات الأخرى.
على الرغم من أن دفق صفيف البايت ليس دفقًا قائمًا على الملفات ، إلا أنه لا يزال دفقًا مهمًا للغاية ، لأن صفيف البايت المغطى بالداخل غير ثابت ، ولكنه قابل للتمديد ديناميكيًا ، وغالبًا ما يعتمد على بعض السيناريوهات ، وهو مناسب جدًا.
BytearRayInputStream عبارة عن دفق من صفائف البايت القراءة التي يمكن إنشاء مثيل لها بواسطة المنشئ التالي:
BYTE BUF BUF [] ؛ محمي int POS ؛ COUNT المحمية ؛ public bytearrayinputStream (byte buf []) {this.buf = buf ؛ this.pos = 0 ؛ this.count = buf.length ؛} public bytearrayinputStream (byte buf [] ، int ، int length)BUF عبارة عن مجموعة بايت مغلفة داخل bytearrayinputstream. جميع عمليات قراءة BytearRayInputStream تدور حوله.
لذلك ، عند إنشاء كائن ByteArrayInputStream ، يتم تمرير مجموعة بايت مستهدفة واحدة على الأقل.
يتم استخدام سمة POS لتسجيل موضع قراءة الدفق الحالية ، ويسجل العد الموضع الأخير لآخر فهرس بايت صالح لمجموعة البايت الهدف.
بعد فهم ذلك ، ليس من الصعب قراءة طرق مختلفة لقراءتها:
// اقرأ البايت التالي المزامنة int read () {return (pos <count)؟ (buf [pos ++] & 0xff): -1 ؛} // اقرأ بايت Len ووضعها في Byte Array B Public Synchronized int (Byte B []بالإضافة إلى ذلك ، يقوم ByteArrayInputStream أيضًا بتنفيذ عملية "REPRED Read" بكل بساطة.
علامة void العامة (int readaheadlimit) {mark = pos ؛} reset void المزامنة العامة () {pos = mark ؛}نظرًا لأن ByTearRayInputStream يعتمد على صفائف البايت ، فإن جميع عمليات القراءة المتكررة أسهل في التنفيذ ، وهي كافية للتنفيذ بناءً على الفهارس.
BytearRayoutputStream هو دفق صفيف بايت مكتوب. لا تزال العديد من التطبيقات لها خصائصها الخاصة. دعونا نلقي نظرة معا.
أولاً ، مطلوب هاتان الممتلكتان:
يمثل BUF BUF المحمي []
مُنشئ:
public bytearrayoutputstream () {this (32) ؛} public bytearrayoutputstream (int size) {if (size <0) {throw new alficalargumentException ("الحجم الأولي السلبي:"+ حجم) ؛ } buf = new byte [size] ؛}تتمثل المهمة الأساسية للمشارك في تهيئة BUF البايت الداخلي ، مما يتيح لك المرور في الحجم للحد بشكل صريح من حجم صفيف البايت المتهيج ، وإلا فإن الطول الافتراضي سيكون 32.
اكتب المحتوى إلى bytearrayoutputstream من الخارج:
proid synchronised proid write (int b) {insureCapacity (count + 1) ؛ buf [count] = (byte) b ؛ COUNT + = 1 ؛} كتابة الفراغ المزامنة العامة (BYTE B [] ، int OFF ، int len) {if ((OFF <0) || (OFF> B.Length) || (len <0) || ((OFF + LEN) - B.Length> 0)) } insureCapacity (count + len) ؛ System.arrayCopy (B ، Off ، Buf ، Count ، Len) ؛ العد += len ؛}عند رؤية ذلك ، فإن الخطوة الأولى لجميع عمليات الكتابة هي استدعاء طريقة SecureCapacity ، والغرض من ذلك هو التأكد من أن صفيف البايت في الدفق الحالي يمكن أن يستوعب عملية الكتابة هذه.
هذه الطريقة هي أيضا مثيرة للاهتمام للغاية. إذا وجدت أن BUF الداخلي لا يمكنه دعم عملية الكتابة هذه بعد الحساب ، فسيتم استدعاء طريقة النمو للتوسع. يشبه مبدأ التوسع في السعة مستوى ArrayList ، الذي تم توسيعه إلى ضعف السعة الأصلية.
بالإضافة إلى ذلك ، يحتوي BytearRayoutputStream أيضًا على طريقة Writeto:
orteeto void criteTo (OutputStream Out) المتواصل العام (Out.Write ، 0 ، count) ؛}
اكتب صفيف البايت المغطى داخليًا في دفق الإخراج.
بعض الطرق المتبقية هي أيضا شائعة الاستخدام:
لاحظ أنه على الرغم من أن هذين التدفقين يسمى "التدفقات" ، إلا أنهما لا يخصصان بعض الموارد مثل التدفقات الحقيقية ، لذلك لا نحتاج إلى استدعاء طريقته الوثيقة ، وليس من غير المجدي أن نسميها (قال المسؤول ، ليس له أي تأثير).
لن يتم إصدار حالات الاختبار. سأقوم بتحميل جميع حالات الرموز المستخدمة في هذه المقالة لاحقًا. يمكنك اختيار تنزيلها بنفسك.
من أجل التحكم في الطول ، سيتم وضع التعلم المتبقي في المقالة التالية.
يتم تخزين جميع الرموز والصور والملفات في المقالة في السحابة على جيثب:
(https://github.com/singleyam/overview_java)
يمكنك أيضًا اختيار التنزيل محليًا.
لخص
ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.