C# File Stream მენტორინგის სესია

ნაწილი II - ფაილებთან და დირექტორიებთან მუშაობა

FileInfo/File და DirectoryInfo/Directory კლასები

📅 სესიის გეგმა (120 წუთი)

დროითი განაწილება:

  • 0-10 წუთი: გამეორება და შესავალი
  • 10-30 წუთი: FileInfo და File კლასების თეორია
  • 30-50 წუთი: DirectoryInfo და Directory კლასების თეორია
  • 50-60 წუთი: შესვენება
  • 60-100 წუთი: პრაქტიკული მაგალითები
  • 100-120 წუთი: საშინაო დავალების განმარტება

სესიის მიზნები:

  • FileInfo და File კლასების განსხვავების გაგება
  • DirectoryInfo და Directory კლასების ათვისება
  • ფაილებისა და დირექტორიების მანიპულაციის ტექნიკების დაუფლება
  • პრაქტიკული პროექტების განხორციელება
📚 თეორიული ნაწილი

FileInfo vs File კლასები

ძირითადი განსხვავებები:

თვისება FileInfo File
ტიპი Instance კლასი Static კლასი
გამოყენება ერთ ფაილთან მრავალჯერადი მუშაობისთვის ერთჯერადი ოპერაციებისთვის
შესრულების სიჩქარე უფრო სწრაფი მრავალჯერადი ოპერაციებისთვის უფრო სწრაფი ერთჯერადი ოპერაციებისთვის
მეხსიერების მოხმარება მეტი მეხსიერება ნაკლები მეხსიერება

FileInfo კლასი

FileInfo - ძირითადი მეთოდები და თვისებები:
  • Name - ფაილის სახელი
  • FullName - ფაილის სრული მისამართი
  • Length - ფაილის ზომა ბაიტებში
  • CreationTime - შექმნის დრო
  • LastWriteTime - ბოლო ცვლილების დრო
  • Exists - ფაილის არსებობა
  • Directory - მშობელი დირექტორია
  • Extension - ფაილის გაფართოება
FileInfo - ძირითადი მეთოდები:
  • Create() - ფაილის შექმნა
  • Delete() - ფაილის წაშლა
  • CopyTo() - ფაილის კოპირება
  • MoveTo() - ფაილის გადატანა
  • OpenRead() - კითხვისთვის გახსნა
  • OpenWrite() - ჩაწერისთვის გახსნა
  • OpenText() - ტექსტის კითხვისთვის
  • CreateText() - ტექსტის ჩაწერისთვის

File კლასი

File - ძირითადი მეთოდები:
  • Exists() - ფაილის არსებობის შემოწმება
  • ReadAllText() - მთელი ტექსტის კითხვა
  • WriteAllText() - ტექსტის ჩაწერა
  • ReadAllLines() - ყველა ხაზის კითხვა
  • WriteAllLines() - ხაზების ჩაწერა
  • Copy() - ფაილის კოპირება
  • Move() - ფაილის გადატანა
  • Delete() - ფაილის წაშლა
  • Create() - ფაილის შექმნა

DirectoryInfo vs Directory კლასები

DirectoryInfo და Directory კლასების განსხვავებები:

თვისება DirectoryInfo Directory
ტიპი Instance კლასი Static კლასი
გამოყენება დირექტორიასთან მრავალჯერადი მუშაობისთვის ერთჯერადი ოპერაციებისთვის
შესრულების სიჩქარე უფრო სწრაფი მრავალჯერადი ოპერაციებისთვის უფრო სწრაფი ერთჯერადი ოპერაციებისთვის

DirectoryInfo კლასი

DirectoryInfo - ძირითადი თვისებები:
  • Name - დირექტორიის სახელი
  • FullName - დირექტორიის სრული მისამართი
  • Exists - დირექტორიის არსებობა
  • Parent - მშობელი დირექტორია
  • Root - root დირექტორია
  • CreationTime - შექმნის დრო
  • LastWriteTime - ბოლო ცვლილების დრო
DirectoryInfo - ძირითადი მეთოდები:
  • Create() - დირექტორიის შექმნა
  • Delete() - დირექტორიის წაშლა
  • GetFiles() - ფაილების მიღება
  • GetDirectories() - ქვე-დირექტორიების მიღება
  • MoveTo() - დირექტორიის გადატანა
  • CreateSubdirectory() - ქვე-დირექტორიის შექმნა

Directory კლასი

Directory - ძირითადი მეთოდები:
  • Exists() - დირექტორიის არსებობის შემოწმება
  • CreateDirectory() - დირექტორიის შექმნა
  • Delete() - დირექტორიის წაშლა
  • GetFiles() - ფაილების სიის მიღება
  • GetDirectories() - დირექტორიების სიის მიღება
  • Move() - დირექტორიის გადატანა
  • GetCurrentDirectory() - მიმდინარე დირექტორიის მიღება
  • SetCurrentDirectory() - მიმდინარე დირექტორიის დაყენება
მნიშვნელოვანი: FileInfo და DirectoryInfo კლასები იყენებენ instance-ს, რაც ნიშნავს, რომ ისინი იხსენებენ ინფორმაციას ფაილის/დირექტორიის შესახებ. თუმცა ეს ინფორმაცია არ განახლდება ავტომატურად, ამიტომ საჭიროა Refresh() მეთოდის გამოყენება.
💡 პრაქტიკული მაგალითები

მაგალითი 1: FileInfo კლასის გამოყენება

ფაილის ინფორმაციის მიღება და მანიპულაცია:


using System;
using System.IO;

class Program
{
    static void Main()
    {
        // FileInfo ობიექტის შექმნა
        FileInfo fileInfo = new FileInfo(@"C:\test\example.txt");

        Console.WriteLine("=== ფაილის ინფორმაცია ===");
        Console.WriteLine($"ფაილის სახელი: {fileInfo.Name}");
        Console.WriteLine($"სრული მისამართი: {fileInfo.FullName}");
        Console.WriteLine($"არსებობა: {fileInfo.Exists}");

        if (fileInfo.Exists)
        {
            Console.WriteLine($"ზომა: {fileInfo.Length} ბაიტი");
            Console.WriteLine($"შექმნის დრო: {fileInfo.CreationTime}");
            Console.WriteLine($"ბოლო ცვლილება: {fileInfo.LastWriteTime}");
            Console.WriteLine($"გაფართოება: {fileInfo.Extension}");
            Console.WriteLine($"მშობელი დირექტორია: {fileInfo.Directory.Name}");

            // ფაილის კოპირება
            string backupPath = @"C:\test\backup_example.txt";
            fileInfo.CopyTo(backupPath, true);
            Console.WriteLine($"ფაილი დაკოპირდა: {backupPath}");
        }
        else
        {
            Console.WriteLine("ფაილი არ არსებობს, შევქმნათ იგი...");

            // ფაილის შექმნა და ტექსტის ჩაწერა
            using (StreamWriter writer = fileInfo.CreateText())
            {
                writer.WriteLine("ეს არის ტესტ ფაილი");
                writer.WriteLine("შექმნილია FileInfo კლასით");
                writer.WriteLine($"შექმნის დრო: {DateTime.Now}");
            }

            Console.WriteLine("ფაილი შეიქმნა წარმატებით!");

            // ინფორმაციის განახლება
            fileInfo.Refresh();
            Console.WriteLine($"ახალი ზომა: {fileInfo.Length} ბაიტი");
        }
    }
}

მაგალითი 2: File კლასის გამოყენება

სტატიკური მეთოდებით ფაილებთან მუშაობა:


string filePath = @"C:\test\static_example.txt";

Console.WriteLine("=== File კლასის მაგალითი ===");

// ფაილის არსებობის შემოწმება
if (File.Exists(filePath))
{
    Console.WriteLine("ფაილი უკვე არსებობს");

    // მთელი ტექსტის კითხვა
    string content = File.ReadAllText(filePath);
    Console.WriteLine("ფაილის შიგთავსი:");
    Console.WriteLine(content);
}
else
{
    Console.WriteLine("ფაილი არ არსებობს, შევქმნათ");

    // ტექსტის ჩაწერა ახალ ფაილში
    string[] lines = {
                        "პირველი ხაზი",
                        "მეორე ხაზი",
                        "მესამე ხაზი",
                        $"შექმნის დრო: {DateTime.Now}"
                        };

    File.WriteAllLines(filePath, lines);
    Console.WriteLine("ფაილი შეიქმნა და ტექსტი ჩაიწერა");
}

// ყველა ხაზის კითხვა
Console.WriteLine("\n=== ყველა ხაზი ცალ-ცალკე ===");
string[] allLines = File.ReadAllLines(filePath);
for (int i = 0; i < allLines.Length; i++)
{
    Console.WriteLine($"ხაზი {i + 1}: {allLines[i]}");
}
// ფაილის კოპირება
string copyPath = @"C:\test\copy_static_example.txt";
File.Copy(filePath, copyPath, true);
Console.WriteLine($"\nფაილი დაკოპირდა: {copyPath}"); // დამატებითი ტექსტის ჩაწერა
File.AppendAllText(filePath, $"\nდამატებული ხაზი: {DateTime.Now}");
Console.WriteLine("დამატებითი ტექსტი ჩაიწერა");
                        

მაგალითი 3: DirectoryInfo კლასის გამოყენება

დირექტორიებთან მუშაობა DirectoryInfo-ით:


using System;
using System.IO;

class Program
{
    static void Main()
    {
        // DirectoryInfo ობიექტის შექმნა
        DirectoryInfo dirInfo = new DirectoryInfo(@"C:\test\MyFolder");

        Console.WriteLine("=== დირექტორიის ინფორმაცია ===");
        Console.WriteLine($"დირექტორიის სახელი: {dirInfo.Name}");
        Console.WriteLine($"სრული მისამართი: {dirInfo.FullName}");
        Console.WriteLine($"არსებობა: {dirInfo.Exists}");

        if (!dirInfo.Exists)
        {
            Console.WriteLine("დირექტორია არ არსებობს, შევქმნათ...");
            dirInfo.Create();
            Console.WriteLine("დირექტორია შეიქმნა!");
        }

        // ქვე-დირექტორიების შექმნა
        DirectoryInfo subDir1 = dirInfo.CreateSubdirectory("Documents");
        DirectoryInfo subDir2 = dirInfo.CreateSubdirectory("Images");
        DirectoryInfo subDir3 = dirInfo.CreateSubdirectory("Videos");

        Console.WriteLine("\nქვე-დირექტორიები შეიქმნა:");
        Console.WriteLine($"- {subDir1.Name}");
        Console.WriteLine($"- {subDir2.Name}");
        Console.WriteLine($"- {subDir3.Name}");

        // ფაილების შექმნა ქვე-დირექტორიებში
        CreateSampleFile(Path.Combine(subDir1.FullName, "document1.txt"), "ეს არის დოკუმენტი");
        CreateSampleFile(Path.Combine(subDir1.FullName, "document2.txt"), "მეორე დოკუმენტი");
        CreateSampleFile(Path.Combine(subDir2.FullName, "image1.jpg"), "ფოტოს მონაცემები");
        CreateSampleFile(Path.Combine(subDir3.FullName, "video1.mp4"), "ვიდეოს მონაცემები");

        Console.WriteLine("\n=== დირექტორიის შიგთავსი ===");

        // ყველა ქვე-დირექტორიის ჩვენება
        DirectoryInfo[] directories = dirInfo.GetDirectories();
        Console.WriteLine("ქვე-დირექტორიები:");
        foreach (DirectoryInfo dir in directories)
        {
            Console.WriteLine($" 📁 {dir.Name} (შექმნის დრო: {dir.CreationTime.ToShortDateString()})");

            // ყველა ფაილის ჩვენება ამ დირექტორიაში
            FileInfo[] files = dir.GetFiles();
            foreach (FileInfo file in files)
            {
                Console.WriteLine($" 📄 {file.Name} ({file.Length} ბაიტი)");
            }
        }

        // მშობელი დირექტორიის ინფორმაცია
        if (dirInfo.Parent != null)
        {
            Console.WriteLine($"\nმშობელი დირექტორია: {dirInfo.Parent.Name}");
        }
    }

    static void CreateSampleFile(string filePath, string content)
    {
        File.WriteAllText(filePath, content);
    }
}
                        

მაგალითი 4: Directory კლასის გამოყენება

სტატიკური მეთოდებით დირექტორიებთან მუშაობა:


using System;
using System.IO;

class Program
{
    static void Main()
    {
        string baseDir = @"C:\test\StaticDirectory";

        Console.WriteLine("=== Directory კლასის მაგალითი ===");
        Console.WriteLine($"მიმდინარე დირექტორია: {Directory.GetCurrentDirectory()}");

        // დირექტორიის შექმნა
        if (!Directory.Exists(baseDir))
        {
            Directory.CreateDirectory(baseDir);
            Console.WriteLine($"დირექტორია შეიქმნა: {baseDir}");
        }

        // რამდენიმე ქვე-დირექტორიის შექმნა
        string[] subDirs = { "Folder1", "Folder2", "Folder3" };
        foreach (string subDir in subDirs)
        {
            string fullPath = Path.Combine(baseDir, subDir);
            Directory.CreateDirectory(fullPath);

            // ყველა ქვე-დირექტორიაში ფაილების შექმნა
            for (int i = 1; i <= 3; i++)
            {
                string fileName = $"file{i}.txt";
                string
                filePath = Path.Combine(fullPath, fileName);
                File.WriteAllText(filePath, $"ეს არის ფაილი {i} დირექტორიაში {subDir}");
            }
        }

        Console.WriteLine("\n === ყველა ფაილის ჩვენება=== ");
        // ყველა ფაილის მოძიება (ყველა ქვე-დირექტორიაში)
        string[] allFiles = Directory.GetFiles(baseDir, " *.txt", SearchOption.AllDirectories);
        foreach (string file in
                    allFiles)
        {
            FileInfo fileInfo = new FileInfo(file);
            Console.WriteLine($"📄 {fileInfo.Name} - {fileInfo.DirectoryName} ({fileInfo.Length} ბაიტი)");
        }
        Console.WriteLine("\n === ყველა დირექტორიის ჩვენება === ");
        // ყველა ქვე-დირექტორიის მოძიება
        string[] allDirs = Directory.GetDirectories(baseDir, " *", SearchOption.AllDirectories);
        foreach (string dir in
                        allDirs)
        {
            DirectoryInfo dirInfo = new DirectoryInfo(dir);
            Console.WriteLine($"📁 {dirInfo.Name} - {dirInfo.FullName}");
        } // განსაკუთრებული ფაილების მოძიება
        Console.WriteLine("\n==='.txt' ფაილების მოძიება===");
        string[] txtFiles = Directory.GetFiles(baseDir, " *.txt", SearchOption.TopDirectoryOnly);
        Console.WriteLine($"მთავარ დირექტორიაში ნაპოვნია {txtFiles.Length} .txt ფაილი");
        // დირექტორიის გადატანა
        string newLocation = @"C:\test\MovedDirectory";
        if
        (Directory.Exists(newLocation))
        { Directory.Delete(newLocation, true); }
        Directory.Move(baseDir, newLocation);
        Console.WriteLine($"\nდირექტორია გადატანილია: {newLocation} ");
    }
}
                        

მაგალითი 5: კომპლექსური ფაილური სისტემის მენეჯერი

ფაილური სისტემის მენეჯერი ყველა კლასის გამოყენებით:


using System;
using System.IO;
using System.Linq;

class FileSystemManager
{
    static void Main()
    {
        string workingDirectory = @"C:\test\FileManager";

        // მუშა დირექტორიის შექმნა
        Directory.CreateDirectory(workingDirectory);

        Console.WriteLine("=== ფაილური სისტემის მენეჯერი ===\n");

        bool exit = false;
        while (!exit)
        {
            ShowMenu();
            string choice = Console.ReadLine();

            switch (choice)
            {
                case "1":
                    CreateFileStructure(workingDirectory);
                    break;
                case "2":
                    ShowDirectoryInfo(workingDirectory);
                    break;
                case "3":
                    SearchFiles(workingDirectory);
                    break;
                case "4":
                    CopyFiles(workingDirectory);
                    break;
                case "5":
                    CleanupFiles(workingDirectory);
                    break;
                case "6":
                    exit = true;
                    break;
                default:
                    Console.WriteLine("არასწორი არჩევანი!");
                    break;
            }

            if (!exit)
            {
                Console.WriteLine("\nდააჭირეთ ნებისმიერ ღილაკს გასაგრძელებლად...");
                Console.ReadKey();
                Console.Clear();
            }
        }
    }

    static void ShowMenu()
    {
        Console.WriteLine("აირჩიეთ ოპერაცია:");
        Console.WriteLine("1. ფაილური სტრუქტურის შექმნა");
        Console.WriteLine("2. დირექტორიის ინფორმაციის ჩვენება");
        Console.WriteLine("3. ფაილების ძიება");
        Console.WriteLine("4. ფაილების კოპირება");
        Console.WriteLine("5. ფაილების გაწმენდა");
        Console.WriteLine("6. გამოსვლა");
        Console.Write("თქვენი არჩევანი: ");
    }

    static void CreateFileStructure(string baseDir)
    {
        Console.WriteLine("ფაილური სტრუქტურის შექმნა...\n");

        // დირექტორიების შექმნა DirectoryInfo-ით
        DirectoryInfo mainDir = new DirectoryInfo(baseDir);

        DirectoryInfo documentsDir = mainDir.CreateSubdirectory("Documents");
        DirectoryInfo imagesDir = mainDir.CreateSubdirectory("Images");
        DirectoryInfo backupDir = mainDir.CreateSubdirectory("Backup");

        // ფაილების შექმნა FileInfo-ით
        CreateDocumentFile(documentsDir.FullName, "report.txt", "ეს არის ანგარიშის ფაილი");
        CreateDocumentFile(documentsDir.FullName, "notes.txt", "ჩანაწერები და შენიშვნები");
        CreateDocumentFile(documentsDir.FullName, "log.txt", GenerateLogContent());

        CreateDocumentFile(imagesDir.FullName, "photo1.jpg", "ფოტო 1 - მონაცემები");
        CreateDocumentFile(imagesDir.FullName, "photo2.png", "ფოტო 2 - მონაცემები");

        Console.WriteLine("ფაილური სტრუქტურა შეიქმნა წარმატებით!");
    }

    static void CreateDocumentFile(string directory, string fileName, string content)
    {
        FileInfo fileInfo = new FileInfo(Path.Combine(directory, fileName));

        using (StreamWriter writer = fileInfo.CreateText())
        {
            writer.WriteLine(content);
            writer.WriteLine($"შექმნის დრო: {DateTime.Now}");
            writer.WriteLine($"ზომა: {content.Length} სიმბოლო");
        }

        Console.WriteLine($"შეიქმნა: {fileInfo.Name}");
    }

    static string GenerateLogContent()
    {
        return $@"=== სისტემის ლოგი ===
                            დრო: {DateTime.Now}
                            მომხმარებელი: System
                            ქმედება: ფაილების შექმნა
                            სტატუსი: წარმატებული
                            დეტალები: ფაილური სტრუქტურა შეიქმნა";
    }

    static void ShowDirectoryInfo(string baseDir)
    {
        Console.WriteLine("დირექტორიის ინფორმაცია:\n");

        DirectoryInfo dirInfo = new DirectoryInfo(baseDir);

        Console.WriteLine($"დირექტორია: {dirInfo.Name}");
        Console.WriteLine($"სრული მისამართი: {dirInfo.FullName}");
        Console.WriteLine($"შექმნის დრო: {dirInfo.CreationTime}");
        Console.WriteLine($"ბოლო ცვლილება: {dirInfo.LastWriteTime}");

        // ქვე-დირექტორიების ინფორმაცია
        DirectoryInfo[] subDirs = dirInfo.GetDirectories();
        Console.WriteLine($"\nქვე-დირექტორიები ({subDirs.Length}):");

        foreach (DirectoryInfo subDir in subDirs)
        {
            FileInfo[] files = subDir.GetFiles();
            long totalSize = files.Sum(f => f.Length);

            Console.WriteLine($" 📁 {subDir.Name}");
            Console.WriteLine($" ფაილები: {files.Length}");
            Console.WriteLine($" მთლიანი ზომა: {totalSize} ბაიტი");

            foreach (FileInfo file in files)
            {
                Console.WriteLine($" 📄 {file.Name} ({file.Length} ბაიტი)");
            }
        }
    }

    static void SearchFiles(string baseDir)
    {
        Console.Write("შეიყვანეთ საძიებო პატერნი (მაგ: *.txt): ");
        string pattern = Console.ReadLine();

        if (string.IsNullOrWhiteSpace(pattern))
            pattern = "*.*";

        Console.WriteLine($"\nძიება: {pattern}\n");

        try
        {
            string[] files = Directory.GetFiles(baseDir, pattern, SearchOption.AllDirectories);

            Console.WriteLine($"ნაპოვნია {files.Length} ფაილი:");

            foreach (string file in files)
            {
                FileInfo fileInfo = new FileInfo(file);
                Console.WriteLine($"📄 {fileInfo.Name}");
                Console.WriteLine($" მისამართი: {fileInfo.DirectoryName}");
                Console.WriteLine($" ზომა: {fileInfo.Length} ბაიტი");
                Console.WriteLine($" ბოლო ცვლილება: {fileInfo.LastWriteTime}");
                Console.WriteLine();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"შეცდომა ძიებისას: {ex.Message}");
        }
    }

    static void CopyFiles(string baseDir)
    {
        Console.WriteLine("ფაილების კოპირება Backup დირექტორიაში...\n");

        string backupDir = Path.Combine(baseDir, "Backup");
        Directory.CreateDirectory(backupDir);

        // ყველა .txt ფაილის კოპირება
        string[] txtFiles = Directory.GetFiles(baseDir, "*.txt", SearchOption.AllDirectories);

        foreach (string file in txtFiles)
        {
            FileInfo sourceFile = new FileInfo(file);

            // თუ ფაილი უკვე backup დირექტორიაშია, გამოვტოვოთ
            if (sourceFile.DirectoryName.Contains("Backup"))
                continue;

            string backupFileName = $"backup_{DateTime.Now:yyyyMMdd}_{sourceFile.Name}";
            string backupPath = Path.Combine(backupDir, backupFileName);

            sourceFile.CopyTo(backupPath, true);
            Console.WriteLine($"დაკოპირდა: {sourceFile.Name} -> {backupFileName}");
        }

        Console.WriteLine("\nკოპირება დასრულდა!");
    }

    static void CleanupFiles(string baseDir)
    {
        Console.WriteLine("ძველი backup ფაილების გაწმენდა...\n");

        string backupDir = Path.Combine(baseDir, "Backup");

        if (!Directory.Exists(backupDir))
        {
            Console.WriteLine("Backup დირექტორია არ არსებობს.");
            return;
        }

        DirectoryInfo backupDirInfo = new DirectoryInfo(backupDir);
        FileInfo[] backupFiles = backupDirInfo.GetFiles();

        // 1 დღეზე ძველი ფაილების წაშლა
        DateTime cutoffDate = DateTime.Now.AddDays(-1);
        int deletedCount = 0;

        foreach (FileInfo file in backupFiles)
        {
            if (file.CreationTime < cutoffDate)
            {
                Console.WriteLine($"იშლება: {file.Name} (შექმნილია:{file.CreationTime})");
                file.Delete();
                deletedCount++;
            }
        }
        Console.WriteLine($"\nწაიშალა{deletedCount}ძველი ფაილი.");
    }
}
                            
🔨 დამატებითი კოდის მაგალითები

მაგალითი: ფაილების ფილტრაცია და სორტირება


using System;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;

class FileFilterExample
{
    static void Main()
    {
        string directory = @"C:\test\FilterExample";
        Directory.CreateDirectory(directory);

        // ტესტ ფაილების შექმნა
        CreateTestFiles(directory);

        Console.WriteLine("=== ფაილების ფილტრაცია და სორტირება ===\n");

        DirectoryInfo dirInfo = new DirectoryInfo(directory);
        FileInfo[] allFiles = dirInfo.GetFiles();

        // ზომის მიხედვით სორტირება (კლებადობით)
        var largestFiles = allFiles
        .OrderByDescending(f => f.Length)
        .Take(5);

        Console.WriteLine("5 ყველაზე დიდი ფაილი:");
        foreach (var file in largestFiles)
        {
            Console.WriteLine($"📄 {file.Name} - {file.Length} ბაიტი");
        }

        // ბოლოს შეცვლილი ფაილები
        var recentFiles = allFiles
        .Where(f => f.LastWriteTime > DateTime.Now.AddDays(-1))
        .OrderBy(f => f.LastWriteTime);

        Console.WriteLine("\nბოლო 24 საათში შეცვლილი ფაილები:");
        foreach (var file in recentFiles)
        {
            Console.WriteLine($"📄 {file.Name} - {file.LastWriteTime}");
        }

        // გაფართოების მიხედვით დაჯგუფება
        var filesByExtension = allFiles
        .GroupBy(f => f.Extension.ToLower())
        .OrderBy(g => g.Key);

        Console.WriteLine("\nფაილები გაფართოების მიხედვით:");
        foreach (var group in filesByExtension)
        {
            Console.WriteLine($"\n{group.Key} ({group.Count()} ფაილი):");
            foreach (var file in group.OrderBy(f => f.Name))
            {
                Console.WriteLine($" 📄 {file.Name}");
            }
        }
    }

    static void CreateTestFiles(string directory)
    {
        Random random = new Random();
        string[] extensions = { ".txt", ".log", ".dat", ".tmp", ".bak" };
        string[] names = { "document", "report", "data", "backup", "temp", "log", "config" };

        for (int i = 0; i < 15; i++)
        {
            string
            fileName = $"{names[random.Next(names.Length)]}{i}{extensions[random.Next(extensions.Length)]}";
            string filePath = Path.Combine(directory, fileName); // შემთხვევითი ზომის შიგთავსი string
            content = new string('X', random.Next(100, 2000));
            File.WriteAllText(filePath, content); //
            შემთხვევითი თარიღის დაყენება DateTime randomDate = DateTime.Now.AddDays(-random.Next(0,
            10)).AddHours(-random.Next(0, 24));
            File.SetLastWriteTime(filePath, randomDate);
        }
    }
}
                    

მაგალითი: ფაილების მონიტორინგი


using System;
using System.IO;

class FileMonitorExample
{
    private static FileSystemWatcher watcher;

    static void Main()
    {
        string monitorPath = @"C:\test\Monitor";
        Directory.CreateDirectory(monitorPath);

        Console.WriteLine($"ფაილების მონიტორინგი: {monitorPath}");
        Console.WriteLine("დააჭირეთ 'q'-ს გასასვლელად\n");

        // FileSystemWatcher-ის კონფიგურაცია
        watcher = new FileSystemWatcher(monitorPath);

        // ყველა ტიპის ცვლილების მონიტორინგი
        watcher.NotifyFilter = NotifyFilters.CreationTime
        | NotifyFilters.LastWrite
        | NotifyFilters.FileName
        | NotifyFilters.DirectoryName;

        // ყველა ფაილის მონიტორინგი
        watcher.Filter = "*.*";

        // ივენთების დაერთება
        watcher.Created += OnCreated;
        watcher.Changed += OnChanged;
        watcher.Deleted += OnDeleted;
        watcher.Renamed += OnRenamed;

        // მონიტორინგის დაწყება
        watcher.EnableRaisingEvents = true;

        // ტესტ ფაილების შექმნა
        CreateTestMonitorFiles(monitorPath);

        // მომხმარებლის შეყვანის მოლოდინი
        char key;
        do
        {
            key = Console.ReadKey(true).KeyChar;
        } while (key != 'q' && key != 'Q');

        watcher.Dispose();
        Console.WriteLine("\nმონიტორინგი გათიშულია.");
    }

    private static void OnCreated(object sender, FileSystemEventArgs e)
    {
        Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] ✅ შეიქმნა: {e.Name}");
        ShowFileInfo(e.FullPath);
    }

    private static void OnChanged(object sender, FileSystemEventArgs e)
    {
        Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] ✏️ შეცვლილია: {e.Name}");
        ShowFileInfo(e.FullPath);
    }

    private static void OnDeleted(object sender, FileSystemEventArgs e)
    {
        Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] ❌ წაიშალა: {e.Name}");
    }

    private static void OnRenamed(object sender, RenamedEventArgs e)
    {
        Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 🔄 გადაკრებილია: {e.OldName} -> {e.Name}");
    }

    private static void ShowFileInfo(string filePath)
    {
        try
        {
            if (File.Exists(filePath))
            {
                FileInfo fileInfo = new FileInfo(filePath);
                Console.WriteLine($" 📊 ზომა: {fileInfo.Length} ბაიტი, ბოლო ცვლილება: {fileInfo.LastWriteTime}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($" ⚠️ შეცდომა ინფორმაციის მიღებისას: {ex.Message}");
        }
    }

    private static void CreateTestMonitorFiles(string directory)
    {
        Console.WriteLine("ტესტ ფაილების შექმნა...\n");

        // 3 წამში ფაილების შექმნა
        System.Threading.Timer timer = new System.Threading.Timer(_ =>
        {
            try
            {
                string fileName = $"test_{DateTime.Now:HHmmss}.txt";
                string filePath = Path.Combine(directory, fileName);
                File.WriteAllText(filePath, $"ტესტ ფაილი შექმნილია: {DateTime.Now}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"შეცდომა ტესტ ფაილის შექმნისას: {ex.Message}");
            }
        }, null, TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5));

        // ტაიმერი გავაჩეროთ 20 წამში
        System.Threading.Timer stopTimer = new System.Threading.Timer(_ =>
        {
            timer.Dispose();
            Console.WriteLine("ტესტ ფაილების შექმნა შეწყდა.\n");
        }, null, TimeSpan.FromSeconds(20), Timeout.InfiniteTimeSpan);
    }
}
                            
📝 საშინაო დავალება

საშინაო დავალება: ფაილური ორგანაიზერი

მიზანი: შექმენით C# პროგრამა, რომელიც ავტომატურად დაალაგებს ფაილებს მათი ტიპის მიხედვით.

ძირითადი მოთხოვნები:

1. ძირითადი ფუნქციონალი (40 ქულა)

  • შექმენით პროგრამა, რომელიც მიიღებს მისამართს დირექტორიისა
  • პროგრამამ უნდა შექმნას ქვე-დირექტორიები: "Documents", "Images", "Videos", "Music", "Others"
  • ყველა ფაილი უნდა გადატანილი იქნას შესაბამის ქვე-დირექტორიაში მისი გაფართოების მიხედვით
  • გამოიყენეთ როგორც FileInfo/DirectoryInfo, ასევე File/Directory კლასები

2. ფაილების კატეგორიზაცია (20 ქულა)

  • Documents: .txt, .doc, .docx, .pdf, .rtf
  • Images: .jpg, .jpeg, .png, .gif, .bmp
  • Videos: .mp4, .avi, .mkv, .wmv, .mov
  • Music: .mp3, .wav, .flac, .aac
  • Others: ყველა სხვა ფაილი

3. ანგარიშგება (20 ქულა)

  • შექმენით ანგარიში, რომელიც შეიცავს:
  • დამუშავებული ფაილების რაოდენობას
  • ყველა კატეგორიის ფაილების რაოდენობას
  • მთლიან ზომას ყველა კატეგორიისთვის
  • ანგარიში შეინახოს "OrganizationReport.txt" ფაილში

4. შეცდომების მართვა (10 ქულა)

  • დაამუშავეთ შესაძლო შეცდომები (ფაილი დაკავებულია, წვდომის უფლება არ არის, და ა.შ.)
  • აჩვენეთ მომხმარებელს შესაბამისი შეტყობინებები

5. დამატებითი ფუნქციები (ბონუსი 10 ქულა)

  • დუბლიკატი ფაილების აღმოჩენა (ერთნაირი სახელი და ზომა)
  • ძველი ფაილების (1 თვეზე მეტი) ცალკე "Archive" ფოლდერში გადატანა
  • ფაილების ზომის მიხედვით დალაგება თითოეულ კატეგორიაში

შესრულების ინსტრუქციები:

  1. პროექტის შექმნა: შექმენით ახალი C# Console Application პროექტი
  2. კოდის დაწერა: დაწერეთ FileOrganizer კლასი მოცემული სტრუქტურის მიხედვით
  3. ტესტირება: შექმენით ტესტ დირექტორია სხვადასხვა ტიპის ფაილებით
  4. ანგარიშის შემოწმება: დარწმუნდით, რომ OrganizationReport.txt სწორად იქმნება
  5. შეცდომების ტესტირება: შეამოწმეთ რა ხდება არასწორი მისამართის შეყვანისას

შეფასების კრიტერიუმები:

  • კოდის ხარისხი (20%): სუფთა, კომენტირებული კოდი
  • ფუნქციონალურობა (40%): ყველა მოთხოვნის შესრულება
  • შეცდომების მართვა (20%): try-catch ბლოკების სწორი გამოყენება
  • ანგარიშგება (20%): დეტალური და ინფორმატიული ანგარიშის შექმნა

გაგზავნის ინსტრუქცია:

ვადა: მომავალი სესიიდან 1 კვირა

ჩასაბარებელი ფაილები:

  • Program.cs - თქვენი მთავარი კოდი
  • Screenshot.png - სკრინშოტი მუშა პროგრამისა
  • TestReport.txt - ტესტირების ანგარიში
მნიშვნელოვანი შენიშვნები:
  • ყოველთვის გამოიყენეთ using statements ფაილებთან მუშაობისას
  • შეამოწმეთ ფაილის არსებობა წაშლისა და გადატანის წინ
  • არ დაავიწყდეთ Refresh() მეთოდის გამოძახება FileInfo/DirectoryInfo ობიექტებისთვის
  • ბექაპი გაუკეთეთ ტესტ ფაილებს ძირითადი ტესტირების წინ
📚 დამატებითი რესურსები და რჩევები

სასარგებლო რჩევები

როდის გამოვიყენოთ FileInfo vs File:

  • გამოიყენეთ FileInfo როდესაც:
    • ერთ ფაილთან რამდენჯერმე მუშაობთ
    • ფაილის მრავალი თვისება გჭირდებათ
    • ობიექტ-ორიენტირებული მიდგომა გირჩევნიათ
  • გამოიყენეთ File როდესაც:
    • ერთჯერადი, სწრაფი ოპერაციები გჭირდებათ
    • მეხსიერების ეკონომია მნიშვნელოვანია
    • მარტივი utility ფუნქციები იწერთ

შესრულების ოპტიმიზაცია:

  • დიდი ფაილებისთვის: გამოიყენეთ FileStream buffer-ით
  • მრავალი ფაილისთვის: მარტო Directory.GetFiles() ერთხელ გამოიძახეთ
  • Recursive ძიებისთვის: SearchOption.AllDirectories გამოიყენეთ
  • მონიტორინგისთვის: FileSystemWatcher უფრო ეფექტურია მუდმივი polling-ისა

ხშირი შეცდომები და მათი აცილება:

  • Path.Combine() გამოიყენეთ: არა string concatenation
  • Using statements: ყოველთვის გამოიყენეთ IDisposable რესურსებისთვის
  • Exception handling: UnauthorizedAccessException, IOException დაამუშავეთ
  • File locks: შეამოწმეთ ფაილი დაკავებული თუ არა რა

პრაქტიკული რჩევები კოდის ხარისხისთვის

კოდის სტრუქტურა:
// ✅ სწორი - ზოგადი მეთოდების გამოყენება public static class FileHelper { public static bool IsValidFile(string filePath) { return File.Exists(filePath) && new FileInfo(filePath).Length > 0; } public static string GetFileCategory(string extension) { var categories = new Dictionary { {"Documents", new[] {".txt", ".doc", ".pdf"}}, {"Images", new[] {".jpg", ".png", ".gif"}}, // ... }; return categories.FirstOrDefault(c => c.Value.Contains(extension.ToLower())).Key ?? "Others"; } } // ❌ არასწორი - გამეორებადი კოდი if (file.EndsWith(".txt") || file.EndsWith(".doc") || file.EndsWith(".pdf")) { // documents... } if (file.EndsWith(".jpg") || file.EndsWith(".png") || file.EndsWith(".gif")) { // images... }
შეცდომების სწორი მართვა:
// ✅ სწორი - კონკრეტული exceptions try { file.MoveTo(destinationPath); } catch (UnauthorizedAccessException) { Console.WriteLine("არ გაქვთ წვდომის უფლება ამ ფაილზე"); } catch (DirectoryNotFoundException) { Console.WriteLine("დანიშნულების დირექტორია არ არსებობს"); } catch (IOException ex) when (ex.HResult == -2147024864) // File in use { Console.WriteLine("ფაილი გამოიყენება სხვა პროცესის მიერ"); } // ❌ არასწორი - ზოგადი exception catching try { file.MoveTo(destinationPath); } catch (Exception ex) { Console.WriteLine("რაღაც შეცდომა მოხდა: " + ex.Message); }

უსაფრთხოება და Best Practices

მნიშვნელოვანი უსაფრთხოების ასპექტები:

  • Path Traversal თავიდან აცილება: Path.GetFullPath() გამოიყენეთ
  • წვდომის უფლებების შემოწმება: Directory/File.GetAccessControl()
  • Temp ფაილები: Path.GetTempFileName() გამოიყენეთ
  • სენსიტიური მონაცემები: არ დატოვოთ plain text-ში

მეხსიერების ეფექტური გამოყენება:

// ✅ სწორი - მეხსიერების ეფექტური გამოყენება using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) using (var reader = new StreamReader(stream)) { string line; while ((line = reader.ReadLine()) != null) { // ხაზის დამუშავება... } } // ❌ არასწორი - მთელი ფაილი მეხსიერებაში string[] allLines = File.ReadAllLines(path); // დიდი ფაილებისთვის პრობლემატური
❓ ხშირი კითხვები და პასუხები
1. რატომ უნდა გამოვიყენო using statement?

პასუხი: using statement ავტომატურად ანთავისუფლებს რესურსებს (ფაილების handles, მეხსიერება) კოდის ბლოკის დასრულების შემდეგ, მაშინაც კი თუ exception მოხდება. ეს აცილებს მეხსიერების გადინებას და ფაილების "ჩაკეტვას".

2. როგორ შევამოწმო ფაილი დაკავებული ხომ არ არის?

პასუხი:

public static bool IsFileLocked(string filePath) { try { using (FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.None)) { stream.Close(); } } catch (IOException) { return true; // ფაილი დაკავებულია } return false; }
3. რა განსხვავებაა SearchOption.TopDirectoryOnly და AllDirectories შორის?

პასუხი:

  • TopDirectoryOnly: ეძებს მხოლოდ მითითებულ დირექტორიაში, ქვე-დირექტორიებში არა
  • AllDirectories: ეძებს მითითებული დირექტორიისა და მისი ყველა ქვე-დირექტორიის ჩათვლით (recursive)
4. როგორ გავიგო ფაილის რეალური ტიპი, არა მარტო extension?

პასუხი: Windows-ში შეგიძლიათ P/Invoke გამოიყენოთ, ან third-party ბიბლიოთეკები:

// File signature (Magic Numbers) შემოწმება public static bool IsPdfFile(string filePath) { byte[] pdfSignature = { 0x25, 0x50, 0x44, 0x46 }; // %PDF using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { byte[] buffer = new byte[4]; fs.Read(buffer, 0, 4); return buffer.SequenceEqual(pdfSignature); } }
5. როგორ ვამუშაო ძალიან დიდ ფაილებს?

პასუხი: გამოიყენეთ streaming და chunked reading:

public static void ProcessLargeFile(string filePath) { const int bufferSize = 64 * 1024; // 64KB chunks using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = fs.Read(buffer, 0, bufferSize)) > 0) { // buffer-ის დამუშავება... ProcessChunk(buffer, bytesRead); } } }
6. როგორ ვაკეთო atomic file operations?

პასუხი: გამოიყენეთ temp file და შემდეგ rename:

public static void WriteFileSafely(string filePath, string content) { string tempPath = Path.GetTempFileName(); try { // ჯერ temp ფაილში ჩაწერე File.WriteAllText(tempPath, content); // შემდეგ rename (atomic operation) File.Move(tempPath, filePath); } catch { // თუ შეცდომა მოხდა, temp ფაილი წავშალოთ if (File.Exists(tempPath)) File.Delete(tempPath); throw; } }