MAX_PATH ومطبّات المسارات وأسماء الملفّات في Windows ── حدّ 260 حرفاً، الأسماء المحجوزة، النقطة الأخيرة، حساسيّة الأحرف
· آخر تحديث: · غو كومورا · MAX_PATH, مسار الملفّ, المسار الطويل, اسم الملفّ, NTFS, Win32, C#, .NET, تطوير Windows, تحقيق في الأعطال, الاستشارة التقنيّة
«لا يظهر خطأ ‹الملفّ غير موجود› إلّا على جهاز مستخدم واحد بعينه» «تمّ النسخ لكن يتعذّر فتح ذلك الملفّ» ── في تحقيقات أعطال تطبيقات الأعمال التي تتضمّن إدخال وإخراج الملفّات، ليست الحالات التي يتبيّن في النهاية أنّ السبب هو طول المسار أو اسم الملفّ نفسه نادرة. يحشو المستخدمون اسم المشروع والتاريخ في اسم المجلّد، ويحفرون التسلسل الهرميّ عميقاً، ويتجاوزون توقّعاتنا بسهولة.
المزعج في هذا المجال هو أنّ القيود مقسَّمة إلى طبقات عدّة ── «قيد Win32 API» و«قيد نظام الملفّات» و«قيد الصدفة (Explorer)» و«قيد زمن تشغيل .NET» ── فيصعب معرفة ما يمكن معالجته وما يبقى قائماً. يرتّب هذا المقال، إلى جانب التعامل العمليّ في C#، حقيقة MAX_PATH=260 حرفاً، وشروط التعامل المشروع مع المسارات الطويلة، ومطبّات أسماء الملفّات كالأسماء المحجوزة مثل CON والنقطة الأخيرة، وحتّى التعامل مع حالة الأحرف.
1. الخلاصة أوّلاً
- MAX_PATH=260 هو قيد Win32 API يشمل «حرف محرّك الأقراص + نقطتين رأسيّتين + شرطة مائلة عكسيّة + سلسلة مسار بحدّ أقصى 256 حرفاً + محرف NUL الختاميّ». أنظمة الملفّات (كـ NTFS) تستطيع التعامل مع مسارات أطول من ذلك بكثير، وإضافة بادئة
\\?\إلى النسخة اليونيكودية من الـ API يتيح تحديد نحو 32,767 حرفاً إجمالاً.12 - إلغاء حدّ الـ 260 حرفاً يتطلّب، ابتداءً من Windows 10 الإصدار 1607، كلاًّ من «LongPathsEnabled=1 في السجلّ» و«longPathAware في بيان التطبيق» معاً. لا يُفعَّل الأمر بأحدهما فقط.3
- زمن تشغيل .NET (Core) / .NET 5 وما بعده لا يُجري فحص MAX_PATH، ويتعامل مع المسارات الطويلة ضمنيّاً. أمّا .NET Framework فباستهداف 4.6.2 فما بعده يُزال فحص الـ 260 حرفاً على مستوى زمن التشغيل.45
- لكن تطبيقات غير داعمة للمسار الطويل تبقى قائمة فعليّاً، والوثائق الرسميّة نفسها تنصّ صراحةً على أنّ الصدفة (Explorer) قد لا تفسّر بصورة صحيحة مساراً يمكن لـ Win32 API إنشاءه.1
- لا يمكن استخدام الأحرف
< > : " / \ | ? *والمحارف الضابطة (0 إلى 31) في اسم الملفّ، وCON وPRN وAUX وNUL وCOM1 إلى 9 وLPT1 إلى 9 تُعامَل كأسماء محجوزة حتّى بإضافة امتداد (كـ CON.txt).6 - تُحذَف المسافة والنقطة الزائدتان في آخر الاسم بصمت ضمن عمليّة تطبيع المسار. هذا سبب حوادث من نوع «قصدتَ تحديد ‹hoge.› فتحوّل إلى ‹hoge›»، وتعذّر الوصول من Windows إلى ملفّ أنشأه نظام تشغيل آخر بمسافة زائدة في آخر الاسم.67
- الإعداد الافتراضيّ لاسم الملفّ في Windows هو «يحافظ على حالة الأحرف لكن لا يميّزها». تدعم NTFS أيضاً التمييز على مستوى المجلّد (
fsutil.exe file setCaseSensitiveInfo)، لكنّ تطبيقات Windows نفسها قد لا تستطيع مواكبة ذلك.89 - من ناحية التنفيذ، انتبه إلى أنّ دمج المسارات عبر
Path.Combine«يُسقِط الوسائط السابقة عند تمرير وسيط مُجذَّر (rooted)» (Path.Joinخيار متاح أيضاً في سلسلة .NET Core)، وعقِّم أسماء الملفّات القادمة من إدخال المستخدم عبرPath.GetInvalidFileNameCharsمع فحص ذاتيّ للأسماء المحجوزة والحرف الأخير.1011
2. حقيقة MAX_PATH=260
الحدّ الأقصى لطول المسار في Win32 API معرَّف، باستثناء بعض الحالات، بأنّه MAX_PATH=260 حرفاً. لهذا الرقم 260 تفصيل داخليّ. يتكوّن المسار المحليّ من «حرف محرّك الأقراص، ونقطتين رأسيّتين، وشرطة مائلة عكسيّة، وأجزاء الاسم المفصولة بشرطات مائلة عكسيّة، ومحرف NUL الختاميّ»، فمثلاً بالنسبة إلى محرّك D فإنّ الحدّ الأقصى هو «D:\ + سلسلة مسار من 256 حرفاً + NUL ختاميّ».1
بعبارة أخرى، إن ظننتَ أنّ الـ 260 حرفاً هي «الطول القابل للاستخدام في اسم الملفّ»، فأنت في الواقع تخسر 4 أحرف بسبب ترميز محرّك الأقراص وNUL الختاميّ. وكقيد أدقّ، بما أنّ واجهات إنشاء المجلّدات تحتاج إلى هامش لإلحاق اسم ملفّ بصيغة 8.3، فإنّ مسار المجلّد لا يمكن أن يتجاوز MAX_PATH ناقص 12 حرفاً.1
المهمّ أنّ هذا قيد على مستوى طبقة Win32 API، وليس حدّاً لنظام الملفّات. تدعم NTFS أسماء ملفّات طويلة ومسارات ممتدّة، وتقبل النسخة اليونيكودية من كثير من دوالّ Win32 مساراً ممتدّاً يبلغ نحو 32,767 حرفاً إجمالاً. حدّ كلّ عنصر مكوِّن للمسار (اسم مجلّد أو ملفّ واحد) هو القيمة التي تُعيدها GetVolumeInformation، وعموماً 255 حرفاً.12
هذه الفجوة بين «الـ API عند 260، ونظام الملفّات عند نحو 32,767» هي بالذات مصدر أعطال الميدان. مسار أُنشئ بأداة معيّنة قد لا يمكن فتحه بأداة أخرى (أو حتّى تطبيقك الخاصّ) ── هذا التناقض يحدث بشكل مشروع تماماً. حالة استنساخ (git clone) مستودع عميق داخل مجلّد باسم طويل ثمّ تعذّر البناء بعد ذلك، مثال نموذجيّ مذكور في الوثائق الرسميّة نفسها.1
يُذكَر أنّ .NET Framework القديم كان يرمي System.IO.PathTooLongException عندما يبلغ طول المسار الكامل 260 حرفاً أو أكثر. عند رؤية هذا الاستثناء، ابدأ بالاشتباه في طول المسار.12
3. طرق تجاوز حاجز الـ 260 حرفاً وشروطها
هناك طريقتان رئيسيّتان للتعامل مع المسارات الطويلة: «بادئة \\?\» و«تفعيل المسارات الطويلة على مستوى نظام التشغيل».
3.1. بادئة \\?\
بإضافة \\?\ إلى بداية سلسلة المسار، يتوقّف Win32 API عن تحليل السلسلة ويمرّرها كما هي إلى نظام الملفّات مباشرةً. بهذا يمكن تجاوز حدّ MAX_PATH (تكون مسارات UNC بصيغة \\?\UNC\server\share). لكن توجد شروط وآثار جانبيّة.16
- يجب أن تكون النسخة اليونيكودية من الـ API (كتلك المنتهية بـ W، أو استدعاءات .NET التي تستخدم UTF-16 مباشرةً).
- بما أنّ التطبيع يُتجاوَز، لا يمكن استخدام فاصل
/ولا تحديد نسبيّ عبر.أو... لا يمكن إلحاق\\?\بمسار نسبيّ، لذا يبقى المسار النسبيّ دائماً مقيَّداً بـ MAX_PATH.1 - ليست كلّ الواجهات داعمة، ويلزم التحقّق من إمكانيّة الدعم في مرجع كلّ API على حدة.6
3.2. تفعيل المسارات الطويلة في Windows 10 1607 فما بعده ── الشرط هو «كلاهما معاً»
ابتداءً من Windows 10 الإصدار 1607، يمكن إزالة قيد MAX_PATH من كثير من دوالّ Win32 الشائعة الخاصّة بالملفّات والمجلّدات (كـ CreateFileW وFindFirstFileW وGetFileAttributesW). لكن ذلك يفترض اشتراك (opt-in) من جانب التطبيق، ويلزم استيفاء الشرطين التاليين معاً.3
- أن تكون قيمة السجلّ
LongPathsEnabled(من نوع REG_DWORD) الموجودة فيHKLM\SYSTEM\CurrentControlSet\Control\FileSystemمساوية لـ 1. يمكن ضبطها أيضاً عبر سياسة المجموعة «إعدادات الكمبيوتر > القوالب الإداريّة > النظام > نظام الملفّات > تفعيل مسارات Win32 الطويلة». - أن يحتوي بيان التطبيق (application manifest) على عنصر
longPathAware.
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</windowsSettings>
</application>
# جانب السجلّ (بصلاحيّات مسؤول)
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" `
-Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
الاستفسار من نوع «ضبطتُ السجلّ لكنّه لا يعمل» غالباً ما يكون سببه إغفال جانب البيان (manifest). كما تشدّد الوثائق الرسميّة نفسها على أنّ «إعداد السجلّ هذا لا يؤثّر إلّا في التطبيقات المعدَّلة صراحةً للاستفادة من الميزة الجديدة». كذلك، تُخزَّن قيمة السجلّ مؤقّتاً (cache) على مستوى العمليّة عند أوّل استدعاء لدالّة ملفّات، ولا تُعاد قراءتها طوال حياة العمليّة. قد يكون إعادة التشغيل لازماً لضمان انعكاس تغيير الإعداد في جميع التطبيقات.3
3.3. الوضع في .NET
- .NET (Core) / .NET 5 فما بعده: لا يُجري زمن التشغيل فحص MAX_PATH، ويتعامل مع المسارات الطويلة ضمنيّاً. لا حاجة لشيفرة خاصّة من جانب التطبيق.4
- .NET Framework: باستهداف 4.6.2 فما بعده، يُزال فحص الـ 260 حرفاً على مستوى زمن التشغيل، ويقتصر
PathTooLongExceptionعندئذٍ على حالتَي «تجاوز 32,767 حرفاً» أو «إعادة نظام التشغيل خطأً». حتّى التطبيقات القائمة التي تستهدف إصداراً أقدم يمكنها الاشتراك (opt-in) عبر مفتاح AppContext من نوعSwitch.System.IO.BlockLongPaths=false(مع تعطيل معالجة المسار القديم عبرSwitch.System.IO.UseLegacyPathHandling=false).512 - كي تُمرِّر تطبيقات .NET Framework مساراً طويلاً في العمل الفعليّ، يلزم إلى جانب إعدادات زمن التشغيل أعلاه الجمع بين تفعيل المسار الطويل من جهة نظام التشغيل والبيان. توثيق دعم المسار الطويل في NuGet.exe يذكر صراحةً هذا التكوين (Windows 10 1607 فما بعده + بيان longPathAware + تعطيل UseLegacyPathHandling) كمثال فعليّ.13
3.4. الواقع الباقي رغم كلّ ذلك ── «تطبيقات غير داعمة»
حتّى بعد كلّ هذا، لا تصبح جميع التطبيقات في العالم قادرة على التعامل مع المسارات الطويلة. تنصّ الوثائق الرسميّة صراحةً على أنّ «متطلّبات الصدفة (shell) ونظام الملفّات مختلفة. قد لا تفسّر واجهة الصدفة بصورة صحيحة مساراً يمكن لـ Win32 API إنشاءه»1، وبالفعل، لا تزال هناك أدوات لا تدّعي دعم المسار الطويل (فمثلاً توثيق NuGet يذكر أنّ Visual Studio أو msbuild -t:restore عند استعادة الحزم لا يدعمان المسار الطويل13). حتّى إن استطاع تطبيقك إنشاء ملفّ بمسار طويل، فهل يستطيع المستخدم فتحه عبر Explorer أو أداة أخرى؟ مسألة منفصلة تماماً. القرار التصميميّ الذي يأخذ هذا التناقض بعين الاعتبار مجموع في جدول القرار في الفصل 6.
4. الأحرف الممنوعة والأسماء المحجوزة للأجهزة، والنقطة والمسافة الأخيرتان
المنطقة الملغومة الأخرى إلى جانب طول المسار هي قواعد اسم الملفّ نفسه. ننظّم من القاعدة الرسميّة النقاط التي يسهل التعثّر بها في تطبيقات الأعمال.6
| التصنيف | المحتوى | ملاحظة |
|---|---|---|
| الأحرف المحجوزة | < > : " / \ \| ? * |
يشمل \ (و/) فاصل المسار، و: الخاصّ بمحرّك الأقراص |
| المحارف الضابطة | القيمة الصحيحة 0 (NUL) و1 إلى 31 | غير مسموحة إلّا داخل تدفّق بيانات بديل (alternate data stream) |
| أسماء الأجهزة المحجوزة | CON, PRN, AUX, NUL, COM1 إلى COM9, LPT1 إلى LPT9 (والأرقام العلويّة COM¹ إلى ³, LPT¹ إلى ³) | غير مسموحة حتّى بإضافة امتداد (NUL.txt وNUL.tar.gz تُعادل NUL) |
| الحرف الأخير | اسم ينتهي بمسافة أو نقطة | يقبله نظام الملفّات لكن لا تدعمه الصدفة وواجهة المستخدم |
4.1. الأسماء المحجوزة للأجهزة ── حتّى CON.txt ممنوع
CON وNUL أسماء أجهزة من عصر MS-DOS، ولا تزال باقية حتّى اليوم كأسماء محجوزة في مساحة أسماء NT. لذا لا يمكن إنشاء ملفّ باسم «CON» بالطرق المعتادة، وحتّى بإضافة امتداد كما في CON.txt يُفسَّر الأمر كاسم محجوز.6 الظهور الميدانيّ لهذه المشكلة هو محاولة حفظ سجلّ اتّصال منفذ تسلسليّ باسم كـ «COM1.log» وحدوث خلل، أو تعذّر فتح مجلّد باسم «aux» أُنشئ من جانب Linux على Windows.
كملاحظة إضافيّة، من ناحية مواصفات تطبيع المسار، كانت المسارات التي تبدأ بأسماء محجوزة مثل «CON» أو «COM1.TXT» تُحوَّل تقليديّاً إلى مسار جهاز (\\.\CON) عند تفسيرها. تغيّر هذا التفسير في Windows 11، حيث أصبح الإشارة إلى جهاز قديم (legacy) تتطلّب تحديداً كاملاً بصيغة \\.\CON.7 مع ذلك، بما أنّ أنظمة تشغيل قديمة وتطبيقات قائمة كثيرة تبقى على التفسير التقليديّ، يبقى الاستنتاج بضرورة تجنّب الأسماء المحجوزة كأسماء لبيانات العمل صحيحاً دون تغيير.
4.2. المسافة والنقطة الأخيرتان تختفيان «بصمت»
تنصّ قاعدة التسمية الرسميّة على «ألّا ينتهي اسم الملفّ أو المجلّد بمسافة أو نقطة».6 وبتعمّق أكثر، يوجد في تطبيع مسار Windows قاعدة صريحة هي «إن لم ينتهِ المسار بمحرف فاصل، تُزال جميع النقاط والمسافات (U+0020) الزائدة في آخره».7
المزعج في هذا في العمل الفعليّ هو أنّه لا يُنتِج خطأً، بل يتحوّل بصمت إلى اسم آخر. إذا أدخل المستخدم اسماً مثل «تقرير v2.»، فالذي يُنشَأ هو «تقرير v2». وعلى العكس، ملفّ من نوع «report » (بمسافة زائدة) أُنشئ عبر SMB من جانب Linux، لا يمكن الوصول إليه عبر تحديد المسار العاديّ في Windows لأنّ التطبيع يغيّر الاسم. الوسيلة للوصول إلى هذه «الأسماء المشروعة التي لا يصل إليها التطبيع» هي بادئة \\?\ التي تتجاوز التطبيع. وتنصّ الوثائق الرسميّة نفسها على هذا الاستخدام صراحةً بقولها إنّ ملفّاً باسم مثل hidden. «لا يمكن الوصول إليه بأيّ طريقة أخرى».7
يُذكَر أنّ النقطة في بداية الاسم مشروعة (اسم مثل .gitignore يمكن إنشاؤه دون مشكلة).6
5. حالة الأحرف: «تُحفَظ لكن لا تُميَّز»
السلوك الافتراضيّ لنظام ملفّات Windows هو case-preserving, case-insensitive (يحفظ الحالة لكن لا يميّزها). إن أنشأتَ اسماً باسم Readme.txt، يُحفَظ ذلك الشكل عند العرض، لكن عند البحث أو المقارنة تُتجاهَل حالة الأحرف، فيُصار إلى الملفّ نفسه أيضاً عبر README.TXT. حرف محرّك الأقراص أيضاً لا يميّز حالة الأحرف بالمثل.86
تنصّ قاعدة التسمية الرسميّة، الموجَّهة لمطوّري التطبيقات، على «لا تفترض تمييز حالة الأحرف (اعتبر OSCAR وOscar وoscar الاسم نفسه)»، بينما تذكر في الوقت نفسه أنّ NTFS نفسها تدعم تمييز حالة الأحرف بأسلوب POSIX (لكنّه معطَّل افتراضيّاً).6
يظهر هذا للعيان في تكامل Linux. ابتداءً من Windows 10 البناء (build) 17107، يمكن تفعيل تمييز حالة الأحرف على مستوى المجلّد.9
# في PowerShell بصلاحيّات مسؤول
fsutil.exe file setCaseSensitiveInfo C:\work\linux-src enable
fsutil.exe file queryCaseSensitiveInfo C:\work\linux-src
هذه وسيلة فعّالة عند التعامل مع شجرة مصدر من أصل Linux عبر WSL (وجود Makefile وmakefile معاً مثلاً)، لكن للأمر أثر جانبيّ تحذّر منه الوثائق الرسميّة نفسها. قد تصبح تطبيقات Windows التي تفترض أنّ نظام الملفّات لا يميّز حالة الأحرف غير قادرة على الوصول إلى الملفّات في مجلّد فُعِّل فيه التمييز. كذلك، لا يمكن تغيير العلامة إلّا إن كان المجلّد الهدف فارغاً، وترث المجلّدات الفرعيّة المُنشَأة حديثاً إعداد المجلّد الأمّ. وتاريخيّاً، سُجِّل رسميّاً أنّه إن وُجد ملفّان باسمين لا يختلفان إلّا بحالة الأحرف، يظهران معاً في Explorer، لكن أيّاً منهما اختَرتَ يفتح الملفّ نفسه فقط.9
من ناحية تصميم تطبيقات الأعمال، الحلّ العمليّ هو اعتبار «الاختلاف في حالة الأحرف اسماً واحداً على Windows» هو الوضع الافتراضيّ، مع التحقّق من تضارب حالة الأحرف في أسماء الملفّات التي ستُنقَل إلى Linux. توجد مطبّات أيضاً في ترميز الأحرف قبل مسألة اسم الملفّ في تكامل Linux، فراجع أيضاً «مدخل إلى ترميز الأحرف في Windows - المحارف المشوَّهة الناتجة عن تكامل Linux».
6. العمل الفعليّ في تطبيقات الأعمال ── دمج المسارات، التعقيم، جدول القرار
6.1. استخدم Path.Combine مع معرفة مواصفاته
استخدام + لدمج سلاسل المسار مرفوض بداهةً، لكن حتّى Path.Combine له مواصفات ينبغي معرفتها. إن مُرِّر إلى أيّ من الوسائط التالية للوسيط الأوّل مسار مُجذَّر (rooted)، تُتجاهَل جميع الوسائط السابقة له.10
var baseDir = @"C:\App\Data";
// إن كان إدخال المستخدم مُجذَّراً، يُتجاهَل baseDir بصمت
Path.Combine(baseDir, @"C:\Windows\secret.txt"); // → "C:\Windows\secret.txt"
Path.Combine(baseDir, @"\evil.txt"); // → "\evil.txt" (جذر محرّك الأقراص الحاليّ)
تمرير سلسلة قادمة من إدخال المستخدم أو ملفّ إعداد مباشرةً إلى الوسيط الثاني يتحوّل إلى ثغرة كتابة خارج مجلّد الحفظ المقصود. تحذّر الوثائق الرسميّة نفسها من أنّ هذا السلوك قد يؤدّي إلى وصول غير مقصود إلى ملفّات حسّاسة، وتذكر كبديل Path.Join / Path.TryJoin (غير متاحتين في .NET Framework).1014 أيّاً كان ما تستخدمه، فإنّ التحقّق في النهاية من أنّ نتيجة التطبيع عبر Path.GetFullPath تقع تحت مجلّد الأساس هو القاعدة المتّبعة.
// طبِّع جانب الأساس أيضاً، ثمّ حوِّل إلى مسار نسبيّ للحكم.
// أكثر مقاومة لتفاوتات مطابقة السلسلة من البداية، كوجود فاصل ختاميّ
// من عدمه أو كون الأساس جذر محرّك أقراص
var baseFull = Path.GetFullPath(baseDir);
var fullPath = Path.GetFullPath(Path.Combine(baseFull, userInput));
var relative = Path.GetRelativePath(baseFull, fullPath);
if (relative == ".." ||
relative.StartsWith(".." + Path.DirectorySeparatorChar) ||
Path.IsPathRooted(relative)) // عند الخروج إلى محرّك أقراص آخر أو UNC، يُعاد مسار مطلق
{
throw new InvalidOperationException("وجهة الحفظ تشير إلى خارج المجلّد المتوقَّع.");
}
يقارن Path.GetRelativePath المسارات وفق منهج نظام التشغيل الافتراضيّ. أي أنّه في Windows حكم لا يميّز حالة الأحرف، وهو ما يتّسق مع «الإعداد الافتراضيّ في Windows هو عدم تمييز حالة الأحرف» الموضَّح في الفصل التالي. وبالمقابل، في المواضع التي فُعِّل فيها تمييز حالة الأحرف على مستوى المجلّد (راجع الفصل التالي)، قد يصبح Data وdata مجلّدين مختلفين، فقد يخطئ الحكم المتجاهل لحالة الأحرف في اعتبار «مجلّد آخر يختلف فقط بحالة الأحرف» جزءاً من الأساس. إن كنتَ تتعامل مع احتماليّة وجود مثل هذه البِنية، فالأسلم اتّباع سياسة عدم قبول موضع فُعِّل فيه التمييز كمجلّد أساس.
نقطة أخرى، تذكَّر أنّ هذا الحكم ليس إلّا حكماً على السلسلة النصّيّة المُطبَّعة. إن وُجدت وصلة تقاطع (junction) أو رابط رمزيّ (symbolic link) داخل مجلّد الأساس، فقد يشير المسار نصّيّاً إلى داخل الأساس بينما الكيان الفعليّ خارجه. وبما أنّ الرابط قد يتسلّل ليس فقط إلى الملفّ الطرفيّ بل أيضاً إلى مجلّد في منتصف المسار (بصيغة الأساس\رابط\ملفّ.txt)، فإنّ فحص الطرف فقط عبر File.ResolveLinkTarget لا يكشف ذلك. أوّل شيء هو تجنّب البِنية التي يمكن فيها لمستخدم غير موثوق إنشاء روابط أو تقاطعات داخل الأساس أصلاً. وإن كان لا بدّ من الالتزام الصارم فوق ذلك، فإمّا الحصول على المسار النهائيّ المؤكَّد من مقبض الملفّ المفتوح فعليّاً (عبر GetFinalPathNameByHandle في Win32) والتحقّق من وقوعه تحت الأساس، أو فحص كلّ عنصر مكوِّن من مكوّنات المسار للتأكّد من أنّه ليس رابطاً.
6.2. تعقيم اسم الملفّ القادم من إدخال المستخدم
في الميزات التي تُبنى فيها أسماء الملفّات من إدخال المستخدم كـ«اسم الجهة + التاريخ.csv»، اجمع التعقيم في موضع واحد. نقطة البداية هي Path.GetInvalidFileNameChars، لكن الوثائق الرسميّة تنصّ صراحةً على أنّ هذه المصفوفة لا تضمن مجموعة كاملة من الأحرف غير الصحيحة.11 لا يمكن لهذه الـ API كشف الأسماء المحجوزة للأجهزة ولا النقطة والمسافة الأخيرتين، لذا أضِف فحصاً ذاتيّاً.
private static readonly HashSet<string> ReservedNames =
new(StringComparer.OrdinalIgnoreCase)
{
"CON", "PRN", "AUX", "NUL",
"COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9",
"LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9",
"COM¹","COM²","COM³", // الأرقام العلويّة COM¹ إلى COM³ أيضاً أسماء محجوزة
"LPT¹","LPT²","LPT³", // وكذلك LPT¹ إلى LPT³
};
public static string SanitizeFileName(string input)
{
var invalid = Path.GetInvalidFileNameChars();
var name = new string(input.Select(c => invalid.Contains(c) ? '_' : c).ToArray());
name = name.TrimEnd(' ', '.'); // المسافة والنقطة الأخيرتان تُحذَفان بصمت، فأزِلهما
// اجعله ضمن حدّ طول عنصر اسم الملفّ الواحد (عادةً 255 حرفاً) أيضاً.
// اقطعه بتحفّظ مع ترك هامش لتسلسل المجلّدات أو لاحقة يضيفها التطبيق لاحقاً
const int MaxNameLength = 120;
if (name.Length > MaxNameLength)
{
var ext = Path.GetExtension(name);
if (ext.Length > 20)
{
ext = ""; // "الامتداد" الطويل بشكل غير طبيعيّ لا يُبقى عليه كامتداد
// (لمنع استثناء ناتج عن تحديد نطاق سالب)
}
name = name[..(MaxNameLength - ext.Length)].TrimEnd(' ', '.') + ext;
}
// احكم على الفراغ / الاسم المحجوز دائماً على "الشكل النهائيّ".
// لالتقاط حالات قد يتحوّل فيها الاسم بعد القطع أو TrimEnd إلى فراغ أو
// اسم محجوز (كـ NUL)
var stem = name.Split('.')[0]; // للتعامل مع NUL.txt: احكم بالاسم المحجوز على الجزء قبل الامتداد
if (name.Length == 0 || ReservedNames.Contains(stem))
{
name = "_" + name; // إضافة حرف واحد لا تزال ضمن حدّ 255 بأمان
}
return name;
}
نظراً لتكرار مصادفة هذه المشكلة في أسماء ملفّات إخراج CSV، راجع أيضاً «CSV ليس ‹مجرّد نصّ› ── العمل الفعليّ مع CSV في تطبيقات C# للأعمال».
6.3. مطبّ المسار النسبيّ والمجلّد الحاليّ
يوجد فخّان في المسار النسبيّ. أوّلاً، بما أنّ المجلّد الحاليّ إعداد على مستوى العمليّة، يمكن تغييره من أيّ مؤشّر ترابط وفي أيّ وقت. تكتب الوثائق الرسميّة صراحةً أنّ «المسار النسبيّ خطير في التطبيقات متعدّدة مؤشّرات الترابط»، وابتداءً من .NET Core 2.1 يمكن استخدام Path.GetFullPath(string, string) الذي يحدِّد مساراً أساسيّاً صراحةً.7 ثانياً، صيغة مثل C:tmp.txt بلا شرطة مائلة عكسيّة مباشرةً بعد حرف محرّك الأقراص هي مسار نسبيّ من المجلّد الحاليّ في محرّك C، وليست مساراً مطلقاً. هذا «المسار النسبيّ بالنسبة لمحرّك الأقراص» مُسمَّى رسميّاً كمصدر شائع لأخطاء البرامج والسكربتات.7
اجعل من عادتك تحويل أيّ مسار يُستلَم من ملفّ إعداد أو إدخال مستخدم إلى مسار مطلق عبر Path.GetFullPath فور استلامه، قبل تسجيله في السجلّ أو التحقّق منه.
6.4. جدول القرار ── هل تدعم المسار الطويل أم ترفضه عند المدخل
| الحالة | التوصية | السبب |
|---|---|---|
| تطبيق أعمال عامّ يختار فيه المستخدم وجهة الحفظ بحرّيّة | التحقّق عند المدخل ورفضه (فحص طول المسار الكامل واسم الملفّ قبل الحفظ وإصدار خطأ واضح) | يبقى حادث «تطبيقي يدعم لكن Explorer أو أداة التكامل لا تستطيع فتحه» قائماً1 |
| طرف «يقرأ» تسلسلاً هرميّاً عميقاً أنشأه طرف آخر، كالنسخ الاحتياطيّ والمزامنة واستخراج الأرشيف | دعم المسار الطويل (سلسلة .NET Core + بيان عند الحاجة، وفي Framework إعداد 4.6.2+) | لا يمكن التحكّم في المدخل، وتوقّف العمل إن تعذّرت القراءة54 |
| تطبيقك «يُنشئ» تسلسلاً هرميّاً عميقاً | إعادة النظر في التصميم من حيث المبدأ لعدم الإنشاء أصلاً (تسطيح التسلسل الهرميّ، اعتماد أسماء تجزئة (hash) وما شابه) | احتماليّة عدم دعم مستخدم المسار الذي أُنشئ (إنسان أو تطبيق آخر) مرتفعة1 |
| تبادل ملفّات مع Linux/WSL | الفحص قبل النقل للأسماء المحجوزة وتضارب حالة الأحرف والحرف الأخير | لأنّ ملفّات لا يمكن الوصول إليها من جانب Windows قد تنشأ69 |
| توليد اسم ملفّ من إدخال المستخدم | جمع التعقيم في دالّة مشتركة عبر GetInvalidFileNameChars مع فحص الأسماء المحجوزة والحرف الأخير |
لأنّ مصفوفة الـ API وحدها غير كافية11 |
7. استكشاف الأخطاء ── «يظهر في Explorer لكن لا يُفتَح»
خطوات التمييز بين الاحتمالات عند استفسار من نوع «الملفّ ظاهر في Explorer، لكن عند فتحه في التطبيق يظهر ‹الملفّ غير موجود›».
| نقطة التحقّق | الوسيلة | إن انطبقت |
|---|---|---|
| هل المسار الكامل قريب من 260 حرفاً | في PowerShell: (Get-ChildItem -Recurse).FullName \| Where-Object { $_.Length -ge 250 } |
اختصر أسماء المجلّدات العلويّة أو انظر في دعم المسار الطويل (الفصل 3) |
| هل اسم الملفّ اسم محجوز (aux، con، com1، إلخ) | تحقّق بصريّ من الاسم. يشمل ذلك ما له امتداد أيضاً6 | إعادة التسمية (وإن كان المصدر Linux مثلاً، حوِّل الاسم عند النقل) |
| هل توجد مسافة أو نقطة في آخر الاسم | تحقّق عبر cmd /c dir /x أو عرض بعلامات اقتباس |
الحذف أو إعادة التسمية عبر مسار ببادئة \\?\7 |
| هل يوجد ملفّان بالاسم نفسه يختلفان فقط بحالة الأحرف | يحدث كثيراً في مجلّدات من أصل WSL/Git9 | إعادة تسمية أحدهما أو إعادة النظر في استخدام المجلّد الهدف |
| هل تُستخدَم مسارات نسبيّة أو مسارات نسبيّة لمحرّك الأقراص | سجِّل في السجلّ المسار المطلق الذي حاولتَ فتحه فعليّاً | التحويل إلى مطلق عبر Path.GetFullPath قبل الاستخدام7 |
الخطوة الأولى المُوصى بها في التحقيق هي تسجيل «المسار الذي حاولتَ فتحه بالضبط» في سجلّ أخطاء التطبيق كمسار مطلق وبعلامات اقتباس. فرسالة استثناء «الملفّ غير موجود» وحدها لا تُميِّز لاحقاً ما إذا كان المسار قد اقتُطع، أو تغيّر الاسم بالتطبيع، أو كان يشير أصلاً إلى مجلّد مختلف تماماً. تسجيله بين علامتَي اقتباس يجعل مشكلات يصعب ملاحظتها بصريّاً، كالمسافة الأخيرة، واضحة من النظرة الأولى.
يُذكَر أنّ فشل تحميل DLL أيضاً من الأخطاء المتكرّرة من فئة «الملفّ غير موجود»، لكنّه في الغالب مشكلة ترتيب البحث أكثر منه طول المسار، وقد نظّمناها في «آليّة تحليل أسماء DLL في Windows - ترتيب البحث وSxS».
8. الخلاصة
- MAX_PATH=260 قيد Win32 API يشمل «
D:\+ 256 حرفاً كحدّ أقصى + NUL ختاميّ»، وNTFS نفسها تستطيع التعامل مع مسار ممتدّ يبلغ نحو 32,767 حرفاً. للمجلّدات أيضاً قيد إضافيّ هو MAX_PATH ناقص 12. - تجاوز الـ 260 حرفاً يحتاج إمّا بادئة
\\?\(النسخة اليونيكودية من الـ API فقط، ولا مسارات نسبيّة)، أو تفعيل المسار الطويل ابتداءً من Windows 10 1607 (كلا منLongPathsEnabledفي السجلّ وبيانlongPathAware). - .NET (Core)/5+ تتعامل مع المسارات الطويلة ضمنيّاً، و.NET Framework باستهداف 4.6.2 فما بعده يُزال فيها فحص زمن التشغيل. لكن نظراً لبقاء تطبيقات غير داعمة، بما فيها Explorer، احكم بشكل منفصل بين «هل يمكن الإنشاء» و«هل يستطيع المستخدم التعامل معه».
- لا يُسمَح في اسم الملفّ بالأحرف المحجوزة (
< > : " / \ | ? *) والمحارف الضابطة، ولا الأسماء المحجوزة للأجهزة كـ CON وNUL وCOM1 حتّى بامتداد، وتختفي المسافة والنقطة في آخر الاسم بصمت بالتطبيع. - الإعداد الافتراضيّ لحالة الأحرف هو «تُحفَظ لكن لا تُميَّز». التمييز على مستوى المجلّد عبر
fsutil file setCaseSensitiveInfoفعّال في تكامل WSL، لكنّه يأتي مقابل مخاطر خلل في تطبيقات Windows. - من ناحية التنفيذ، الأسلوب المتّبع هو التحقّق من مجلّد الأساس مع مراعاة مواصفات الوسيط المُجذَّر في
Path.Combine، وتوحيد التعقيم عبرGetInvalidFileNameCharsمع فحص الأسماء المحجوزة والحرف الأخير، واستبعاد المسارات النسبيّة (التحويل إلى مطلق عبرPath.GetFullPath).
مقالات ذات صلة
- CSV ليس ‹مجرّد نصّ› ── العمل الفعليّ مع CSV في تطبيقات C# للأعمال (ترميز الأحرف، توافق Excel، الحماية من الحقن)
- مدخل إلى ترميز الأحرف في Windows - المحارف المشوَّهة الناتجة عن تكامل Linux
- ترميز الأحرف وأحرف نهاية السطر في Windows - أساسيّات المحارف المشوَّهة وCRLF/LF
- آليّة تحليل أسماء DLL في Windows - ترتيب البحث وSxS
مجالات الاستشارة ذات الصلة
تتعامل شركة Komura Soft LLC مع تحقيق الأعطال الناتجة عن إدخال/إخراج الملفّات، كتعذّر فتح ملفّات في بيئة أو جهاز معيّن فقط، ومراجعة تصميم دعم المسار الطويل والتحقّق من صحّة أسماء الملفّات في تطبيقات الأعمال القائمة، والاستشارة في تصميم تكامل الملفّات في البيئات المختلطة بين Windows وLinux.
روابط مرجعيّة
-
Microsoft Learn, Maximum Path Length Limitation. حول تعريف MAX_PATH=260 وتفصيله الداخليّ («حرف محرّك الأقراص + نقطتين رأسيّتين + شرطة مائلة عكسيّة + 256 حرفاً + NUL ختاميّ»)، والمسار الممتدّ الذي يبلغ نحو 32,767 حرفاً عبر النسخة اليونيكودية من الـ API وبادئة
\\?\، وطول العنصر المكوِّن (عموماً 255 حرفاً)، وكون المسار النسبيّ دائماً مقيَّداً بـ MAX_PATH، وكون إنشاء المجلّدات مقيَّداً بـ MAX_PATH ناقص 12، واختلاف متطلّبات الصدفة ونظام الملفّات وعدم قدرة واجهة الصدفة أحياناً على تفسير مسار أنشأه Win32. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 -
Microsoft Learn, NTFS overview. حول دعم NTFS لأسماء الملفّات الطويلة والمسارات الممتدّة التي تبلغ نحو 32,767 حرفاً، والتوافق العكسيّ عبر أسماء الاستعارة (alias) بصيغة 8.3. ↩ ↩2
-
Microsoft Learn, Maximum Path Length Limitation ── Enable long paths in Windows 10, version 1607, and later. حول ضرورة كلٍّ من قيمة السجلّ LongPathsEnabled=1 وعنصر longPathAware في بيان التطبيق معاً ابتداءً من Windows 10 1607، والإعداد عبر سياسة المجموعة، وتخزين قيمة السجلّ مؤقّتاً على مستوى العمليّة، وقائمة دوالّ Win32 التي يُزال عنها القيد. ↩ ↩2 ↩3
-
Microsoft Learn, File path formats on Windows systems ── Skip normalization. حول معالجة .NET Core و.NET 5 فما بعده للمسارات الطويلة ضمنيّاً دون فحص MAX_PATH (فحص MAX_PATH مقصور على .NET Framework)، وكون
\\?\آليّة لتجاوز التطبيع. ↩ ↩2 ↩3 -
Microsoft Learn, Retargeting changes for migration to .NET Framework 4.6.x. حول دعم المسارات الطويلة (حتّى 32K حرف) وإزالة قيد الـ 260 حرفاً عند استهداف .NET Framework 4.6.2، وإمكانيّة اشتراك التطبيقات ذات الاستهداف القديم عبر Switch.System.IO.BlockLongPaths=false. ↩ ↩2 ↩3
-
Microsoft Learn, Naming Files, Paths, and Namespaces. حول الأحرف المحجوزة (
< > : " / \ | ? *) والمحارف الضابطة (0 إلى 31)، وأسماء الأجهزة المحجوزة (CON/PRN/AUX/NUL/COM1-9/LPT1-9 والأرقام العلويّة)، ومعادلة الاسم المُلحَق بامتداد كـ NUL.txt للاسم المحجوز، وعدم إنهاء الاسم بمسافة أو نقطة، ومشروعيّة النقطة في البداية، وعدم افتراض تمييز حالة الأحرف ودلالات NTFS بأسلوب POSIX، وسلوك بادئة\\?\ومتطلّب النسخة اليونيكودية من الـ API. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 -
Microsoft Learn, File path formats on Windows systems ── Path normalization. حول إزالة النقطة والمسافة الأخيرتين في تطبيع المسار، وعدم إمكانيّة الوصول إلى اسم مثل
hidden.إلّا عبر\\?\، وتفسير أسماء الأجهزة القديمة كـ CON والتغيير في Windows 11، وكون المسار النسبيّ لمحرّك الأقراص (C:tmp.txt) سبباً شائعاً للأخطاء البرمجيّة، وكون المجلّد الحاليّ إعداداً على مستوى العمليّة وخطورة المسار النسبيّ في التطبيقات متعدّدة مؤشّرات الترابط، وPath.GetFullPath(String, String). ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 -
Microsoft Learn, File path formats on Windows systems ── Case and the Windows file system. حول حفظ اسم المجلّد والملفّ لحالة الأحرف وقت الإنشاء، مع عدم تمييز حالة الأحرف عند مقارنة الأسماء. ↩ ↩2
-
Microsoft Learn, Adjust case sensitivity. حول تمييز حالة الأحرف على مستوى المجلّد ابتداءً من Windows 10 البناء 17107 (fsutil.exe file setCaseSensitiveInfo)، وضرورة صلاحيّات المسؤول ومجلّد فارغ للتغيير، ووراثة المجلّدات الفرعيّة الجديدة للإعداد، والتحذير من احتمال خلل تطبيقات Windows التي تفترض عدم تمييز حالة الأحرف، وأنّ ملفّين مختلفين فقط بحالة الأحرف كانا يظهران معاً في Explorer لكن لا يُفتَح إلّا أحدهما. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Path.Combine Method. حول تجاهل عناصر المسار السابقة وإعادة سلسلة تبدأ من العنصر المُجذَّر إذا احتوت وسائط غير الأولى على مسار مُجذَّر، واحتمال الوصول غير المقصود إلى ملفّات حسّاسة، وذكر Join/TryJoin (غير متاحتين في .NET Framework) كبديل. ↩ ↩2 ↩3
-
Microsoft Learn, Path.GetInvalidFileNameChars Method. حول إعادة مصفوفة الأحرف غير القابلة للاستخدام في اسم الملفّ، وعدم ضمان المصفوفة المُعادة لمجموعة كاملة من الأحرف غير الصحيحة، واختلافها باختلاف نظام الملفّات. ↩ ↩2 ↩3
-
Microsoft Learn, PathTooLongException Class. حول كونه استثناءً يُرمى عندما يتجاوز المسار الحدّ الأقصى المعرَّف في النظام، وأنّه ابتداءً من .NET Framework 4.6.2 يُرمى فقط في حالة «تجاوز 32,767 حرفاً» أو «إعادة نظام التشغيل خطأً». ↩ ↩2
-
Microsoft Learn, Long Path Support (NuGet CLI). حول التكوين الفعليّ (Windows 10 1607 فما بعده أو 1511 + .NET Framework 4.6.2، وسياسة مسارات Win32 الطويلة، وبيان longPathAware + تعطيل UseLegacyPathHandling) الذي تحتاجه الأدوات القائمة على .NET Framework لاستخدام المسار الطويل، وعدم دعم استعادة الحزم في Visual Studio أو msbuild للمسار الطويل. ↩ ↩2
-
Microsoft Learn, Path.Join Method. حول أنّ Join لا يُسقِط المسار اللاحق المُجذَّر بل يدمجه، وأمثلة فعليّة على فرق السلوك مع Combine. ↩
مقالات ذات صلة
أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.
استدعاء Win32 API بأمان من C# ── دليل P/Invoke العمليّ (DllImport / LibraryImport / CsWin32)
نُنظِّم النقاط العمليّة لاستدعاء Win32 API من C# عبر P/Invoke. الفرق بين DllImport وLibraryImport، والتوليد التلقائيّ عبر CsWin32، ومطبّا...
إدارة إصدارات مخطّط قاعدة بيانات تطبيقات الأعمال ── ممارسات الترحيل (migration) لمنع «اختلاف قاعدة البيانات من عميل لآخر»
دليل عمليّ لإدارة إصدارات مخطّط قاعدة بيانات تطبيقات الأعمال الموزَّعة على عملاء متعدّدين. نشرح PRAGMA user_version وتنفيذ الترحيل الأمام...
CI/CD عمليّ لتطبيقات WinForms / WPF ── أتمتة من البناء إلى التوقيع والتوزيع عبر GitHub Actions
دليل عمليّ لبناء CI/CD لتطبيقات WinForms / WPF عبر GitHub Actions. يشمل YAML الأدنى للبناء + الاختبار على windows-latest، وترقيم الإصدار ...
عندما يُعامَل تطبيق Windows الذي طوّرته شركتك بوصفه فيروساً ── التعامل مع الكشف الخاطئ في Microsoft Defender والتعايش مع أثره على الأداء
نرتّب الإجراء الرسميّ عند كشف Microsoft Defender تطبيق Windows الذي طوّرته شركتك خطأً. نشرح آليّة برامج مكافحة الفيروسات الحديثة، والإبلا...
السكون والإسبات وModern Standby والتطبيقات طويلة التشغيل ── منع «التوقّف في منتصف الليل» بالتصميم
نرتّب أسباب وصول تطبيقات Windows طويلة التشغيل إلى حالة «توقّفت عندما نظرت صباحاً»، انطلاقاً من الفرق بين سكون S3 والإسبات وModern Standb...
أين يتصل هذا الموضوع
ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.
تطوير تطبيقات ويندوز
ندعم تطوير برامج ويندوز للأعمال، وتكامل الأجهزة، وأدوات التواصل.
الأسئلة الشائعة
أسئلة شائعة حول موضوع هذه المقالة.
- كم عدد الأحرف التي يمكن استخدامها في مسار Windows؟
- الإعداد الافتراضيّ لواجهات Win32 API هو MAX_PATH=260 حرفاً، وهو طول يشمل «حرف محرّك الأقراص + نقطتين رأسيّتين + شرطة مائلة عكسيّة + سلسلة مسار من 256 حرفاً + محرف NUL الختاميّ». أنظمة الملفّات نفسها مثل NTFS تستطيع التعامل مع مسارات أطول من ذلك بكثير، وإن مرّرتَ إلى النسخة اليونيكودية من الـ API مساراً ببادئة \\?\ يمكنك تحديد ما يصل إلى نحو 32,767 حرفاً إجمالاً. لكن عموماً يبلغ الحدّ الأقصى لاسم مجلّد أو ملفّ واحد (عنصر واحد) 255 حرفاً، وتبقى المسارات النسبيّة دائماً مقيَّدة بحدّ MAX_PATH.
- كيف يمكن إلغاء حدّ MAX_PATH البالغ 260 حرفاً؟
- ابتداءً من Windows 10 الإصدار 1607، بضبط قيمة السجلّ LongPathsEnabled=1 (أو سياسة المجموعة «تفعيل مسارات Win32 الطويلة») مع عنصر longPathAware في بيان التطبيق (application manifest) معاً، يُزال حدّ 260 حرفاً في كثير من دوالّ Win32 الخاصّة بالملفّات. لا يُفعَّل الأمر بأحدهما فقط. زمن تشغيل .NET (Core) / .NET 5 وما بعده لا يُجري فحص MAX_PATH ويتعامل مع المسارات الطويلة ضمنيّاً، أمّا .NET Framework فباستهداف 4.6.2 فما بعده يُزال فحص الـ 260 حرفاً على مستوى زمن التشغيل. مع ذلك، تبقى تطبيقات غير داعمة للمسارات الطويلة قائمة، بما فيها Explorer نفسه، فيلزم القرار مع مراعاة مَن سيتعامل مع المسار الطويل الذي أنشأتَه.
- لماذا لا يمكن إنشاء ملفّ باسم CON أو NUL؟
- CON وPRN وAUX وNUL وCOM1 إلى COM9 وLPT1 إلى LPT9 وغيرها أسماء أجهزة محجوزة موروثة من عصر MS-DOS، وWindows تفسّر هذه الأسماء كأجهزة لا كملفّات. حتّى بإضافة امتداد كما في NUL.txt يظلّ الأمر يُعامَل معاملة NUL نفسها، فلا يمكن تجاوز المشكلة بهذه الطريقة. تغيّر جزئيّاً سلوك تفسير المسار في Windows 11، لكن بما أنّ أنظمة تشغيل قديمة وتطبيقات كثيرة لا تزال على التفسير التقليديّ، يبقى تجنّب هذه الأسماء في بيانات العمل الآمن الأسلم.
- هل تُميَّز حالة الأحرف (كبيرة/صغيرة) في أسماء الملفّات على Windows؟
- الإعداد الافتراضيّ هو «الحفاظ على الحالة، دون تمييزها» (case-preserving, case-insensitive). إن أنشأتَ ملفّاً باسم Readme.txt، يُحفَظ شكل الأحرف ذلك في العرض، لكنّ محاولة فتح README.TXT تصل إلى الملفّ نفسه أيضاً. تدعم NTFS أيضاً تمييز حالة الأحرف بأسلوب POSIX، وابتداءً من Windows 10 الإصدار 17107 يمكن تفعيل التمييز على مستوى المجلّد عبر fsutil.exe file setCaseSensitiveInfo، لكن نظراً لأثر جانبيّ يتمثّل في احتمال خلل تطبيقات Windows التي تفترض عدم تمييز الحالة، ينبغي حصر ذلك في المواضع الضروريّة فعلاً كالتكامل مع WSL.
الملف الشخصي للمؤلف
صفحة الملف الشخصي لمؤلف المقالة.
غو كومورا
مؤسّس شركة كومورا سوفت ذ.م.م.
يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.
روابط عامة