ডিরেক্টরি স্ট্রাকচার
এই পাঠে যা শিখবেন
- ডিরেক্টরি কী এবং কেন এটি ফাইল সিস্টেমের সংগঠনের কেন্দ্রীয় ডেটা স্ট্রাকচার
- চার ধরনের ডিরেক্টরি স্ট্রাকচার এবং প্রতিটি কোন সমস্যা সমাধান করে (বা করে না)
- পাথ রেজোলিউশন ঠিক কীভাবে ধাপে ধাপে একটি ট্রি হেঁটে ফাইল খুঁজে বের করে
- Python-এ নেস্টেড dict দিয়ে একটি বাস্তব ট্রি ডিরেক্টরি ও
resolve_path()ফাংশন বাস্তবায়ন, সফল ও ব্যর্থ উভয় ক্ষেত্রেই
১ · ডিরেক্টরি কী
ডিরেক্টরি (Directory)Directoryনিজেই এক ধরনের বিশেষ ফাইল বা OS ডেটা স্ট্রাকচার, যা ফাইলনামকে তাদের মেটাডেটা/লোকেশনের সাথে ম্যাপ করে — সামগ্রিক ফাইল সিস্টেমকে সংগঠিত করে। নিজেই এক ধরনের বিশেষ ফাইল (বা OS-এর একটি ডেটা স্ট্রাকচার) — যা ফাইলনামকে তাদের L37-এ দেখা মেটাডেটা/লোকেশনের সাথে ম্যাপ করে। যদি L37-এর একটি একক ফাইলের অ্যাট্রিবিউট টেবিল কল্পনা করেন, ডিরেক্টরি হলো সেই টেবিলগুলোকে গোছানোভাবে সংগঠিত করার কাঠামো — যাতে হাজারো ফাইলের মধ্যে থেকে সঠিকটি দ্রুত খুঁজে পাওয়া যায়।
২ · চার ধরনের ডিরেক্টরি স্ট্রাকচার
সব ফাইল একটিমাত্র ফ্ল্যাট নেমস্পেসে — সহজ, কিন্তু প্রতিটি ফাইলের নাম গ্লোবালি ইউনিক হতে হয়, কয়েকটির বেশি ফাইলেই নাম-সংঘর্ষ (collision) শুরু হয়ে যায়।
প্রতি ইউজারের নিজস্ব ডিরেক্টরি — ইউজারদের মধ্যে নাম-সংঘর্ষ সমাধান করে, কিন্তু একজন ইউজার নিজের ফাইলকে সাব-গ্রুপে ভাগ করতে পারেন না।
ডিরেক্টরির ভেতরে ফাইল ও সাব-ডিরেক্টরি উভয়ই থাকতে পারে, অসীম গভীরতার একটি ট্রি তৈরি করে — একটি সম্পূর্ণ পাথ ফাইলকে ইউনিকভাবে চিহ্নিত করে।
একটি ফাইল/ডিরেক্টরি একাধিক জায়গায় "শেয়ার" হতে পারে লিংকের মাধ্যমে (Unix হার্ড/সফট লিংক) — কিন্তু প্রকৃত সাইকেল (চক্র) এড়াতে সতর্কতার সাথে ডিজাইন করতে হয়, নইলে রিকার্সিভ ট্রাভার্সাল অসীম লুপে আটকে যেতে পারে।
৩ · পাথ রেজোলিউশন — ট্রি হেঁটে ফাইল খোঁজা
একটি সম্পূর্ণ পাথ (Path)Pathরুট থেকে শুরু করে ধারাবাহিক ডিরেক্টরি নামের একটি ক্রম, যা একটি নির্দিষ্ট ফাইল/ডিরেক্টরিকে ইউনিকভাবে চিহ্নিত করে।
(যেমন /home/user/documents/file.txt) রুট ডিরেক্টরি থেকে শুরু করে একের পর এক সাব-ডিরেক্টরির নাম দিয়ে
ফাইলটি পর্যন্ত পৌঁছানোর একটি নির্দেশনা। পাথ রেজোলিউশন মানে এই পাথটিকে "/" দিয়ে ভেঙে প্রতিটি অংশ
ধরে ধরে ট্রি-এর ভেতরে নিচের দিকে নামা — একটি অংশ না পাওয়া গেলে, বা মাঝপথে একটি ফাইলকে ডিরেক্টরি হিসেবে ব্যবহারের
চেষ্টা করা হলে, রেজোলিউশন ব্যর্থ হয়ে যায়।
# L38 -- ট্রি-স্ট্রাকচার্ড ডিরেক্টরি সিমুলেশন (নেস্টেড dict, toy in-memory)
FILE_MARKER = "__FILE__"
root = {
"home": {
"user": {
"documents": {
"report.txt": FILE_MARKER,
"notes.txt": FILE_MARKER,
},
"photo.png": FILE_MARKER,
}
}
}
def resolve_path(root_dir, path_string):
parts = [p for p in path_string.strip("/").split("/") if p]
current = root_dir
walked = []
for i, part in enumerate(parts):
walked.append(part)
if not isinstance(current, dict) or part not in current:
return None, f"পাথ রিজলভ ব্যর্থ -> '/{'/'.join(walked)}' পাওয়া যায়নি"
current = current[part]
is_last = (i == len(parts) - 1)
if current == FILE_MARKER and not is_last:
return None, f"পাথ রিজলভ ব্যর্থ -> '/{'/'.join(walked)}' একটি ফাইল, ডিরেক্টরি নয় (আরও গভীরে যাওয়া যায় না)"
return current, f"পাথ রিজলভ সফল -> '{path_string}'"
tests = [
"/home/user/documents/report.txt",
"/home/user/photo.png",
"/home/user/documents",
"/home/user/documents/missing.txt",
"/home/nobody/file.txt",
"/home/user/photo.png/extra",
]
for t in tests:
result, message = resolve_path(root, t)
print(message, "->", ("FILE" if result == FILE_MARKER else ("DIR" if isinstance(result, dict) else "N/A")))
/home/nobody/file.txt ব্যর্থ হয় কারণ "nobody" নামের
কোনো সাব-ডিরেক্টরিই home-এর ভেতরে নেই। আর /home/user/photo.png/extra ব্যর্থ হয় ভিন্ন
কারণে — photo.png নিজেই একটি ফাইল (FILE_MARKER), তাই তার "ভেতরে" আরও কিছু খোঁজার
চেষ্টা সঠিকভাবেই প্রত্যাখ্যাত হয়।
ডিরেক্টরি স্ট্রাকচার ঠিক করে দেয় ফাইল সিস্টেমের সামগ্রিক "নেমস্পেস" কেমন দেখতে হবে। ট্রি-স্ট্রাকচার্ড ডিরেক্টরি জিতেছে কারণ এটি সিঙ্গেল-লেভেলের নাম-সংঘর্ষ সমস্যা এবং টু-লেভেলের "সাব-গ্রুপিং করতে না পারা" সমস্যা — দুটোই একসাথে সমাধান করে, এবং পাথ রেজোলিউশনের মাধ্যমে যেকোনো গভীরতার ফাইলকে একটি একক স্ট্রিং দিয়ে ইউনিকভাবে ঠিকানা দেওয়া যায়।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ টু-লেভেল ডিরেক্টরি ইউজারদের মধ্যে নাম-সংঘর্ষ সমাধান করে, তাহলে সরাসরি ট্রি-স্ট্রাকচার্ডে না গিয়ে টু-লেভেলেই কেন থামা যেত না?
টু-লেভেল শুধু "কোন ইউজারের ফাইল" এই একস্তরের সমস্যা সমাধান করে — একজন ইউজারের নিজের শত শত ফাইল একটি ফ্ল্যাট তালিকায় থেকেই যায়, তাকে প্রজেক্ট/ফোল্ডার অনুযায়ী ভাগ করার কোনো উপায় থাকে না। ট্রি-স্ট্রাকচার্ড এই সীমাবদ্ধতা সরিয়ে দেয় — একজন ইউজার নিজেই যতগুলো ইচ্ছা সাব-ডিরেক্টরি তৈরি করে নিজের ফাইল সংগঠিত করতে পারেন, যেকোনো গভীরতায়।
প্র ০২ অ্যাসাইক্লিক-গ্রাফ ডিরেক্টরিতে "সাইকেল" (চক্র) তৈরি হলে ঠিক কোন বাস্তব সমস্যা হয়?
অনেক ফাইল-সিস্টেম অপারেশন (যেমন একটি ডিরেক্টরির মোট ডিস্ক ব্যবহার হিসাব করা, বা রিকার্সিভভাবে সব ফাইল লিস্ট করা) ধরে নেয় ট্রাভার্সাল একদিন শেষ হবে — কারণ এটি একটি ট্রি। যদি লিংকের কারণে একটি ডিরেক্টরি নিজেরই কোনো পূর্বপুরুষের (ancestor) দিকে ফিরে যায় (সাইকেল), তাহলে এই রিকার্সিভ ট্রাভার্সাল কখনও শেষ না হয়ে অসীম লুপে আটকে যেতে পারে — তাই বাস্তব সিস্টেমগুলো সাইকেল তৈরি প্রতিরোধ করে বা ট্রাভার্সালে "দেখা হয়েছে" ট্র্যাক রাখে।
প্র ০৩
কোড সেলে /home/user/photo.png/extra কেন ব্যর্থ হলো, যদিও "photo.png" পর্যন্ত পাথের প্রতিটি অংশ আসলে বিদ্যমান?
কারণ resolve_path প্রতিটি ধাপে চেক করে বর্তমান নোডটি আসলেই একটি ডিরেক্টরি (dict) কি না, যদি আরও
গভীরে যাওয়ার দরকার থাকে। "photo.png"-তে পৌঁছানোর পর সেটি হলো FILE_MARKER — একটি
dict নয়। যেহেতু পাথে আরও একটি অংশ ("extra") বাকি ছিল, isinstance(current, dict)
চেক ব্যর্থ হয় এবং ফাংশনটি সঠিকভাবে জানায় যে একটি ফাইলকে ডিরেক্টরি হিসেবে ট্রাভার্স করার চেষ্টা করা হচ্ছে।
অনুশীলন
-
চিন্তা করুন: আপনার নিজের কম্পিউটারে কোনো একটি ফাইলের সম্পূর্ণ পাথ লিখে ফেলুন (যেমন
C:\Users\...বা/home/...) — এটি কয়টি "ধাপ"-এ ভাঙা যায়, এবং প্রতিটি ধাপ কি সত্যিই একটি ডিরেক্টরি?সাধারণত পাথের শেষ অংশটি বাদে (যেটি ফাইল হতে পারে) প্রতিটি অংশই একটি ডিরেক্টরি — উপরের কোড সেলের
resolve_pathঠিক এই নিয়মই মেনে চলে (শেষ অংশ ছাড়া বাকি সব অংশেisinstance(current, dict)সত্য হতে হবে)। ধাপের সংখ্যা যত বেশি, পাথ তত "গভীর" — এবং প্রতিটি ধাপে একটি অতিরিক্ত ডিরেক্টরি-লুকআপ প্রয়োজন হয়, যা বাস্তব ফাইল সিস্টেমে সামান্য কিন্তু বাস্তব একটি পারফরম্যান্স খরচ। -
পরীক্ষা করুন: উপরের কোড সেলের
rootdict-এ একটি নতুন সাব-ডিরেক্টরি"downloads"যোগ করে তার ভেতরে একটি ফাইল রাখুন, তারপর সেই নতুন পাথ দিয়েresolve_pathকল করে দেখুন সঠিকভাবে খুঁজে পায় কি না।root["home"]["user"]["downloads"] = {"movie.mp4": FILE_MARKER}যোগ করেresolve_path(root, "/home/user/downloads/movie.mp4")কল করলে এটি সফল হবে এবংFILE_MARKERফেরত দেবে — কারণresolve_pathকোনো হার্ডকোডেড পাথ জানে না, শুধু রানটাইমেrootট্রি-এর গঠন অনুসরণ করে। এটি দেখায় ফাংশনটি সত্যিই সাধারণ (generic) — যেকোনো নতুন ফাইল/ডিরেক্টরি যোগ করলে সাথে সাথে সেটি রেজলভযোগ্য হয়ে যায়, কোড পরিবর্তন ছাড়াই।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পরবর্তী পাঠ — ফাইল অ্যালোকেশন মেথড L39 ডিরেক্টরি ফাইলের নাম-থেকে-লোকেশন ম্যাপ করে দিলেও, সেই "লোকেশন"-এ ডেটা আসলে কীভাবে বসে থাকে তা এই পাঠে।
- আগের পাঠ — ফাইল কনসেপ্ট ও অ্যাট্রিবিউট L37 ডিরেক্টরি আসলে কোন তথ্য (নাম, মেটাডেটা) সংগঠিত করছে তার ভিত্তি।
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৬টি পাঠ প্রসেস, মেমরি, ফাইল সিস্টেম, I/O ও ভার্চুয়ালাইজেশন — সব মডিউল এক জায়গায়।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks ও Operating Systems — সব এক জায়গায়।