المصدر: مدونة Baoyu
1. سأشرح مبدأ التحميل بدون مكونات شيئًا فشيئًا مع مثال HTML للعميل كما يلي. لتصفح المرفقات التي تم تحميلها، نقوم بتمرير العنصر <input type="file">، ولكن تأكد من تعيين سمة enctype للنموذج على "multipart/form-data":
<طريقة النموذج = "post" action = "upload.asp" enctype = "multipart/form-data">
<التسمية>
<نوع الإدخال = "ملف" اسم = "ملف 1" />
</التسمية>
<br />
<نوع الإدخال = "نص" اسم = "اسم الملف" قيمة = "اسم الملف الافتراضي"/>
<br />
<نوع الإدخال = "إرسال" القيمة = "إرسال"/>
<نوع الإدخال = "إعادة تعيين" القيمة = "إعادة تعيين"/>
</النموذج>
في برنامج asp في الخلفية، كان من السهل جدًا الحصول على بيانات ASCII المقدمة بواسطة النموذج. ولكن إذا كنت بحاجة إلى الحصول على الملف الذي تم تحميله، فيجب عليك استخدام طريقة BinaryRead لكائن الطلب لقراءته. تقوم طريقة BinaryRead بقراءة ثنائية لعدد محدد من البايتات من دفق الإدخال الحالي. هناك شيء واحد يجب ملاحظته وهو أنه بمجرد استخدام طريقة BinaryRead، لن يكون من الممكن استخدام مجموعات Request.Form أو Request.QueryString. بالدمج مع خاصية TotalBytes لكائن الطلب، يمكن تحويل كافة البيانات المرسلة بواسطة النموذج إلى بيانات ثنائية، ولكن يتم ترميز كافة هذه البيانات. أولاً، دعونا نلقي نظرة على كيفية ترميز هذه البيانات. هل هناك أي قواعد يجب اتباعها؟ قم بتقسيم التعليمات البرمجية في التعليمات البرمجية، وقمنا بتحويل القراءة الثنائية بواسطة BinaryRead إلى نص وإخراجها في ملف upload.asp في الخلفية (ملاحظة). لا تقم بتحميل ملفات كبيرة الحجم في هذا المثال، وإلا فقد يتعطل المتصفح):
<%
خافت البيانات الثنائية، PostData
الحجم = الطلب.TotalBytes
البيانات الثنائية = Request.BinaryRead(الحجم)
PostData = BinaryToString(biData,Size)
Response.اكتب "<pre>" & PostData & "</pre>" 'استخدم التنسيق مسبقًا وأخرجه كما هو
"قم بتحويل الدفق الثنائي إلى نص بمساعدة مجموعة السجلات."
الدالة BinaryToString(biData,Size)
كونست أدلونجفارشار = 201
تعيين RS = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary"، adLongVarChar، الحجم
RS. مفتوح
RS.AddNew
RS("mBinary").AppendChunk(biData)
تحديث RS
BinaryToString = RS("mBinary").Value
RS.إغلاق
وظيفة النهاية
%>
من أجل التبسيط، قم بتحميل أبسط ملف نصي (G:homepage.txt، مع المحتوى "Baoyu: http://www.webuc.net ") لاختباره، واحتفظ بالقيمة الافتراضية "اسم الملف الافتراضي" في ملف اسم ملف مربع النص أرسل وشاهد الإخراج:
--------------------------------7d429871607fe
ترتيب المحتوى: اسم بيانات النموذج = "file1"؛
نوع المحتوى: نص/عادي
باويو: http://www.webuc.net
--------------------------7d429871607fe
ترتيب المحتوى: اسم بيانات النموذج = "اسم الملف"؛
اسم الملف الافتراضي
-----------------------------7d429871607fe--
يمكن ملاحظة أنه بالنسبة للعناصر الموجودة في النموذج، "----- --------------------------7d429871607fe" تستخدم هذه الحدود لفصل القطع إلى قطع، وتوجد بعض المعلومات الوصفية في بداية كل قطعة على سبيل المثال: المحتوى-التصرف: اسم بيانات النموذج = "اسم الملف"، في معلومات الوصف، يمكنك معرفة اسم عنصر النموذج من خلال الاسم = "اسم الملف". إذا كان هناك محتوى مثل filename="G:homepage.txt"، فهذا يعني أنه ملف تم تحميله، وإذا كان ملفًا تم تحميله، فستحتوي معلومات الوصف على سطر آخر من نوع المحتوى: نص/عادي للوصف نوع محتوى الملف . يتم فصل معلومات الوصف ومعلومات النص عن طريق فواصل الأسطر.
حسنًا، الأمر واضح بشكل أساسي. وفقًا لهذه القاعدة، نحن نعرف كيفية فصل البيانات ومعالجة البيانات المنفصلة، ومع ذلك، فقد أغفلنا تقريبًا مشكلة واحدة، وهي القيمة الحدية ("-------" في ما سبق مثال) كيف عرفت -----------------------7d429871607fe")؟ تختلف قيمة الحدود هذه في كل مرة تقوم فيها بتحميلها. ولحسن الحظ، يمكن الحصول عليها من خلال Request.ServerVariables("HTTP_CONTENT_TYPE") في ملف asp. على سبيل المثال، في المثال أعلاه، يكون محتوى HTTP_CONTENT_TYPE: "multipart/form-data؛ border=-- --------------------------7d429871607fe"، مع هذا، لا يمكننا فقط تحديد ما إذا كان enctype = "multipart/form- data "(إذا لم يتم استخدامه، ليست هناك حاجة لتنفيذه أدناه)، يمكنك أيضًا الحصول على قيمة الحدود border=------------------------------------- ----- 7d429871607fe. (ملاحظة: قيمة الحد التي تم الحصول عليها هنا تحتوي على "--" في البداية أقل من قيمة الحد أعلاه. ومن الأفضل إضافتها.)
أما بالنسبة لعملية كيفية تحليل البيانات، فلن أخوض في التفاصيل ليس أكثر من استخدام وظائف مثل InStr وMid لفصل البيانات التي نريدها.
2. عند التحميل على شكل أجزاء، يجب أن يعكس تقدم التسجيل شريط التقدم في الوقت الفعلي. والجوهر هو معرفة مقدار البيانات التي حصل عليها الخادم الحالي في الوقت الفعلي؟ وبالعودة إلى عملية التحميل، فإننا نقوم بتنفيذها من خلال Request.BinaryRead(Request.TotalBytes). أثناء عملية الطلب، لا يمكننا معرفة مقدار البيانات التي حصل عليها الخادم الحالي. لذلك لا يمكننا استخدام الحل إلا إذا تمكنا من تقسيم البيانات التي تم الحصول عليها إلى أجزاء، ثم بناءً على عدد الكتل التي تم تحميلها، يمكننا حساب حجم التحميل حاليًا! وهذا يعني أنه إذا كانت 1K عبارة عن كتلة واحدة، فسيتم تقسيم تدفق الإدخال لتحميل 1 ميجا بايت إلى 1024 كتلة للحصول عليها، على سبيل المثال، إذا حصلت على 100 كتلة، فهذا يعني أنه تم تحميل 100 كيلو. عندما اقترحت الحظر، وجده العديد من الأشخاص أمرًا لا يصدق، لأنهم تجاهلوا أن طريقة BinaryRead لا يمكنها قراءة الحجم المحدد فحسب، بل يمكنها أيضًا القراءة بشكل مستمر.
اكتب مثالاً للتحقق من سلامة قراءة الكتلة، بناءً على المثال الموجود الآن (لاحظ أن هذا المثال لا يقوم بتحميل ملفات كبيرة، وإلا فقد يتسبب في تعطل المتصفح):
<%
خافت البيانات الثنائية، PostData، TotalBytes، ChunkBytes
ChunkBytes = 1 * 1024 ' حجم القطعة هو 1 كيلو بايت
TotalBytes = Request.TotalBytes 'الحجم الإجمالي
PostData = "" ' تم تحويل البيانات إلى نوع نص
ReadBytes = 0 'تمت التهيئة إلى 0
"اقرأ في أجزاء
افعل بينما ReadBytes <TotalBytes
biData = Request.BinaryRead(ChunkBytes) 'القطعة الحالية
PostData = PostData & BinaryToString(biData,ChunkBytes) 'تحويل القطعة الحالية إلى نص ولصقها
ReadedBytes = ReadedBytes + ChunkBytes 'تسجيل حجم القراءة
إذا ReadedBytes > TotalBytes ثم ReadedBytes = TotalBytes
حلقة
Response.اكتب "<pre>" & PostData & "</pre>" ' استخدم ما قبل وأخرج التنسيق كما هو
'تحويل الدفق الثنائي إلى نص
الدالة BinaryToString(biData,Size)
كونست أدلونجفارشار = 201
تعيين RS = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary"، adLongVarChar، الحجم
RS. مفتوح
RS.AddNew
RS("mBinary").AppendChunk(biData)
تحديث RS
BinaryToString = RS("mBinary").Value
RS.إغلاق
وظيفة النهاية
%>
حاول تحميل الملف النصي الآن. تثبت نتائج الإخراج أن المحتوى المقروء في الكتل مكتمل، وفي حلقة while، يمكننا تسجيل الحالة الحالية في التطبيق في كل مرة يتم فيها التكرار، وبعد ذلك يمكننا اجتياز الوصول إلى تطبيق للحصول على شريط تقدم التحميل ديناميكيًا.
أيضًا: في المثال أعلاه، يتم استخدام ربط السلسلة إذا كنت تريد ربط البيانات الثنائية، فيمكنك استخدام أسلوب الكتابة لكائن ADODB.Stream كما يلي:
Set bSourceData = createobject("ADODB.Stream")
.)
bSourceData.Open
bSourceData.Type = 1 'ثنائي
افعل بينما ReadBytes <TotalBytes
بيانات ثنائية = Request.BinaryRead(ChunkBytes)
bSourceData.Write biData ' استخدم طريقة الكتابة مباشرة لكتابة دفق الملف الحالي في bSourceData
ReadedBytes = ReadedBytes + ChunkBytes
إذا ReadedBytes > TotalBytes ثم ReadedBytes = TotalBytes
Application("ReadedBytes") = ReadedBytes
حلقة
3. احفظ الملف الذي تم تحميله، واحصل على البيانات المقدمة من خلال Request.BinaryRead بعد فصل الملف الذي تم تحميله، تختلف طريقة الحفظ حسب نوع البيانات:
بالنسبة للبيانات الثنائية، يمكنك حفظ الدفق الثنائي مباشرة من خلال طريقة SaveToFile. كائن ADODB.Stream يصبح ملفًا.
بالنسبة للبيانات النصية، يمكنك حفظ البيانات النصية في ملف من خلال طريقة الكتابة لكائن TextStream.
يمكن تحويل البيانات النصية والبيانات الثنائية بسهولة إلى بعضها البعض لتحميل الملفات الصغيرة، ولا يوجد فرق بين الاثنين. ومع ذلك، لا تزال هناك بعض الاختلافات عند الحفظ بين الطريقتين بالنسبة لكائن ADODB.Stream، يجب تحميل جميع البيانات قبل حفظها كملف، لذلك فإن تحميل الملفات الكبيرة باستخدام هذه الطريقة سيشغل مساحة كبيرة من الذاكرة. وبالنسبة لكائن TextStream، بعد إنشاء الملف، يمكنك كتابة جزء منه في وقت واحد وكتابته عدة مرات، وميزة ذلك هي أنه لن يشغل مساحة ذاكرة الخادم، بالإضافة إلى مبدأ الحصول على البيانات الكتل التي تم تحليلها أعلاه، يمكننا كتابة كل جزء من البيانات التي تم تحميلها إلى الملف. لقد قمت بتجربة ذات مرة وقمت بتحميل ملف يزيد حجمه عن 200 ميجابايت على نفس الجهاز. باستخدام الطريقة الأولى، استمرت الذاكرة في الزيادة، مما أدى بشكل مباشر إلى عدم كفاية الذاكرة الافتراضية للكمبيوتر على الرغم من أن شريط التقدم يشير إلى أن الملف قد تم تحميله، إلا أنه في النهاية، لا يزال الملف غير محفوظ. باستخدام الطريقة الأخيرة، لا يوجد أي تغيير في الذاكرة أثناء عملية التحميل.
4. المشاكل التي لم يتم حلها رأيت Bestcomy على المدونة يصف أن مكون التحميل الخاص بـ Asp.Net يمكن أن يكون مستقلاً عن Sever.SetTimeOut، ولكن في Asp لم أتمكن من القيام بذلك لتحميل الملفات الكبيرة، ولا يمكنني سوى استخدام Server.SetTimeOut يتم ضبطها على قيمة كبيرة جدًا. لا أعرف إذا كان هناك حل أفضل.
إذا استخدمنا طريقة الكتابة لكائن TextStream عند حفظ ملف، فإذا قام المستخدم بمقاطعة نقل الملف عند التحميل، فإن جزء الملف الذي تم تحميله لا يزال موجودًا، وسيكون من الرائع استئناف التحميل. المشكلة الرئيسية هي أنه على الرغم من أن طريقة Request.BinaryRead يمكنها القراءة على شكل كتل، إلا أنها لا تستطيع تخطي قسم معين من القراءة!
5. الاستنتاج تم شرح المبدأ بشكل واضح، لكن الكود الفعلي أكثر تعقيدًا من ذلك، حيث أن الجزء الأكثر صعوبة هو تحليل البيانات التي تم الحصول عليها تحليل ما إذا كان ينتمي إلى معلومات الوصف، لا يزال عنصر النموذج عبارة عن ملف تم تحميله، وما إذا كان الملف قد تم تحميله...
أعتقد أنه بناءً على الوصف أعلاه، يمكنك أيضًا تطوير مكون التحميل القوي الخاص بك بدون مكونات. أعتقد أن المزيد من الأشخاص يهتمون فقط بالرمز ولا يعرفون كيفية كتابته بأنفسهم، ربما ليس لديهم الوقت، وربما لا يكون المستوى كافيًا، وقد أصبح المزيد منه عادة... لقد فعلت ذلك رأيت الكثير من التقنيات على مقال CSDN المكون من ثمانية أجزاء - فقرة من الوصف، ثم كل التعليمات البرمجية. إن تعليم الرجل الصيد ليس جيدًا مثل تعليمه الصيد. إذا أعطيتك رمزًا، فقد لا تفكر في السبب وتستخدمه فقط. عندما تواجه مشكلة مماثلة في المرة القادمة، ما زلت لا تعرف السبب. آمل أن تساعد هذه المقالة المزيد من الأشخاص على تعلم شيء ما، والأهم هو "تنوير" شيء ما!