مقدمة
في المقالة السابقة ، قدمنا المحتوى ذي الصلة في إطار دفق بايت ملف Java ، بينما ستركز مقالتنا على المحتوى ذي الصلة لدفق أحرف الملفات.
بادئ ذي بدء ، يجب أن يكون من الواضح أن ملفات معالجة دفق البايت تعتمد على بايت ، في حين أن ملفات معالجة دفق الأحرف تعتمد على الأحرف كوحدات أساسية.
ولكن في الواقع ، فإن جوهر تشغيل دفق الأحرف هو تغليف العمليين لعملية "بايت تيار" + "الترميز". هل تعتقد ذلك؟ سواء كنت تكتب حرفًا إلى ملف ، فأنت بحاجة إلى تشفير الأحرف إلى ثنائية ، ثم كتابتها إلى الملف بالبايت كوحدة أساسية ، أو تقرأ حرفًا للذاكرة ، فأنت بحاجة إلى قراءتها بالبايت كوحدة أساسية ثم نقلها إلى أحرف.
من المهم أن نفهم هذا ، والذي سيحدد فهمك العام لتيارات الأحرف. دعونا نلقي نظرة على تصميم واجهات برمجة التطبيقات ذات الصلة معًا.
قارئ فئة قاعدة/كاتب
قبل أن نتعلم رسميًا فئة قاعدة دفق الأحرف ، نحتاج إلى معرفة كيفية تمثيل الشخصية في Java.
بادئ ذي بدء ، يتم ترميز الحرف الافتراضي في Java هو: UTF-8 ، ونعلم أن الأحرف المشفرة UTF-8 يتم تخزينها باستخدام 1 إلى 4 بايت ، والأحرف الأكثر شيوعًا ، يتم استخدام بايت أقل.
يتم تعريف نوع Char على أنه أحجام بايت ، أي بالنسبة للشخصيات العادية ، يمكن لـ Char تخزين شخصية ، ولكن بالنسبة لبعض مجموعات الأحرف التكميلية ، غالبًا ما يتم استخدام اثنين من chars لتمثيل شخصية.
القارئ هو الفئة الأساسية لقراءة تدفقات الأحرف ، ويوفر عمليات قراءة الأحرف الأساسية. دعونا نلقي نظرة معا.
لنلقي نظرة على مُنشئه أولاً:
قفل الكائن المحمي ؛ قارئ محمي () {this.lock = this ؛} قارئ محمي (قفل الكائن) {if (lock == null) {رمي nullpointerxception () جديد ؛ } this.lock = lock ؛}القارئ هو فئة مجردة ، لذلك ليس هناك شك في أن هؤلاء المنشئين يتم استدعاؤهم إلى الفئات الفرعية ويستخدمون لتهيئة كائنات قفل القفل ، والتي سنشرحها بالتفصيل لاحقًا.
int public read () remrows ioException {char cb [] = new char [1] ؛ if (read (cb ، 0 ، 1) == -1) return -1 ؛ Else Return CB [0] ؛} int public read (char cbuf []) يلقي ioException {return read (cbuf ، 0 ، cbuf.length) ؛} int int read int char cbuf [] int ، int len)عملية قراءة الشخصية الأساسية هي كل شيء هنا. يتم استخدام الطريقة الأولى لقراءة حرف. إذا تمت قراءته حتى نهاية الملف ، فسيتم إرجاع -1. يتم استلام الشيء نفسه مع int مثل نوع قيمة الإرجاع ، لماذا لا تستخدم char؟ والسبب هو نفسه ، كل ذلك بسبب عدم اليقين في تفسير القيمة -1.
تشبه الطريقة الثانية الطريقة الثالثة ، وقراءة أحرف طول محدد من الملف ووضعها في صفيف الهدف. الطريقة الثالثة هي طريقة مجردة ، والتي يجب تنفيذها بواسطة الفئات الفرعية ، في حين أن الطريقة الثانية تستند إليها.
هناك بعض الطرق الأخرى المتشابهة:
هذه الطرق معروفة بالفعل وتشبه عمومًا مدخلاتنا ، وليس لها تنفيذ أساسي. لن أخوض في التفاصيل هنا ، يمكنك معرفة ما بداخله تقريبًا.
الكاتب هو دفق حرف مكتوب ، يستخدم لكتابة حرف واحد أو أكثر في ملف. بالطبع ، لا تزال طريقة الكتابة المحددة طريقة مجردة ويتم تنفيذها بواسطة فئات فرعية ، لذلك لن نكررها هنا.
محول inpuststramreader/outputStreamWriter
ترث تدفقات أحرف المحول من قارئ أو كاتب فئة أساسية ، والتي تعد أعضاء مهمين للغاية في نظام دفق الأحرف. الوظيفة الرئيسية هي تحويل دفق بايت إلى دفق أحرف. دعنا أولاً نأخذ محول القراءة كمثال.
بادئ ذي بدء ، أعضاءها الأساسيون:
Private Final StreamDecoder SD ؛
StreamDecoder هو وحدة فك ترميز تستخدم لتحويل عمليات مختلفة من البايت إلى العمليات المقابلة للأحرف. سوف نذكرها بشكل مستمر في المقدمة اللاحقة ، ولن نشرح ذلك بشكل موحد هنا.
ثم هناك المنشئ:
public inputStreamReader (inputStream in) {super (in) ؛ حاول {sd = StreamDecoder.ForInputStreamReader (in ، this ، (string) null) ؛ } catch (UnsupportedEncodingException e) {رمي خطأ جديد (e) ؛ }} public inputStreamReader (inputStream in ، String charsetName) يلقي UnsupportedEncodingException {super (in) ؛ if (charsetName == null) رمي nullpointerxception جديد ("charsetName") ؛ sd = StreamDecoder.ForInputStreamReader (في ، هذا ، charsetname) ؛}الغرض من هذين المُنشئين هو تهيئة هذا فك التشفير. تسمى الطريقة ForInputStreamReader ، ولكن المعلمات مختلفة. دعونا نلقي نظرة على تنفيذ هذه الطريقة:
هذا هو نمط مصنع ثابت نموذجي. لا يوجد شيء يمكن قوله حول المعلمات الثلاثة ، VAR0 و VAR1 ، يمثلون مثيل دفق البايت ومثيل المحول على التوالي.
تمثل المعلمة VAR2 في الواقع اسم ترميز حرف. إذا كان NULL ، فسيتم استخدام ترميز الأحرف الافتراضية للنظام: UTF-8.
أخيرًا ، يمكننا الحصول على مثيل من وحدة فك الترميز.
يتم تنفيذ جميع الطرق التي تم تقديمها بعد ذلك تقريبًا عن طريق الاعتماد على وحدة فك الترميز هذا.
السلسلة العامة getencoding () {return sd.getencoding () ؛} public int read () remrows ioException {return sd.read () ؛} public int read (char cbuf []لا يزال رمز التنفيذ للطرق ذات الصلة في وحدة فك الترميز معقدة نسبيًا. لن نجري بحثًا متعمقًا هنا ، لكن فكرة التنفيذ العامة هي: عملية "Byte Stream Reading + Decoding".
بالطبع ، يجب أن يكون هناك مثيل معاكس للدفاع في OutputStreamWriter لترميز الأحرف.
بصرف النظر عن هذا ، لا تختلف بقية العمليات ، إما مكتوبة إلى الملف من خلال صفيف أحرف ، مكتوبة إلى الملف من خلال سلسلة ، أو مكتوبة إلى الملف من خلال 16 بتات من int.
ملف حرف الملفات fileereader/الكاتب
يمكن القول أن دفق حرف الملف بسيط للغاية. لا توجد طريقة أخرى باستثناء المنشئ ، ويعتمد بالكامل على دفق بايت الملف.
لنأخذ FileReader كمثال.
يرث FileReader من InputStreamReader ، ولديه فقط المُنشئين الثلاثة التاليين: Publireader (اسم ملف السلسلة) يلقي FileNotfoundException {super fileInputStream (filename)) ؛ FileInputStream (FD)) ؛}من الناحية النظرية ، يجب أن تستند جميع تدفقات الأحرف إلى محولنا ، لأنه يوفر فقط تحويل من طابع بايت ، سواء أكنت تكتب أو تقرأ ، فهو لا ينفصل عنه.
لا يمتد FileReader لدينا أي من أساليبه الخاصة. طريقة تشغيل الأحرف التي يتم تنفيذها مسبقًا في فئة Parent Class InportStreamReader كافية له. يحتاج فقط إلى المرور في مثيل دفق البايت المقابل.
وينطبق الشيء نفسه على FilewRiter ، لن أخوض في التفاصيل هنا.
دفق صفيف شخصية chararrayreader/كاتب
تتشابه صفائف الأحرف وتيارات صفيف البايت ، سواء لحل الموقف الذي يوجد فيه حجم ملف غير مؤكد ويتطلب قراءة كمية كبيرة من المحتوى.
نظرًا لأنها توفر آلية توسع ديناميكي داخليًا ، فلا يمكنهم استيعاب الملفات المستهدفة فحسب ، بل يمكنهم أيضًا التحكم في حجم الصفيف حتى لا يخصص الكثير من الذاكرة وإهدار الكثير من مساحة الذاكرة.
خذ chararrayreader كمثال
محمي char buf [] ؛ public chararrayreader (char buf []) {this.buf = buf ؛ this.pos = 0 ؛ this.count = buf.length ؛} chararrayReader العامة (char buf [] ، int ، طول int) {// ..}تتمثل المهمة الأساسية للمشارك في تهيئة صفيف الأحرف إلى سمة BUF الداخلية. ستستند جميع عمليات القراءة اللاحقة على مثيل دفق صفيف الأحرف إلى صفيف أحرف BUF.
فيما يتعلق بالطرق الأخرى لـ ChararrayReader و ChararRayWriter ، لن أكررها هنا ، والتي تشبه أساسًا دفق صفيف البايت في المقالة السابقة.
بالإضافة إلى ذلك ، هناك أيضًا StringReader و StringWriter. في الواقع ، هو في الأساس مثل دفق صفيف الأحرف. بعد كل شيء ، جوهر السلسلة هو صفيف شار.
BufferedReader/الكاتب
وبالمثل ، يعد BufferedReader/Writer دفقًا مخزن المؤقت ، وهو أيضًا تيار ديكور ، يستخدم لتوفير وظائف التخزين المؤقت. بشكل عام يشبه دفق البايت العازلة لدينا ، دعنا نقدمه باختصار هنا.
القارئ الخاص في ؛ خاص char cb [] ؛ int int int int int int int int int int
CB عبارة عن مجموعة أحرف تقرأ بعض الأحرف من دفق الملفات. يمكنك تهيئة طول هذا الصفيف في المُنشئ ، وإلا سيتم استخدام القيمة الافتراضية البالغة 8192.
Public int read () rems IoException {..} public int read (char cbuf [] ، int Off ، int len) {...}فيما يتعلق بالقراءة ، يعتمد ذلك على طريقة قراءة سمة الأعضاء في. كنوع من القارئ ، غالبًا ما يتم قراءة طريقة مثيل inputstream الذي يتم الاعتماد عليه داخليًا.
لذلك ، لا يمكن فصل جميع تدفقات الأحرف تقريبًا عن مثيل دفق البايت.
لن أكررها هنا حول BufferedWriter. إنه مشابه بشكل أساسي ، باستثناء أن أحدهم يقرأ والآخر يكتب ، ويدور حول صفيف الشخصية الداخلية.
دفق الطباعة القياسي
هناك نوعان رئيسيان من تدفقات الطباعة ، PrintStream و PrintWriter. السابق هو تيار بايت والأخير هو دفق حرف.
يعتبر هذان الجداولان لدمج التدفقات تحت فئات كل منهما. هناك طرق تغليف داخلية غنية ، لكن التنفيذ معقد بعض الشيء. دعونا نلقي نظرة أولاً على دفق بايت Printstream:
هناك العديد من المنشئين الرئيسيين:
من الواضح أن المُنشئين البسيطين سيعتمدون على المُنشئين المعقدين ، والذي يعتبر بالفعل "روتينًا قديمًا" لتصميم JDK. ما يميزه عن تدفقات البايت الأخرى هو أن PrintStream يوفر Flag Autoflush يحدد ما إذا كان سيتم تحديث ذاكرة التخزين المؤقت تلقائيًا.
التالي هو طريقة الكتابة لـ PrintStream:
بالإضافة إلى ذلك ، فإن PrintStream تغلف أيضًا عددًا كبيرًا من طرق الطباعة ويكتب أنواعًا مختلفة من المحتوى إلى ملفات ، مثل:
بالطبع ، لا تكتب هذه الأساليب حقًا ثنائيًا رقميًا إلى ملف ، ولكن ببساطة كتابة سلاسلها المقابلة إلى ملف ، على سبيل المثال:
طباعة (123) ؛
الملف النهائي ليس البيان الثنائي المقابل لـ 123 ، ولكن فقط السلسلة 123 ، وهو دفق الطباعة.
يقوم دفق الأحرف المخزنة المستخدمة بواسطة PrintStream بتنفيذ جميع عمليات الطباعة. إذا تم تحديد التحديث التلقائي ، فسيتم تحديث المخزن المؤقت تلقائيًا عند مواجهة رمز الخط الجديد "/n".
لذلك ، يدمج PrintStream جميع طرق الإخراج في تدفقات البايت وتيارات الأحرف ، حيث يتم استخدام طريقة الكتابة لعمليات دفق البايت ويتم استخدام طريقة الطباعة لعمليات دفق الأحرف ، والتي يجب توضيحها.
أما بالنسبة لـ PrintWriter ، فهو دفق حرف كامل يعمل تمامًا ضد الشخصيات. سواء كانت طريقة الكتابة أو طريقة الطباعة ، فهي عملية دفق الأحرف.
خلاصة القول ، قضينا ثلاث مقالات تشرح عمليات البايت وعمليات دفق الأحرف في جافا. بايت دفق يكمل نقل البيانات بين القرص والذاكرة بناءً على البايتات. الأكثر نموذجية هي دفق حرف الملف ، وتطبيقاتها كلها طرق محلية. مع قدرات نقل البايت الأساسية ، يمكننا أيضًا تحسين الكفاءة من خلال التخزين المؤقت.
التنفيذ الأساسي لتيارات الأحرف هو inputstreamreader و outputstreamwriter. من الناحية النظرية ، يمكنهم بالفعل إكمال عمليات دفق الأحرف الأساسية ، لكنها تقتصر فقط على العمليات الأساسية. ما هو ضروري لبناء مثيلاتهم هو "مثيل دفق بايت" + "تنسيق ترميز".
لذلك ، فإن العلاقة بين دفق الأحرف ودفق البايت مثل المعادلة أعلاه. تتمثل الخطوة اللازمة لكتابة حرف في ملف القرص في تشفير الحرف بتنسيق الترميز المحدد ، ثم استخدم دفق البايت لكتابة الحرف المشفر إلى الملف. عملية القراءة هي عكس ذلك.
يتم تخزين جميع الرموز والصور والملفات في المقالة في السحابة على جيثب:
(https://github.com/singleyam/overview_java)
يمكنك أيضًا اختيار التنزيل محليًا.
لخص
ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.