1. عملية تحويل جافا ترميز
نستخدم دائمًا ملف فئة Java للتفاعل مع المستخدمين بشكل مباشر (الإدخال والإخراج) ، وقد يحتوي النص الوارد في هذا المحتوى التفاعلي على الصينية. سواء كانت فئات Java تتفاعل مع قاعدة البيانات أو مع الصفحة الأمامية ، فإن دورة حياتهم هي دائمًا مثل هذا:
(1) يكتب المبرمجون رمز البرنامج من خلال محرر على نظام التشغيل وحفظ نظام التشغيل بتنسيق .java. نسمي هذه الملفات الملفات المصدر.
(2) تجميع هذه الملفات المصدر من خلال javac.exe في JDK لتشكيل فئة .class.
(3) قم بتشغيل هذه الفئات مباشرة أو نشرها في حاوية ويب للحصول على نتيجة الإخراج.
لوحظت هذه العمليات من منظور الماكرو ، ومن المؤكد أنه من غير الممكن فهم هذا. نحن بحاجة إلى أن نفهم حقًا كيف يتم تشفير Java وفك تشفيره:
الخطوة 1: عندما نستخدم محررًا لكتابة ملف مصدر Java ، سيستخدم ملف البرنامج تنسيق الترميز الافتراضي لنظام التشغيل (عادةً ما يستخدم نظام التشغيل الصيني لدينا تنسيق ترميز GBK) لتشكيل ملف .java. يتم حفظ ملف Source Java في File.Encoding تنسيق الترميز الذي يدعمه نظام التشغيل بشكل افتراضي. يمكن للرمز التالي عرض قيمة معلمة ملف النظام.
System.out.println (System.getProperty ("file.encoding")) ؛ الخطوة 2: عندما نستخدم javac.exe لتجميع ملف java الخاص بنا ، ستؤكد JDK أولاً ترميز معلمة التجميع الخاصة به لتحديد مجموعة أحرف الكود المصدر. إذا لم نحدد معلمة التجميع ، فسيحصل JDK أولاً على الملف الافتراضي لنظام التشغيل. معلمة الترميز ، ثم يقوم JDK بتحويل برنامج مصدر Java الذي كتبناه من File.Encoding Format إلى تنسيق Unicode الافتراضي داخل Java ووضعه في الذاكرة.
الخطوة 3: يكتب JDK المعلومات التي تم تجميعها وحفظها على الذاكرة أعلاه في ملف الفئة لتشكيل ملف .class. في هذا الوقت ، يتم ترميز ملف .class ، مما يعني أنه يتم تحويل المحتويات في ملفات .Class المشتركة إلى تنسيق ترميز Unicode ، سواء كانت أحرفًا صينية أو إنجليزية.
في هذه الخطوة ، تختلف طريقة معالجة ملفات مصدر JSP قليلاً: تدعو حاوية الويب إلى برنامج التحويل البرمجي JSP. سيقوم برنامج التحويل البرمجي JSP أولاً بالتحقق مما إذا كان ملف JSP يحتوي على تنسيق ترميز الملف. إذا لم يتم تعيينه ، فسيقوم برنامج التحويل البرمجي JSP بالاتصال بـ JDK لتحويل ملف JSP إلى فئة Servlet المؤقتة باستخدام طريقة الترميز الافتراضية ، ثم تجميعها في ملف .class والحفاظ عليه في مجلد مؤقت.
الخطوة 4: قم بتشغيل الفصل المترجم: سيكون هناك عدة مواقف هنا
(1) تشغيل مباشرة على وحدة التحكم.
(2) فئة JSP/Servlet.
(3) بين فئة Java وقاعدة البيانات.
كل من هذه المواقف الثلاثة سيكون لها طرق مختلفة للقيام بذلك.
1. فصول تعمل على وحدة التحكم
في هذه الحالة ، ستقرأ JVM أولاً ملف الفئة المحفوظ في نظام التشغيل في الذاكرة. في هذا الوقت ، يتم ترميز ملف الفئة في الذاكرة في Unicode ، ثم يقوم JVM بتشغيله. إذا احتاج المستخدم إلى إدخال المعلومات ، فسيتم ترميز إدخال المعلومات من قبل المستخدم بتنسيق ملف. بعد تشغيل البرنامج ، يتم تحويل النتيجة إلى File.Encoding Format وإعادتها إلى نظام التشغيل والإخراج إلى الواجهة. العملية برمتها على النحو التالي:
في العملية بأكملها أعلاه ، لا يمكن أن تحدث أي أخطاء في أي تحويل ترميز متضمن ، وإلا ستحدث رمز مشجعة.
2. فئة Servlet
نظرًا لأن ملفات JSP سيتم تحويلها في النهاية إلى ملفات Servlet (ولكن موقع التخزين مختلف) ، سنقوم أيضًا بتضمين ملفات JSP هنا.
عندما يطلب المستخدم servlet ، تقوم حاوية الويب باستدعاء JVM لتشغيل Servlet. بادئ ذي بدء ، سيقوم JVM بتحميل فئة Servlet في الذاكرة. رمز servlet في الذاكرة في تنسيق ترميز Unicode. ثم يدير JVM servlet في الذاكرة. أثناء التشغيل ، إذا كنت بحاجة إلى قبول البيانات التي تم تمريرها من العميل (مثل البيانات التي تم تمريرها بواسطة النماذج وعنوان URL) ، فستقبل حاوية الويب البيانات الواردة. أثناء عملية الاستقبال ، إذا قام البرنامج بتعيين ترميز المعلمات الواردة ، فسيتم اعتماد تنسيق الترميز. إذا لم يتم تعيينه ، يتم اعتماد تنسيق ترميز ISO-8859-1 الافتراضي. بعد البيانات المستلمة ، ستقوم JVM بتحويل تنسيق الترميز إلى Unicode وتخزينه في الذاكرة. بعد تشغيل servlet ، يتم إنشاء نتائج الإخراج ، ولا يزال تنسيق الترميز لنتائج الإخراج هذه أحاديًا. بعد ذلك مباشرة ، سترسل حاوية الويب مباشرة سلسلة تنسيق ترميز Unicode التي تم إنشاؤها إلى العميل. إذا كان البرنامج يحدد تنسيق الترميز في وقت الإخراج ، فسيتم إخراجه إلى المتصفح وفقًا لتنسيق الترميز المحدد. خلاف ذلك ، تم اعتماد تنسيق الترميز ISO-8859-1 الافتراضي. مخطط تدفق العملية بأكمله كما يلي:
3. جزء قاعدة البيانات
نحن نعلم أن العلاقة بين برامج Java وقواعد البيانات متصلة من خلال برنامج تشغيل JDBC ، وبرنامج تشغيل JDBC الافتراضي بتنسيق الترميز ISO-8859-1. وهذا يعني ، عندما نقوم بنقل البيانات إلى قاعدة البيانات من خلال برنامج Java ، ستقوم JDBC أولاً بتحويل البيانات بتنسيق ترميز Unicode إلى تنسيق ترميز ISO-8859-1 ، ثم تخزينها في قاعدة البيانات ، أي عندما تحفظ قاعدة البيانات البيانات ، فإن الشكل الافتراضي هو ISO-88-8.
2. الترميز وفك التشفير
سيؤدي ما يلي إلى إنهاء عمليات الترميز وفك التشفير التي تحتاجها Java إلى أداءها في تلك المناسبات ، وفرز العملية الوسيطة بالتفصيل لزيادة عملية الترميز وفك التشفير في Java. هناك أربعة سيناريوهات رئيسية في Java تتطلب الترميز وفك التشفير:
(1): عملية I/O.
(2): الذاكرة
(3): قاعدة البيانات
(4): Javaweb
فيما يلي بشكل أساسي يقدم السيناريوهين السابقين. طالما تم تعيين جزء قاعدة البيانات بشكل صحيح ، فلن تكون هناك مشكلة. هناك الكثير من سيناريوهات Javaweb ، وتحتاج إلى فهم ترميز عنوان URL ، والحصول ، والنشر ، وفك تشفير Servlet ، وبالتالي فإن مقدمة LZ لسيناريو Javaweb.
1. i/o العملية
في LZ السابقة ذكرت أن المشكلة المشوهة ليست أكثر من عدم تناسق تنسيق الترميز أثناء عملية الترميز. على سبيل المثال ، يتم استخدام UTF-8 للترميز ويستخدم GBK لفك تشفير. ومع ذلك ، فإن السبب الأساسي هو أن هناك مشكلة في تحويل الطابع إلى البايت أو البايت إلى الشحن ، والسيناريو الرئيسي للتحويل في هذه الحالة هو عملية الإدخال/الإخراج. بالطبع ، تشمل عمليات الإدخال/الإخراج بشكل أساسي الشبكة I/O (أي ، Javaweb) و Disk I/O. تم تقديم الشبكة I/O في القسم التالي.
أولاً ، دعونا نلقي نظرة على عملية الترميز I/O.
InputStream هي الفئة الفائقة لجميع فئات دفق الإدخال البايت ، والقارئ هو الفئة المجردة للقارئ. تقرأ Java الملفات بطريقة مقسمة إلى دفق البايت وبمدفق الأحرف. InputStream والقارئ هما الفئات الفائقة لهذين طريقتين للقراءة.
بواسطة Byte ، عادةً ما نستخدم طريقة InputStream.Read () لقراءة البايتات في دفق البيانات (قراءة () فقط يقرأ بايت واحد فقط في وقت واحد ، وهو بطيء للغاية. عادة ما نستخدم القراءة (البايت [])) ، ثم حفظه في صفيف بايت [] ، وأخيراً تحويله إلى سلسلة. عندما نقرأ ملفًا ، يعتمد ترميز البايتات على تنسيق الترميز المستخدم بواسطة الملف ، وستشارك أيضًا مشكلة الترميز في عملية التحويل إلى السلسلة. إذا كانت تنسيقات الترميز مختلفة بين الاثنين ، فقد تحدث المشكلة. على سبيل المثال ، هناك مشكلة في تنسيق ترميز test.txt هو UTF-8 ، وبالتالي فإن تنسيق ترميز دفق البيانات الذي تم الحصول عليه عند قراءة ملف من خلال دفق بايت هو UTF-8. إذا لم نحدد تنسيق الترميز أثناء التحويل إلى السلسلة ، فنحن نستخدم تنسيق ترميز النظام (GBK) افتراضيًا إلى فك التشفير. نظرًا لأن تنسيقات الترميز للاثنين غير متناسقة ، فسيحدث الرمز المشتعلة بالتأكيد في عملية بناء السلسلة ، على النحو التالي:
ملف الملف = ملف جديد ("c: //test.txt") ؛ inputStream input = new FileInputStream (ملف) ؛ StringBuffer Buffer = new StringBuffer () ؛ بايت [] بايت = بايت جديد [1024] ؛ لـ (int n ؛ (n = input.Read (bytes))! =-1 ؛) {buffer.append (سلسلة جديدة (بايت ، 0 ، n)) ؛ } system.out.println (buffer) ؛ نتيجة الإخراج مشوهة ...
المحتوى في test.txt هو: أنا سم.
لتجنب التعليمات البرمجية المشوهة ، حدد تنسيق الترميز أثناء عملية بناء السلسلة بحيث تكون تنسيقات الترميز للاثنين متسقة أثناء الترميز وفك التشفير:
buffer.append (سلسلة جديدة (بايت ، 0 ، n ، "utf-8")) ؛
حسب الحرف ، يمكن اعتبار دفق الأحرف بمثابة دفق غلاف. لا تزال طبقتها الأساسية تستخدم دفق بايت لقراءة البايتات ، ثم تقوم بفك تشفير بايت القراءة في أحرف باستخدام طريقة الترميز المحددة. في Java ، القارئ عبارة عن طبقة فائقة تقرأ تدفقات الأحرف. لذلك من المنظور السفلي ، لا يوجد فرق بين قراءة الملفات عن طريق البايت والقراءة حسب الحرف. عند القراءة ، يتم ترك قراءة الأحرف مع بايت في كل مرة ، وقراءة تدفقات البايت بايت في وقت واحد.
Byte & Character Conversion Conversion Bytes to Formes هو بشكل أساسي InputStreamReader. يتم شرح واجهة برمجة التطبيقات على النحو التالي: InputStreamReader هو الجسر بين دفق البايت إلى دفق الأحرف: إنه يقرأ البايتات باستخدام charset المحددة وتفككها في أحرف. يمكن تحديد الحرف التي تستخدمها أو يتم تقديمها بشكل صريح بواسطة الاسم ، أو يمكن أن تقبل مجموعة الأحرف الافتراضية للنظام الأساسي. كل مكالمة إلى طريقة read () في InputStreamReader تؤدي إلى قراءة واحدة أو أكثر من القراءة من دفق الإدخال الأساسي. لتمكين التحويل الفعال من البايت إلى الحرف ، يمكنك قراءة المزيد من البايتات من الدفق الأساسي مسبقًا ، وتجاوز البايتات المطلوبة لتلبية عملية القراءة الحالية. شرح API واضح للغاية. لا يزال inputStreamReader يستخدم قراءة البايت عند قراءة الملف في الأسفل. بعد قراءة البايتات ، يحتاج إلى تحليل شخصيات وفقًا لتنسيق ترميز محدد. إذا لم يكن هناك تنسيق ترميز محدد ، فإنه يعتمد تنسيق الترميز الافتراضي للنظام.
string file = "c: //test.txt" ؛ String charset = "utf-8" ؛ // اكتب أحرفًا للتحويل إلى FileOutputStream OutputStream = FileOutputStream (ملف جديد) ؛ OutputStreamWriter Writer = New OutputStreamWriter (OutputStream ، Charset) ؛ جرب {writer.write ("أنا cm") ؛ } أخيرًا {writer.close () ؛ } // قراءة البايتات للتحويل إلى أحرف fileInputStream inputStream = جديد fileInputStream (ملف) ؛ inputStreamReader Reader = جديد inputStreamReader (inputStream ، charset) ؛ StringBuffer Buffer = new StringBuffer () ؛ char [] buf = new Char [64] ؛ عدد int = 0 ؛ حاول {بينما ((count = reader.read (buf))! = -1) {buffer.append (buf ، 0 ، count) ؛ }} أخيرًا {reader.close () ؛ } system.out.println (buffer) ؛ 2. الذاكرة
أولاً ، دعونا نلقي نظرة على الكود البسيط التالي
سلسلة s = "أنا cm" ؛ Byte [] bytes = S.GetBytes () ؛ السلسلة S1 = سلسلة جديدة (بايت ، "GBK") ؛ السلسلة S2 = سلسلة جديدة (بايت) ؛
في هذا الرمز ، نرى ثلاث عمليات تحويل تشفير (ترميز واحد ، فكان فك الارتباط). دعونا نلقي نظرة على string.getTytes () أولاً:
البايت العام [] getBytes () {return stringCoding.encode (value ، 0 ، value.length) ؛ }استدعاء داخليًا طريقة stringCoding.encode ():
static byte [] encode (char [] ca ، int Off ، int len) {string csn = charset.defaultcharset (). name () ؛ جرب {// استخدم charset name encode () الذي يوفر التخزين المؤقت. Return Encode (CSN ، CA ، Off ، Len) ؛ } catch (UnsupportedEncodingException X) {warnunsupportedcharset (CSN) ؛ } حاول {return encode ("ISO-8859-1" ، CA ، Off ، Len) ؛ } catch (UnsupportedEncodingException X) {// إذا تم الضغط على هذا الرمز أثناء تهيئة VM ، فإن MessageUtils هي // الطريقة الوحيدة التي سنكون قادرين على الحصول على أي نوع من رسائل الخطأ. MessageUtils.err ("ISO-8859-1 Charset غير متوفر:" + X.ToString ()) ؛ // إذا لم نتمكن من العثور على ISO-8859-1 (ترميز مطلوب) ، فإن الأشياء // مخطئة بشكل خطير في التثبيت. System.exit (1) ؛ العودة لاغية. }}تقوم طريقة Encode (char [] paramarrayofchar ، int paramint1 ، int paramint2) بالاتصال أولاً بتنسيق الترميز الافتراضي للنظام. إذا لم يتم تحديد تنسيق الترميز ، فسيتم تنفيذ عملية الترميز افتراضيًا باستخدام تنسيق الترميز ISO-8859-1. مزيد من التعميق هو على النحو التالي:
سلسلة CSN = (charsetName == NULL)؟ "ISO-8859-1": CharsetName ؛
في نفس الطريقة ، يمكنك أن ترى أن مُنشئ سلسلة جديدة يسمى طريقة stringCoding.decode ():
السلسلة العامة (بايت بايت [] ، إزاحة int ، طول int ، charset charset) {if (charset == null) رمي nullpointerxception جديد ("charset") ؛ checkbounds (البايت ، الإزاحة ، الطول) ؛ this.value = stringCoding.decode (charset ، bytes ، الإزاحة ، الطول) ؛ } طريقة فك التشفير وتشفير التعامل مع تنسيق الترميز بنفس الطريقة.
بالنسبة للحالتين أعلاه ، نحتاج فقط إلى تعيين تنسيق ترميز موحد ، ولن تكون هناك مشاكل مشوهة بشكل عام.
3. تنسيق الترميز والترميز
أولاً ، انظر إلى مخطط فئة ترميز Java
أولاً ، قم بتعيين فئة الرسم البياني وفقًا للمخطط المحدد ، ثم قم بإنشاء كائن chartSetEncoder وفقًا لـ ChartSet ، وأخيراً استدعاء charsetencoder.encode لتشفير السلسلة. ستتوافق أنواع الترميز المختلفة مع فئة ، ويتم الانتهاء من عملية الترميز الفعلي في هذه الفئات. يوضح مخطط التوقيت التالي عملية الترميز التفصيلية:
من خلال مخطط الفئة المشفرة هذا ومخطط التوقيت ، يمكنك فهم عملية الترميز التفصيلية. سيقوم ما يلي بتشفير ISO-8859-1 و GBK و UTF-8 من خلال رمز بسيط.
اختبار الفئة العامة test02 {public static void main (string [] args) يلقي UnsupportedEncodingException {string string = "i am cm" ؛ test02.printChart (string.tochararray ()) ؛ Test02.printChart (String.getBytes ("ISO-8859-1")) ؛ Test02.printChart (String.getBytes ("GBK")) ؛ Test02.printChart (String.getBytes ("UTF-8")) ؛ } / *** تحويل char إلى hexadecimal* / public static void printchart (char [] chars) {for (int i = 0 ؛ i <chars.length ؛ i ++) {system.out.print (integer.toHexString (char [i])+") ؛ } system.out.println ("") ؛ } / ** * byte تم تحويله إلى hex * / public static void printchart (byte [] bytes) {for (int i = 0 ؛ i <bytes.length ؛ i ++) {string hex = integer.toHexString (bytes [i] & 0xff) ؛ if (hex.length () == 1) {hex = '0' + hex ؛ } system.out.print (Hex.ToupperCase () + "") ؛ } system.out.println ("") ؛ }}الإخراج:
6211 662f 20 63 6d 3f 20 63 6d CE D2 CA C7 20 63 6D E6 88 91 E6 98 AF 20 63 6D
من خلال البرنامج ، يمكننا أن نرى أن نتيجة "I Am CM" هي:
char []: 6211 662f 20 63 6d ISO-8859-1: 3F 3F 20 63 6d GBK: CE D2 CA C7 20 63 6D UTF-8: E6 88 91 E6 98 AF 20 63 6D
الصورة كما يلي: