পাইথনে ফাইল পরিচালনা

পাইথনে ফাইল পরিচালনা

এই প্রবন্ধটি পাইথনে ফাইল পরিচালনার বিষয়ে ব্যাখ্যা করে।

এই গাইডটি 'নিরাপত্তা', 'দক্ষতা' এবং 'পাঠযোগ্যতা' মাথায় রেখে, ধারণাগুলি ধাপে ধাপে বর্ণনা করে, মৌলিক বিষয় থেকে ব্যবহারিক কৌশল পর্যন্ত।

YouTube Video

পাইথনে ফাইল পরিচালনা

ফাইল পরিচালনা একটি অত্যাবশ্যক মৌলিক দক্ষতা, ছোট স্ক্রিপ্ট থেকে শুরু করে বৃহৎ আকারের অ্যাপ্লিকেশন পর্যন্ত।

ফাইল খোলা ও বন্ধ করা

প্রথমে, টেক্সট ফাইল পড়া ও লেখার উদাহরণগুলি দেখে নেওয়া যাক। with স্টেটমেন্ট (কনটেক্সট ম্যানেজার) ব্যবহার করলে ফাইলটি সঠিকভাবে বন্ধ হয় তা নিশ্চিত হয়।

নিম্নের কোড একটি টেক্সট ফাইল খোলে, তার কনটেন্ট পড়ে এবং লাইন বাই লাইন প্রসেস করে।

1# Open and read a text file safely using a context manager.
2with open("example.txt", "r", encoding="utf-8") as f:
3    # Read all lines lazily (as an iterator) and process each line.
4    for line in f:
5        print(line.rstrip())
  • encoding="utf-8" স্পষ্টভাবে নির্দিষ্ট করলে প্ল্যাটফর্ম-নির্ভর সমস্যা কমে যায়।
  • বড় ফাইলের ক্ষেত্রেও, for line in f ব্যবহার করা মেমোরি-দক্ষ।

লেখা (ওভাররাইট ও অ্যাপেন্ড)

ফাইলে লেখা সময় মোডের প্রতি লক্ষ্য রাখা জরুরি। w ওভাররাইটের জন্য এবং a অ্যাপেন্ডের জন্য। লেখার সময়ও with স্টেটমেন্ট ব্যবহার করুন।

নিম্নের কোড ওভাররাইট ও অ্যাপেন্ড করার মৌলিক উদাহরণ দেখায়।

1# Write (overwrite) to a file.
2with open("output.txt", "w", encoding="utf-8") as f:
3    f.write("First line\n")
4    f.write("Second line\n")
5
6# Append to the same file.
7with open("output.txt", "a", encoding="utf-8") as f:
8    f.write("Appended line\n")
  • এই কোডটি প্রথমে output.txt তে টেক্সট লেখে এবং পরে একই ফাইলে আরো টেক্সট অ্যাপেন্ড করে। "w" মোড ফাইলটি ওভাররাইট করে এবং "a" মোড বিদ্যমান কনটেন্টের শেষে নতুন লাইন অ্যাপেন্ড করে।
  • আপনার যদি ফ্লাশের প্রয়োজন পড়ে, তাহলে flush() কল করুন, তবে সাধারণত কনটেক্সট শেষ হলে কনটেন্ট স্বয়ংক্রিয়ভাবে ফ্লাশ হয়ে যায়।
  • যদি একাধিক প্রসেস বা থ্রেড একই সময়ে লেখার সম্ভাবনা থাকে, তাহলে এক্সক্লুসিভ কন্ট্রোল যেমন ফাইল লকিং বিবেচনা করা উচিত।

বাইনারি ডেটা পড়া ও লেখা

ছবি ও কমপ্রেসড ফাইলগুলো বাইনারি মোডে (rb বা wb) পরিচালনা করা হয়। টেক্সট মোডের তুলনায়, বাইনারি মোডে encoding উপেক্ষা করা হয়।

নিম্নের কোড একটি বাইনারি ফাইল পড়ে এবং আরেকটি ফাইলে বাইনারি মোডে কপি করে।

1# Read and write binary files.
2with open("image.png", "rb") as src:
3    data = src.read()
4
5with open("copy.png", "wb") as dst:
6    dst.write(data)
  • বড় বাইনারি ফাইল ব্যবস্থাপনার সময়, read() দিয়ে সব একসাথে পড়া এড়িয়ে চলুন; চাঙ্ক আকারে পড়া ও লেখা মেমোরি-দক্ষ।

বড় ফাইল চাঙ্কে চাঙ্কে ব্যবস্থাপনার উদাহরণ

যে বিশাল ফাইলগুলো মেমোরিতে ধরে না, সেগুলো নির্দিষ্ট সাইজের চাঙ্কে পড়া ও লেখা করুন। এটি I/O-নির্ভর হওয়ায়, বাফার সাইজ ঠিক করে নেওয়া কার্যকর।

নিম্নের কোড একটি ফাইল ৬৪ কেবল চাঙ্কে কপি করে। এটি দ্রুত কাজ করে এবং মেমোরি ব্যবহার কম রাখে।

1# Copy a large file in chunks to avoid using too much memory.
2CHUNK_SIZE = 64 * 1024  # 64 KB
3
4with open("large_source.bin", "rb") as src,      open("large_dest.bin", "wb") as dst:
5    while True:
6        chunk = src.read(CHUNK_SIZE)
7        if not chunk:
8            break
9        dst.write(chunk)
  • আপনি আপনার নেটওয়ার্ক বা ডিস্কের বৈশিষ্ট্য অনুযায়ী চাঙ্ক সাইজ ঠিক করে নিতে পারেন। SSD-তে সাধারণত একটু বড় চাঙ্ক সাইজ ভালো কাজ করে।

বাফারিং আর্গুমেন্ট ব্যবহার করার উদাহরণ

open() ফাংশনে buffering আর্গুমেন্ট নির্ধারণ করে, আপনি পাইথনের অভ্যন্তরীণভাবে ব্যবহৃত বাফার সাইজ নিয়ন্ত্রণ করতে পারেন। এর মাধ্যমে আপনি ইনপুট/আউটপুট দক্ষতা আরও উন্নত করতে পারেন।

 1# Explicitly set the internal buffer size to 128 KB for faster I/O.
 2CHUNK_SIZE = 64 * 1024
 3BUFFER_SIZE = 128 * 1024  # 128 KB internal buffer
 4
 5with open("large_source.bin", "rb", buffering=BUFFER_SIZE) as src,      open("large_dest.bin", "wb", buffering=BUFFER_SIZE) as dst:
 6    while True:
 7        chunk = src.read(CHUNK_SIZE)
 8        if not chunk:
 9            break
10        dst.write(chunk)
  • আপনি যদি buffering-এর মান 0 নির্ধারণ করেন, তবে বাফার ছাড়াই ইনপুট/আউটপুট সম্পন্ন হয়; ১ হলে লাইন বাফারিং সক্রিয় হয়, আর ২ বা তার বেশি হলে নির্দিষ্ট বাইট সাইজের বাফার ব্যবহৃত হয়।
  • সাধারণত ডিফল্ট মান যথেষ্ট, কারণ অপারেটিং সিস্টেম দক্ষতার সাথে ক্যাশিং পরিচালনা করে; তবে খুব বড় ফাইল বা বিশেষ ডিভাইসের ক্ষেত্রে এই প্যারামিটারটি সমন্বয় করা কার্যকর হতে পারে।

Pathlib ব্যবহার করে আধুনিক ফাইল পরিচালনা

স্ট্যান্ডার্ড pathlib মডিউল পাথ পরিচালনাকে আরও সহজবোধ্য করে তোলে। স্ট্রিং পাথের তুলনায় এটি পাঠযোগ্যতা ও নিরাপত্তা দুটোই বাড়ায়।

 1from pathlib import Path
 2
 3path = Path("data") / "notes.txt"
 4
 5# Ensure parent directory exists.
 6path.parent.mkdir(parents=True, exist_ok=True)
 7
 8# Write and read using pathlib.
 9path.write_text("Example content\n", encoding="utf-8")
10content = path.read_text(encoding="utf-8")
11print(content)
  • এই কোডটি pathlib দিয়ে ডিরেক্টরি তৈরি, টেক্সট ফাইলে লেখা এবং তার কনটেন্ট পড়ার উদাহরণ দেখায়। Path অবজেক্ট দিয়ে আপনি সহজ ও নিরাপদভাবে পাথ পরিচালনা করতে পারেন।
  • Path-এ iterdir() এবং glob()-এর মতো সুবিধাজনক API রয়েছে। বিভিন্ন অপারেটিং সিস্টেমের পাথ সেপারেটর নিয়ে চিন্তা না করে কোড লিখতে পারবেন।

অস্থায়ী ফাইল ও ডিরেক্টরি (tempfile)

tempfile এর মাধ্যমে নিরাপদভাবে অস্থায়ী ফাইল তৈরি করা যায়। এতে নিরাপত্তাজনিত রেস কন্ডিশন বা নামের দ্বন্দ্ব এড়ানো যায়।

নিম্নের কোড অস্থায়ী ফাইল ব্যবহার করে অস্থায়ী ডেটা তৈরির উদাহরণ দেখায়।

 1import tempfile
 2
 3# Create a temporary file that is deleted on close.
 4with tempfile.NamedTemporaryFile(
 5    mode="w+",
 6    encoding="utf-8",
 7    delete=True
 8) as tmp:
 9    tmp.write("temporary data\n")
10    tmp.seek(0)
11    print(tmp.read())
12
13# tmp is deleted here
  • এই কোডটি একটি অস্থায়ী ফাইল তৈরি করে, ডেটা লেখে ও পড়ে, এবং with ব্লক শেষ হলে স্বয়ংক্রিয়ভাবে মুছে ফেলে। tempfile.NamedTemporaryFile ব্যবহারে নিরাপদ এবং দ্বন্দ্বহীনভাবে অস্থায়ী ফাইল ব্যবস্থাপনা করা যায়। delete=True নির্দিষ্ট করা থাকায় ফাইলটি স্বয়ংক্রিয়ভাবে মুছে যায়।
  • Windows-এ আপনি হয়তো সাথে সাথেই অন্য হ্যান্ডল থেকে ফাইল খুলতে পারবেন না, তাই delete=False দিয়ে নিজেই ডিলিট ম্যানেজ করুন।

shutil: কপি, মুভ ও ডিলিটের জন্য উচ্চ-স্তরের অপারেশন

shutil ব্যবহার করে ফাইল ও ডিরেক্টরি রিকার্সিভভাবে কপি, মুভ বা ডিলিট করা সহজ।

 1import shutil
 2
 3# Copy a file preserving metadata.
 4shutil.copy2("source.txt", "dest.txt")
 5
 6# Move a file or directory.
 7shutil.move("old_location", "new_location")
 8
 9# Remove an entire directory tree (use with caution).
10shutil.rmtree("some_directory")
  • shutil.copy2 মেটাডেটাও কপি করে (যেমন পরিবর্তনের সময়)। যদি রিনেম ব্যবহার করা না যায়, move ফাইলটি মুভ করার বিকল্প ব্যবস্থা নেবে।
  • rmtree বিপজ্জনক অপারেশন, তাই ডিলিট করার আগে সবসময় নিশ্চিত করুন ও ব্যাকআপ নিন।

ফাইল মেটাডেটা (os.stat) এবং অনুমতি ব্যবস্থাপনা

ফাইল সাইজ, পরিবর্তনের সময় এবং পারমিশন osstat দিয়ে পড়া ও পরিবর্তন করা যায়।

নিম্নের কোড os.stat দিয়ে মৌলিক ফাইল তথ্য পাওয়া এবং os.chmod দিয়ে অনুমতি পরিবর্তনের উদাহরণ।

 1import os
 2import stat
 3from datetime import datetime
 4
 5st = os.stat("example.txt")
 6print("size:", st.st_size)
 7print("modified:", datetime.fromtimestamp(st.st_mtime))
 8
 9# Make file read-only for owner.
10os.chmod("example.txt", stat.S_IREAD)
  • POSIX ও Windows সিস্টেমে অনুমতি ভিন্নভাবে কাজ করে। ক্রস-প্ল্যাটফর্ম সামঞ্জস্য জরুরি হলে উচ্চ-স্তরের API ব্যবহার করুন বা কন্ডিশনাল হ্যান্ডলিং যুক্ত করুন।

ফাইল লকিং (এক্সক্লুসিভ কন্ট্রোল) — Unix ও Windows-এ পার্থক্য

একই সঙ্গে একাধিক প্রসেস যখন একই ফাইলে অ্যাক্সেস করে তখন এক্সক্লুসিভ কন্ট্রোল দরকার। UNIX-এ fcntl এবং Windows-এ msvcrt ব্যবহৃত হয়।

নিম্নের কোড UNIX সিস্টেমে লেখার সময় এক্সক্লুসিভ লকের জন্য fcntl.flock ব্যবহার করে।

 1# Unix-style file locking example
 2import fcntl
 3
 4with open("output.txt", "a+", encoding="utf-8") as f:
 5    fcntl.flock(f, fcntl.LOCK_EX)
 6    try:
 7        f.write("Safe write\n")
 8        f.flush()
 9    finally:
10        fcntl.flock(f, fcntl.LOCK_UN)
  • এই কোডটি UNIX জাতীয় সিস্টেমে fcntl.flock ব্যবহার করে সুরক্ষিতভাবে লেখার জন্য এক্সক্লুসিভ লক নেয় এবং একসাথে লেখার সম্ভাবনা বন্ধ করে। প্রসেসিং শেষে সবসময় লক ছেড়ে দিন যাতে অন্য প্রসেস অ্যাক্সেস করতে পারে।
  • Windows-এ msvcrt.locking() ব্যবহার করুন। উচ্চ-স্তরের ব্যবহারের জন্য portalocker বা filelock-এর মতো এক্সটার্নাল লাইব্রেরি বিবেচনা করুন।

অ্যাটমিক ফাইল লেখার প্যাটার্ন

আপডেটের সময় ফাইল দুর্নীতিরোধে, প্রথমে অস্থায়ী ফাইলে লিখুন এবং সফল হলে os.replace দিয়ে আসল ফাইলের জায়গায় দিন।

অস্থায়ী ফাইলে লিখে পরে রিপ্লেস করলে ক্র্যাশ হলেও দুর্নীতি এড়ানো যায়।

 1import os
 2from pathlib import Path
 3import tempfile
 4
 5def atomic_write(path: Path, data: str, encoding="utf-8"):
 6    # Write to a temp file in the same directory and atomically replace.
 7    dirpath = path.parent
 8    with tempfile.NamedTemporaryFile(
 9        mode="w",
10        encoding=encoding,
11        dir=str(dirpath),
12        delete=False
13    ) as tmp:
14        tmp.write(data)
15        tmp.flush()
16        tempname = tmp.name
17
18    # Atomic replacement (on most OSes)
19    os.replace(tempname, str(path))
20
21# Usage
22atomic_write(Path("config.json"), '{"key":"value"}\n')

os.replace একই ফাইল সিস্টেমে অ্যাটমিক রিপ্লেসমেন্ট সম্পন্ন করে। বিভিন্ন মাউন্টের মধ্যে অ্যাটমিকিটি নিশ্চিত নয়—এটা খেয়াল রাখবেন।

mmap ব্যবহার করে দ্রুত অ্যাক্সেস (বড় ডেটার জন্য)

বড় ফাইলে র‍্যান্ডম অ্যাক্সেসের জন্য mmap I/O পারফরম্যান্স বাড়ায়। এটি প্রধানত বাইনারি অপারেশনের সাথে জড়িত।

নিম্নের কোড ফাইলটি মেমরিতে ম্যাপ করে এবং নির্দিষ্ট বাইট রেঞ্জ পড়ে বা লেখে। ফাইল সাইজ পরিবর্তনের সময় সতর্ক থাকুন।

1import mmap
2
3with open("data.bin", "r+b") as f:
4    mm = mmap.mmap(f.fileno(), 0)  # map entire file
5    try:
6        print(mm[:20])  # first 20 bytes
7        mm[0:4] = b"\x00\x01\x02\x03"  # modify bytes
8    finally:
9        mm.close()
  • এই কোডটি mmap দিয়ে বাইনারি ফাইল মেমরিতে অ্যাসাইন করে এবং সরাসরি বাইট স্তরে পড়া/লেখা করে। মেমরি ম্যাপিং দ্বারা বড় ডেটাসেটে দ্রুত র‍্যান্ডম অ্যাক্সেস সম্ভব।
  • mmap কার্যকর, তবে ভুলভাবে ব্যবহার করলে ডেটা অ-সামঞ্জস্যের ঝুঁকি থাকে। প্রয়োজনে সিনক্রোনাইজ করার জন্য flush() কল করুন।

CSV / JSON / Pickle: ফরম্যাট অনুযায়ী পড়া ও লেখা

নির্দিষ্ট ডেটা ফরম্যাটের জন্য পৃথক মডিউল রয়েছে। CSV-র জন্য csv, JSON-র জন্য json এবং পাইথন অবজেক্ট সংরক্ষণের জন্য pickle ব্যবহার করুন।

নিম্নের কোডে CSV ও JSON পড়া ও লেখার এবং Pickle ব্যবহারের মৌলিক উদাহরণ দেখানো হয়েছে। Pickle যেহেতু যেকোনো কোড চালাতে পারে, অবিশ্বস্ত সোর্স থেকে ডেটা লোড করা উচিত নয়।

 1import csv
 2import json
 3import pickle
 4
 5# CSV write
 6with open("rows.csv", "w", encoding="utf-8", newline="") as f:
 7    writer = csv.writer(f)
 8    writer.writerow(["name", "age"])
 9    writer.writerow(["Alice", 30])
10
11# JSON write
12data = {"items": [1, 2, 3]}
13with open("data.json", "w", encoding="utf-8") as f:
14    json.dump(data, f, ensure_ascii=False, indent=2)
15
16# Pickle write (only for trusted environments)
17obj = {"key": "value"}
18with open("obj.pkl", "wb") as f:
19    pickle.dump(obj, f)
  • Windows-এ অপ্রয়োজনীয় খালি লাইনের সমস্যা এড়াতে CSV-তে newline="" নির্দিষ্ট করা সুপারিশ করা হয়। ensure_ascii=False ব্যবহার করলে JSON-এ UTF-8 অক্ষর পাঠযোগ্য থাকে।

কমপ্রেসড ফাইল (gzip / bz2 / zipfile) সরাসরি পড়া ও লেখা

gzip ও zip সরাসরি ব্যবস্থাপনা করলে ডিস্ক স্পেস বাঁচানো যায়। স্ট্যান্ডার্ড লাইব্রেরিতেই সংশ্লিষ্ট মডিউলগুলো আছে।

নিম্নের কোডে টেক্সট হিসেবে gzip ফাইল পড়া ও লেখার সহজ উদাহরণ আছে।

1import gzip
2
3# Write gzipped text.
4with gzip.open("text.gz", "wt", encoding="utf-8") as f:
5    f.write("Compressed content\n")
6
7# Read gzipped text.
8with gzip.open("text.gz", "rt", encoding="utf-8") as f:
9    print(f.read())
  • কম্প্রেশন স্তর এবং বিন্যাসের উপর নির্ভর করে কম্প্রেশন রেশন এবং গতির মধ্যে একটি ট্রেড-অফ আছে।

নিরাপত্তা এবং দুর্বলতা প্রতিরোধের ব্যবস্থা

নিরাপত্তা এবং দুর্বলতা প্রতিরোধের জন্য নিম্নলিখিত বিষয়গুলো বিবেচনা করা যেতে পারে।

  • অবিশ্বস্ত ইনপুট কখনও ফাইলের নাম বা পাথে সরাসরি ব্যবহার করবেন না।
  • Pickle শুধু বিশ্বস্ত সোর্সের সাথে ব্যবহার করুন।
  • 'এক্সিকিউশন অনুমতি' সর্বনিম্ন রাখুন এবং শুধু ফাইল পরিচালনাকারী প্রসেসকে প্রয়োজনীয় ন্যূনতম অনুমতি দিন।
  • tempfile ব্যবহার করে অস্থায়ী ফাইল ব্যবহার করুন এবং পাবলিক ডিরেক্টরিতে সাধারণ ফাইল সংরক্ষণ করবেন না।

ইউজার ইনপুট ফাইল পাথে ব্যবহারের আগে স্বাভাবিককরণ ও যাচাই জরুরি। যেমন, Path.resolve() ব্যবহার করে প্যারেন্ট ডিরেক্টরি চেক করুন।

 1from pathlib import Path
 2
 3def safe_path(base_dir: Path, user_path: str) -> Path:
 4    candidate = (base_dir / user_path).resolve()
 5    if base_dir.resolve() not in candidate.parents and base_dir.resolve() != candidate:
 6        raise ValueError("Invalid path")
 7    return candidate
 8
 9# Usage
10base = Path("/srv/app/data")
11
12# Raises an exception: attempted path traversal outside `base`
13safe = safe_path(base, '../etc/passwd')
  • ওয়েব অ্যাপ অথবা পাবলিক API-তে এক্সটার্নাল ইনপুট ফাইল পাথে ব্যবহার করার সময় বিশেষ সতর্কতা অবলম্বন করুন।

সাধারণ প্যাটার্নের সংক্ষিপ্তসার

  • সবসময় with স্টেটমেন্ট ব্যবহার করুন (স্বয়ংক্রিয় বন্ধ)।
  • টেক্সট ডেটার জন্য স্পষ্টভাবে encoding নির্দিষ্ট করুন।
  • বড় ফাইল চাঙ্কে চাঙ্কে পড়া ও লেখা করুন।
  • শেয়ার করা রিসোর্সের জন্য ফাইল লকিং প্রয়োগ করুন।
  • গুরুত্বপূর্ণ আপডেটের জন্য 'অস্থায়ী ফাইলে লেখার পর os.replace' এই এটোমিক প্যাটার্ন ব্যবহার করুন।
  • কোনো বিপজ্জনক অপারেশন (যেমন মুছে ফেলা বা ওভাররাইট) করার আগে অবশ্যই নিশ্চিত হন এবং ব্যাকআপ নিন।
  • বাহ্যিক ইনপুটকে ফাইল পাথ হিসাবে ব্যবহারের সময় অবশ্যই স্বাভাবিককরণ ও যাচাই করুন।

সারসংক্ষেপ

ফাইল অপারেশনের ক্ষেত্রে নিরাপদ ও নির্ভরযোগ্য পদ্ধতি যেমন with স্টেটমেন্ট ব্যবহার, এনকোডিং স্পষ্টভাবে উল্লেখ এবং এটোমিক লেখা ব্যবহার করা গুরুত্বপূর্ণ। বড় পরিসরের প্রসেসিং বা সমান্তরাল অ্যাক্সেসের জন্য ডাটা দুর্নীতি ও দ্বন্দ্ব রোধে লকিং এবং লগ ব্যবস্থাপনা ব্যবস্থা প্রয়োগ করা আবশ্যক। দক্ষতা ও নিরাপত্তার ভারসাম্য রাখা নির্ভরযোগ্য ফাইল অপারেশনের মূল চাবিকাঠি।

আপনি আমাদের ইউটিউব চ্যানেলে ভিজ্যুয়াল স্টুডিও কোড ব্যবহার করে উপরের নিবন্ধটি অনুসরণ করতে পারেন। দয়া করে ইউটিউব চ্যানেলটিও দেখুন।

YouTube Video