1. نظرة عامة على تحميل الملف
لتحقيق وظيفة تحميل الملف في تطوير الويب ، هناك حاجة إلى خطوتين:
1. إضافة عناصر الإدخال تحميل إلى صفحة الويب
<form Action = "#" method = "post" envenpe = "multipart/form-data"> <input type = "file" name = "filename1"/> <br> <input type = "file" name = "filename2"/> <br> <input type = "prisal" value "/> <form> <!-1. بعد تعيين هذه القيمة ، عندما يقوم المتصفح بتحميل الملف ، فإنه سيقوم بإرفاق بيانات الملف بجسم رسالة طلب HTTP ، واستخدم بروتوكول MIME لوصف الملف الذي تم تحميله لتسهيل المستلم لتحليل البيانات التي تم تحميلها ومعالجتها. 3. يجب تعيين سمة الاسم للإدخال ، وإلا فلن يتم إرسال المتصفح بيانات الملف التي تم تحميلها. ->
2. اقرأ بيانات تحميل الملف في Servlet وحفظها على القرص الصلب الخادم
يوفر كائن الطلب طريقة getInputStream ، يمكن من خلالها قراءة البيانات المقدمة من العميل. ومع ذلك ، نظرًا لأن المستخدمين قد يقومون بتحميل ملفات متعددة في نفس الوقت ، فهي مهمة مزعجة للغاية للبرمجة وقراءة البيانات التي تم تحميلها مباشرة على جانب Servlet وتحليل بيانات الملف المقابلة بشكل منفصل.
على سبيل المثال ، ما يلي هو بعض محتويات بروتوكول HTTP للطلب الذي أرسله المتصفح المعترض عند تحميل الملف:
قبول اللغة: ZH-Hans-CN ، ZH-Hans ؛ q = 0.5-content-type: multipart/form-data ؛ الحدود = --------------------------- 7DFA01D1908A4UA-CPU: AMD64ACCEPT-ENCODING: GZIP ، DEFLATEUSER-AGENT: Mozilla/5.0 (Windows NT 6.2 ؛ Win64 ؛ x64 ؛ keep-alivepragma: no-cachecookie: jSessionId = 11ceff8e271ab62ce67b5a87b746b5f ----------------------------- 7dfa01d1908a4content-disposition: form-data ؛ name = "username" Zhangsan --------------------------- 7DFA01D1908A4Content-Disposition: Form-Data ؛ name = "userpass" 1234 --------------------------- 7DFA01D1908A4Content-Disposition: form-data ؛ name = "filename1" ؛ filename = "c: /users/asus/desktop/upload.txt" content-type: text/plainthis هو أول محتوى ملف! --------------------------- 7dfa01d1908a4content-disposition: form-data ؛ name = "filename1" ؛ filename = "c: /users/asus/desktop/upload2
يمكن أيضًا رؤية من البيانات المذكورة أعلاه أنه من الصعب كتابة برنامج قوي ومستقر إذا قمت بتقسيم البيانات وقراءةها يدويًا. لذلك ، لتسهيل المستخدمين لمعالجة البيانات ، توفر مؤسسة Apache Open Source مكونًا مفتوحًا للمصدر (commons-fileupload) المستخدم لمعالجة تحميل ملفات النموذج. يحتوي هذا المكون على أداء ممتاز وواجهة برمجة التطبيقات الخاصة به بسيطة للغاية في الاستخدام ، مما يتيح للمطورين تنفيذ وظيفة تحميل ملف الويب بسهولة. لذلك ، في تطوير الويب ، عادة ما يتم تنفيذ وظيفة تحميل الملف باستخدام مكون المشاع.
يجب استيراد حزمتين من الجرة: commons-fileupload ، commons-io
استجابة. printWriter writer = reponse.getWriter () ؛ // الحصول على استجابة دفق دفق servletInputStream inputStream = request.getInputStream () ؛ // الحصول على طلب دفق إدخال/* 1. قم بإنشاء diskfileitemfactory كائن ، وضبط حجم العازلة ودليل الملف المؤقت* هناك مُنشئان في هذه الفئة ، أحدهما مُبناء بدون معاملات ، والآخر هو as as ana sizethreshold ، هذه المعلمة تحدد حجم المخزن المؤقت للذاكرة ، والقيمة الافتراضية هي 10 كيلو. عندما يكون ملف التحميل أكبر من حجم المخزن المؤقت ، سيقوم مكون FileUpload بتحميل الملف باستخدام ذاكرة التخزين المؤقت المؤقتة للملف* param java.io.file ، تحدد هذه المعلمة دليل الملف المؤقت ، والقيمة الافتراضية هي System.getProperty ("java.io.tmpdir") ؛ * * إذا تم استخدام مُنشئ بدون معلمات ، فسيتم تعيين metSizeThreshold (int sizethreshold) ، setRepository (java.io.file ropository) *. int sizethreshold = 1024*1024 ؛ المصنع. مستودع الملفات = ملف جديد (request.getSession (). getServletContext (). getRealPath ("temp")) ؛ // system.out.println (request.getSession (). getServletContext (). getRealPath ("temp")) ؛ Factory.SetRepository (مستودع) ؛ / * * 2. استخدم كائن diskfileItemFactory لإنشاء كائن servletfileupload وتعيين حجم الملف الذي تم تحميله * * كائن servletfileUpload هو المسؤول عن معالجة بيانات الملف التي تم تحميلها وتغليف كل عنصر إدخال في الشكل في FileItem * طرق شائعة لهذا الكائن: * boolean ismultipartcontent (الطلب) ؛ تحديد ما إذا كان النموذج الذي تم تحميله هو نوع multipart/form-data* list parserequest (request) ؛ تحليل كائن الطلب ، لف كل عنصر إدخال في النموذج في كائن fileItem ، وإرجاع مجموعة القائمة التي تحفظ جميع fileItems* void setFilesizeMax (long filesizemax) ؛ قم بتعيين القيمة القصوى لملف واحد تم تحميلها* setSizeSemax (Sizemax طويل) ؛ حدد الحد الأقصى لقيمة المبلغ الإجمالي لـ Wenjiang* void setheaderencoding () ؛ قم بتعيين تنسيق الترميز لحل مشكلة أسماء ملفات رمز مشتعلة*/ servletFileUpload Upload = new ServletFileUpload (Factory) ؛ تحميل. حاول {parserequest = upload.parserequest (request) ؛ } catch (fileuploadexception e) {eprintStackTrace () ؛ } / * * 4. التكرار على القائمة. كل كائن FileItem ، اتصل بأسلوب iSformfield لتحديد ما إذا كان تحميل ملف* صحيح يعني أنه حقل نموذج عادي ، ثم اتصل بطرق getFieldName وطرق getTring للحصول على اسم الحقل وقيمة الحقل* FALSE هو ملف التحميل ، ثم يتم استخدام ملفات التعبئة أو تمثيل ملفات التعبئة بشكل كبير أو تمثل شكل تبديل الشخصي. من هذا الكائن هي: * منطقية Isformfield () ؛ يحدد ما إذا كان FileItem هو كائن تحميل الملف أو كائن نموذج عادي * صحيح يعني أنه حقل نموذج عادي ، * ثم اتصل على طرق GetFieldName و GetTring للحصول على اسم الحقل وقيمة الحقل * خطأ مثل ملف التحميل ، * ثم اتصل بـ GetName () للحصول على اسم ملف ملف التحميل. ملاحظة: تحمل بعض المتصفحات مسارات العميل وتحتاج إلى طرح أنفسهم * استدعاء طريقة getInputStream () للحصول على دفق إدخال البيانات ، وذلك لقراءة بيانات التحميل * delete () ؛ يعني أنه بعد إغلاق دفق إدخال FileItem ، يتم حذف الملفات المؤقتة. */for (fileItem fileItem: parserequest) {if (fileItem.isformField ()) {// يمثل الحقل العادي إذا ("اسم المستخدم" .equals (fileItem.getFieldName ())))) {String username = fileItem.getString () ؛ Writer.write ("اسم المستخدم الخاص بك:"+اسم المستخدم+"<br>") ؛ } if ("userpass" .equals (fileItem.getFieldName ())))) {string userPass = fileItem.getString () ؛ Writer.write ("كلمة المرور الخاصة بك:"+userpass+"<br>") ؛ }} آخر {// يعني ملف تم تحميله // قد يكون للملفات التي تم تحميلها بواسطة متصفحات مختلفة اسم المسار ، وتحتاج إلى قطع string clientName = fileItem.getName () ؛ اسم ملف السلسلة = "" ؛ if (clientname.contains ("//")) {// if "/" يعني اسمًا به مسار ، يتم اعتراض اسم الملف الأخير = clientname.substring (clientName.lastindexof ("//"). substring (1) ؛ } آخر {filename = clientName ؛ } uuid randomuuid = uuid.randomuuid () ؛ // إنشاء اسم ملف معرف فريد من نوعه على مستوى عالمي 128 بت = randomuuid.toString ()+اسم الملف ؛ / * * تصميم خوارزمية توليد الدليل. إذا كان إجمالي عدد الملفات التي تم تحميلها بواسطة المستخدم أمرًا بملايين أوامر الحجم أو أكثر ، فإن وضعها في نفس الدليل يتسبب في أن يكون فهرس الملف بطيئًا للغاية. * لذلك ، من الضروري للغاية تصميم بنية دليل لتخزين الملفات بطريقة مبعثرة ، وعمق * تحويل خوارزمية التجزئة uuid إلى نطاق أصغر ، * قم بتحويل رمز الهاوية من UUID إلى سلسلة من الثمانية على سبيل المثال ، فهي مبدئة في كل هذا الموجه في كل شيء. بنية الدليل الفعالة للغاية لكل من الخادم ونظام التشغيل*/ int hashuuid = randomuuid.hashCode () ؛ String hexuuid = integer.toHexString (hashuuid) ؛ //system.out.println(hexuuid) ؛ // احصل على المسار المطلق الذي يقوم به المجلد لتخزين الملف الذي تم تحميله في السلسلة filePath = request.getSession (). getServletContext (). getRealPath ("التحميل") ؛ لـ (char c: hexuuid.tochararray ()) {filePath = filePath+"/"+c ؛ } // إذا لم يكن الدليل موجودًا ، فقم بإنشاء ملف دليل على مستوى الثامن filePathFile = ملف جديد (FilePath) ؛ if (! filePathfile.exists ()) {filePathfile.mkdirs () ؛ } // اقرأ الملف من دفق إدخال الطلب واكتب إلى server inputStream inputStream2 = fileItem.getInputStream () ؛ // قم بإنشاء ملف على ملف ملف Server Side = ملف جديد (FilePath+"/"+filename) ؛ BufferEdoutputStream BOS = جديد BufferEdoutPutStream (FileOutputStream جديد (ملف)) ؛ Byte [] Buffer = New Byte [10*1024] ؛ int len = 0 ؛ بينما ((len = inputStream2.Read (Buffer ، 0 ، 10*1024))! =-1) {Bos.Write (Buffer ، 0 ، len) ؛ } writer.write ("قمت بتحميل الملف"+clientName+"بنجاح <br>") ؛ // أغلق المورد bos.close () ؛ inputStream2.Close () ؛ }} // لاحظ أن الملف الذي تم تحميله من Eclipse يتم حفظه في دليل تشغيل المشروع ، وليس في دليل المشروع في مساحة العمل.2. المشكلات التي تحتاج إلى اهتمام خاص لتحميل الملف: (يتم توفير كل هذه المشكلات مع حلول بسيطة في الكود أعلاه)
1. أين تخزين الملفات
لضمان أمان الخادم ، يجب حفظ الملف الذي تم تحميله في دليل الويب الخاص بالتطبيق ، أو دليل لا يديره خادم الويب. إذا قام المستخدم بتحميل ملف باستخدام رمز قابل للتنفيذ ، مثل ملف JSP ، والوصول إليه وفقًا لمسار الوصول إلى الربط ، فيمكنه فعل أي شيء على جانب الخادم.
2. من أجل منع العديد من المستخدمين من تحميل الملفات بنفس اسم الملف ، مما يؤدي إلى الكتابة فوق الملف ، يجب على ملف تحميل الملف التأكد من أن الملف الذي تم تحميله له اسم ملف فريد .
إعادة تسمية باستخدام اسم ملف UUID + تحميل المستخدم
حول uuid:
يشير معرف Uuid (المعرف الفريد العالمي) على مستوى العالم إلى الرقم الذي تم إنشاؤه على الجهاز ، مما يضمن أنه فريد من نوعه لجميع الآلات في نفس الوقت والمساحة. وفقًا للمعايير التي وضعتها مؤسسة Open Software Foundation (OSF) ، وعنوان بطاقة Ethernet ، و Time NanoSecond ، ورمز معرف الرقاقة والعديد من الأرقام الممكنة. إنه يتكون من مزيج من الأجزاء التالية: التاريخ والوقت الحاليين (الجزء الأول من UUID يرتبط بالوقت. إذا قمت بإنشاء uuid آخر بعد بضع ثوانٍ بعد إنشاء uuid ، فإن الجزء الأول مختلف ، والباقي هو نفسه) ، وسلسلة الشبكة ، أو لا يتم الحصول على تسلسل الشبكة ، أو لا يتم الحصول على بطاقة الشبكة بشكل آخر). أن سلسلة النتيجة التي تم إنشاؤها ستكون طويلة نسبيا.
إنه رقم طويل 128 بت ، يتم التعبير عنه بشكل عام في سداسي عشري. تتمثل الفكرة الأساسية للخوارزمية في إنشاء GUID مع بطاقة شبكة الجهاز والتوقيت المحلي والرقم الفوري. من الناحية النظرية ، إذا كان الجهاز يولد 100000 GUIDS في الثانية ، فيمكن ضمان (بمعنى الاحتمال) أنه لن يتم تكرار 3240 عامًا.
بدءًا من JDK1.5 ، أصبح توليد UUIDs أمرًا بسيطًا ، معتقدًا أن JDK قد نفذت UUIDs:
java.util.uuid ، فقط نسميها مباشرة.
uuid uuid = uuid.randomuuid () ؛
السلسلة s = uuid.randomuuid (). toString () ؛ // معرف المفتاح الأساسي المستخدم لإنشاء قاعدة البيانات جيدة جدًا. .
يتكون Uuid من رقم ستة عشر أرقامًا ، يتم التعبير عنه في شكل
550E8400-E29B-11D4-A716-446655440000
3. من أجل منع العديد من الملفات في دليل واحد والتأثير على قراءة الملفات وسرعة الكتابة ، يجب أن يختار البرنامج الذي يتولى تحميل الملفات خوارزمية توليد بنية الدليل المناسبة بناءً على إجمالي حجم التحميل الممكن ، وتخزين الملفات التي تم تحميلها بطريقة مشتتة. على سبيل المثال ، استخدم طريقة HashCode لإنشاء دليل متعدد المستويات.
4. إذا قام المستخدمون المختلفين بتحميل نفس الملف ، فليست هناك حاجة لتخزين العديد من النسخ من نفس الملف على جانب الخادم. هذا مضيعة للموارد. يجب تصميم خوارزمية لحل مشكلة الملفات المكررة.
5. مبدأ تقنية JSP يطبق تلقائيًا متعدد الخيوط. لذلك ، لا يحتاج المطورون إلى النظر في عمليات متعددة الخيوط لتحميل الملفات
3. تنزيل الملف
<٪ ArrayList <string> filenames = new ArrayList <string> () ؛ filens.add ("file/aa.txt") ؛ filens.add ("file/bb.jpg") ؛ لـ (اسم ملف السلسلة: أسماء الملفات) {٪> <form action = "downloadservlet" method = "get"> <input type = "hidden" name = "filename" value = "<٪ = filename ٪>" /> <input type = "submit" value = "download: <٪ = filename ٪>" /> < /form> <٪} ٪> اسم ملف السلسلة = request.getParameter ("اسم الملف") ؛ urlname urlname = urlencoder.encode (اسم الملف ، "UTF-8") ؛ // منع الاستجابة الصينية المشوهة. FileInputStream fis = جديد fileInputStream (ملف جديد (request.getSession (). getServletContext (). getRealPath (filename)))) ؛ BufferedInputStream BIS = جديد BufferedInputStream (FIS) ؛ servleToutPutStream SOS = response.getOutputStream () ؛ Byte [] Buffer = New Byte [1024] ؛ int len = 0 ؛ بينما ((len = bis.read (buffer ، 0 ، 1024))! =-1) {sos.write (buffer ، 0 ، len) ؛ } bis.close () ؛ fis.close () ؛4. استخدم مكون SmartUpload في SSH لتبسيط تحميل الملف وتنزيله
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.