CodeGym /Kurslar /C# SELF /Yanaşmaların müqayisəsi File vs FileInfo

Yanaşmaların müqayisəsi File vs FileInfo

C# SELF
Səviyyə, Dərs
Mövcuddur

1. Giriş

.NET-də fayllar və qovluqlarla işləmək üçün fəlsəfi cəhətdən fərqli iki sinif qrupları var:

Statik siniflər: File, Directory — utilitar funksiyalar dəsti kimi işləyir: metodu çağırırsan, yol verirsən, nəticəni alırsan.

İnstant siniflər: FileInfo, DirectoryInfo — konkret faylları və qovluqları öz xüsusiyyətləri və metodları olan obyektlər kimi təmsil edir.

Niyə hər iki yanaşma var? Bu sadəlik (statik metodlar) ilə obyekt yönümlü çevikliyi (instans siniflər) arasında kompromisdir. Hər biri öz ssenarilərində rahatdır.

2. Statik siniflərin fəlsəfəsi

File və Directory sinifləri "Sadəcə et!" prinsipinə əməl edir. Onlar fayl sistemi ilə əməliyyatları icra etmək üçün birbaşa interfeys təmin edir, arada heç bir ara obyekt yaratmağa ehtiyac qalmır.

// Faylın mövcudluğunu yoxlamaq
if (File.Exists("document.txt"))
{
    // Bütün mətni oxumaq
    string content = File.ReadAllText("document.txt");
    
    // Ehtiyat nüsxə yaratmaq
    File.Copy("document.txt", "document_backup.txt");
    
    // Orijinalı silmək
    File.Delete("document.txt");
}

Bu, sadə, bir dəfəlik əməliyyatlar üçün rahatdır: obyektlər, onların həyat dövrü və vəziyyəti barədə düşünməyə ehtiyac yoxdur — sadəcə fayl yolunu verib lazım olan metodu çağırırsan.

Oxşar şəkildə Directory işləyir:

// Qovluq yaratmaq
Directory.CreateDirectory(@"C:\MyProject\Data");

// Bütün mətn fayllarını əldə etmək
string[] textFiles = Directory.GetFiles(@"C:\MyProject", "*.txt");

// Qovluğun mövcudluğunu yoxlamaq
if (Directory.Exists(@"C:\Temp"))
{
    Directory.Delete(@"C:\Temp", recursive: true);
}

3. Praktiki nümunələr əsasında müqayisə

Nümunə 1: Sadə fayl kopyalama

Statik yanaşma:

string sourcePath = "original.txt";
string destinationPath = "copy.txt";

if (File.Exists(sourcePath))
{
    File.Copy(sourcePath, destinationPath, overwrite: true);
    Console.WriteLine("Fayl kopyalandı");
}
else
{
    Console.WriteLine("Mənbə faylı tapılmadı");
}

İnstant yanaşma:

var sourceFile = new FileInfo("original.txt");
var destinationFile = new FileInfo("copy.txt");

if (sourceFile.Exists)
{
    sourceFile.CopyTo(destinationFile.FullName, overwrite: true);
    Console.WriteLine("Fayl kopyalandı");
}
else
{
    Console.WriteLine("Mənbə faylı tapılmadı");
}

Burada statik yanaşma daha səlisdir. Amma əlavə məlumat lazım olsa nə olar?

Nümunə 2: Ölçünü yoxlamaqla kopyalama

Statik yanaşma:

string sourcePath = "largefile.zip";
string destinationPath = "backup.zip";

if (File.Exists(sourcePath))
{
    var fileInfo = new FileInfo(sourcePath); // Yenə də obyekt yaratmaq lazım oldu!
    if (fileInfo.Length > 100 * 1024 * 1024) // 100 MB-dan böyük
    {
        Console.WriteLine($"Diqqət: böyük fayl kopyalanır ({fileInfo.Length / 1024 / 1024} MB)");
    }
    
    File.Copy(sourcePath, destinationPath, overwrite: true);
}

İnstant yanaşma:

var sourceFile = new FileInfo("largefile.zip");

if (sourceFile.Exists)
{
    if (sourceFile.Length > 100 * 1024 * 1024) // 100 MB-dan böyük
    {
        Console.WriteLine($"Diqqət: böyük fayl kopyalanır ({sourceFile.Length / 1024 / 1024} MB)");
    }
    
    sourceFile.CopyTo("backup.zip", overwrite: true);
}

Burada obyekt yönümlü yanaşma daha təbii görünür: faylla obyekt kimi işləyib onun xüsusiyyətlərindən istifadə edirik.

Nümunə 3: Qovluğun məzmununun analizi

Statik yanaşma:

string folderPath = @"C:\Documents";

if (Directory.Exists(folderPath))
{
    string[] files = Directory.GetFiles(folderPath);
    string[] subdirs = Directory.GetDirectories(folderPath);
    
    Console.WriteLine($"Fayllar: {files.Length}, Qovluqlar: {subdirs.Length}");
    
    // Ölçüləri almaq üçün yenə də FileInfo obyektləri lazımdır
    long totalSize = 0;
    foreach (string filePath in files)
    {
        var fileInfo = new FileInfo(filePath);
        totalSize += fileInfo.Length;
    }
    
    Console.WriteLine($"Ümumi ölçü: {totalSize / 1024} KB");
}

İnstant yanaşma:

var folder = new DirectoryInfo(@"C:\Documents");

if (folder.Exists)
{
    var files = folder.GetFiles();
    var subdirs = folder.GetDirectories();
    
    Console.WriteLine($"Fayllar: {files.Length}, Qovluqlar: {subdirs.Length}");
    
    long totalSize = files.Sum(f => f.Length); // Məlumat artıq mövcuddur!
    Console.WriteLine($"Ümumi ölçü: {totalSize / 1024} KB");
}

Burada DirectoryInfo üstün çıxır: FileInfo[] kolleksiyaları artıq metadata ehtiva edir.

4. Yanaşmanı seçmək üçün kriteriyalar

Statik siniflərdən istifadə edin (File/Directory), when:

  • Əməliyyat sadə və bir dəfəlikdir. Faylın mövcudluğunu tez yoxlamaq, onu silmək və ya məzmununu oxumaq lazımdırsa — statik metodlar idealdır.
// Konfiqurasiyanı sadə oxumaq
if (File.Exists("config.json"))
{
    string config = File.ReadAllText("config.json");
    // konfiqurasiyanın emalı...
}
  • Faylın xüsusiyyətləri barədə məlumat lazım deyil. Ölçü, tarixlər və ya atributlar əhəmiyyətli deyilsə — statik çağırışlar daha qısa və uyğun olur.
  • Məntiq yollarla (strings) işləyir, fayllarla obyekt kimi deyil. Məntiq string yollarla işləyirsə, statik metodlar daha təbii görünür.

İnstant siniflərdən istifadə edin (FileInfo/DirectoryInfo), when:

  • Bir fayl/qovluq barədə çoxlu məlumat lazımdır. Length, CreationTime, Attributes kimi xüsusiyyətlər birbaşa mövcuddur.
var logFile = new FileInfo("application.log");
Console.WriteLine($"Log ölçüsü: {logFile.Length / 1024} KB");
Console.WriteLine($"Son dəyişiklik: {logFile.LastWriteTime}");
Console.WriteLine($"Yerləşmə: {logFile.Directory.FullName}");
  • Bir faylla çoxlu əməliyyatlar edirsiniz. Obyekti bir dəfə yaradıb müxtəlif əməliyyatlarda istifadə etmək rahatdır.
var document = new FileInfo("report.docx");
if (document.Exists)
{
    var backup = document.CopyTo($"report_backup_{DateTime.Now:yyyyMMdd}.docx");
    document.MoveTo("archive/report.docx");
    Console.WriteLine($"Sənəd arxivləndi, nüsxə yaradıldı {backup.Name}");
}
  • Faylların kolleksiyaları ilə işləyirsiniz. GetFiles() və GetDirectories() tam məlumatlı obyektlər qaytarır.
  • Obyekt yönümlü arxitektura lazımdır. Faylları/qovluqları obyekt kimi ötürmək, saxlamaq və LINQ ilə işləmək asandır.

5. Performans və kəşfiyyat xüsusiyyətləri

İnstant siniflərdə kəşfiyyat

FileInfo/DirectoryInfo-nin əsas xüsusiyyətlərindən biri metadata-nın kəşf edilməsi (caching). İlk dəfə bir xüsusiyyətə müraciət ediləndə (məsələn, Length və ya CreationTime) .NET sistem çağırışı edir, bütün məlumatları yükləyir və onları obyekt daxilində cache-ləyir.

var file = new FileInfo("document.txt");

// İlk müraciət - bütün metadata üçün sistem çağırışı
long size = file.Length;

// Sonrakı müraciətlər cache-dən istifadə edir - çox sürətli
DateTime created = file.CreationTime;
DateTime modified = file.LastWriteTime;
bool readOnly = file.IsReadOnly;

Eyni faylın bir neçə xüsusiyyətinə ehtiyac varsa, obyekt yönümlü yanaşma daha effektivdir: bir neçə sistem çağırışı yerinə bir çağırış.

Kəşfiyyatın köhnəlməsi problemi

Ayrıca, məlumat proqramınızdan kənarda dəyişərsə, cache köhnələ bilər. Bunun üçün Refresh()-dən istifadə edin:

var file = new FileInfo("data.txt");
Console.WriteLine($"Ölçü: {file.Length}"); // Məsələn, 1000 bayt

// Bu vaxt başqa proqram faylı dəyişdirir...

Console.WriteLine($"Ölçü: {file.Length}"); // Hələ də cache-də 1000 bayt!

// Məcburi yeniləmə
file.Refresh();
Console.WriteLine($"Ölçü: {file.Length}"); // İndi aktual ölçü

Statik çağırışlar həmişə birbaşa fayl sisteminə müraciət etdiyindən bu problem onlarda yoxdur.

Kütləvi əməliyyatlar

Böyük fayl dəstlərində API seçimi performansa təsir edir:

// Statik yanaşma — çox sayda sistem çağırışı
string[] files = Directory.GetFiles(@"C:\Photos");
foreach (string filePath in files)
{
    var info = new FileInfo(filePath); // Hər fayl üçün sistem çağırışı
    if (info.Length > 10 * 1024 * 1024) // 10 MB-dan böyük
    {
        Console.WriteLine($"Böyük foto: {info.Name}");
    }
}

// İnstant yanaşma — qovluq üçün bir sistem çağırışı
var photosDir = new DirectoryInfo(@"C:\Photos");
foreach (var file in photosDir.GetFiles()) // Məlumatlar birbaşa yüklənir
{
    if (file.Length > 10 * 1024 * 1024)
    {
        Console.WriteLine($"Böyük foto: {file.Name}");
    }
}

6. API və imkanlarda fərqlər

İnstant siniflərin unikal imkanları

var file = new FileInfo(@"C:\Projects\MyApp\source\Program.cs");

// Qovluq iyerarxiyası üzrə naviqasiya
DirectoryInfo projectDir = file.Directory.Parent; // MyApp
DirectoryInfo sourceDir = file.Directory; // source

// Fayl haqqında detallı məlumat
Console.WriteLine($"Extension: {file.Extension}");
Console.WriteLine($"Yalnız oxumaq: {file.IsReadOnly}");
Console.WriteLine($"Attributes: {file.Attributes}");

// Qovluğu obyekt kimi istifadə etmək
var dir = new DirectoryInfo(@"C:\Projects");
DirectoryInfo parent = dir.Parent; // C:\
DirectoryInfo root = dir.Root;     // C:\

Statik siniflərin unikal imkanları

// Mətni bir sətrdə oxumaq və yazmaq
string content = File.ReadAllText("config.txt");
File.WriteAllText("output.txt", "Hello World");

// Sətirlərlə işləmək
string[] lines = File.ReadAllLines("data.txt");
File.WriteAllLines("output.txt", new[] { "Line 1", "Line 2" });

// Fayla mətn əlavə etmək
File.AppendAllText("log.txt", $"{DateTime.Now}: Application started\n");

// Baytlarla işləmək
byte[] data = File.ReadAllBytes("image.jpg");
File.WriteAllBytes("copy.jpg", data);

7. Praktik tövsiyələr

Ssenari 1: Ehtiyat nüsxə utiliti

Ölçü və tarix yoxlaması ilə kopyalama üçün instant siniflər rahatdır:

public void BackupDirectory(string sourcePath, string backupPath)
{
    var sourceDir = new DirectoryInfo(sourcePath);
    var backupDir = new DirectoryInfo(backupPath);
    
    if (!backupDir.Exists)
        backupDir.Create();
    
    foreach (var file in sourceDir.GetFiles())
    {
        var backupFile = new FileInfo(Path.Combine(backupPath, file.Name));
        
        // Yalnız fayl daha yeni olduqda və ya mövcud deyilsə kopyalayırıq
        if (!backupFile.Exists || file.LastWriteTime > backupFile.LastWriteTime)
        {
            file.CopyTo(backupFile.FullName, overwrite: true);
            Console.WriteLine($"Kopyalandı: {file.Name} ({file.Length / 1024} KB)");
        }
    }
}

Ssenari 2: Sadə mətn faylları ilə iş

Sadə məlumatların yüklənməsi/saxlanması üçün statik metodlar kifayətdir:

public void SaveUserPreferences(string username, string theme, bool notifications)
{
    string configPath = "user.config";
    string[] settings = {
        $"Username={username}",
        $"Theme={theme}",
        $"Notifications={notifications}"
    };
    
    File.WriteAllLines(configPath, settings);
}

public Dictionary<string, string> LoadUserPreferences()
{
    string configPath = "user.config";
    var preferences = new Dictionary<string, string>();
    
    if (!File.Exists(configPath))
    {
        // Defolt parametrləri yaradırıq
        SaveUserPreferences("User", "Light", true);
        return LoadUserPreferences();
    }
    
    string[] lines = File.ReadAllLines(configPath);
    foreach (string line in lines)
    {
        if (line.Contains('='))
        {
            string[] parts = line.Split('=', 2);
            preferences[parts[0]] = parts[1];
        }
    }
    
    return preferences;
}

Ssenari 3: Fayl sistemi analiz

Disk istifadəsi hesabatları üçün instant siniflər ideal seçimdir:

public void AnalyzeDiskUsage(string path)
{
    var directory = new DirectoryInfo(path);
    var report = new Dictionary<string, long>();
    
    foreach (var file in directory.GetFiles("*", SearchOption.AllDirectories))
    {
        string extension = file.Extension.ToLower();
        if (string.IsNullOrEmpty(extension))
            extension = "(bez rasshireniya)";
            
        if (!report.ContainsKey(extension))
            report[extension] = 0;
            
        report[extension] += file.Length;
    }
    
    var sortedReport = report.OrderByDescending(kvp => kvp.Value);
    foreach (var item in sortedReport.Take(10))
    {
        Console.WriteLine($"{item.Key}: {item.Value / 1024 / 1024} MB");
    }
}

8. Tipik səhvlər və tələlər

Səhv: Lazımsız qarışdırma

Bəzən statik metodlarla başlayıb sonra metadata üçün obyekt yaradılır — nəticədə lazımsız duplikasiya yaranır:

// Səmərəsiz - fayl sisteminə iki dəfə müraciət
if (File.Exists("document.txt"))
{
    var fileInfo = new FileInfo("document.txt"); // Mövcudluq yoxlamasının duplikasiyası
    Console.WriteLine($"Ölçü: {fileInfo.Length}");
}

// Daha yaxşısı, birbaşa obyekt yönümlü yanaşma
var fileInfo = new FileInfo("document.txt");
if (fileInfo.Exists)
{
    Console.WriteLine($"Ölçü: {fileInfo.Length}");
}

Səhv: Köhnəlmiş cache-i nəzərə almamaq

Uzun müddətli iş zamanı fayllar xaricdən dəyişilə bilər — cache-i Refresh() ilə yeniləyin:

var logFile = new FileInfo("application.log");

while (true)
{
    logFile.Refresh(); // Fayl haqqında məlumatı yeniləyirik
    
    if (logFile.Length > 100 * 1024 * 1024) // 100 MB
    {
        // Log-u arxivləşdiririk
        logFile.MoveTo($"logs/archived_{DateTime.Now:yyyyMMdd_HHmmss}.log");
        break;
    }
    
    Thread.Sleep(60000); // Hər dəqiqə yoxlayırıq
}

Səhv: Kütləvi əməliyyatlar üçün yanlış seçim

Minlərlə fayl üzərində işləyərkən API seçimi performansa ciddi təsir edir:

// Yavaş - çox sayda kiçik fayl sistemi çağırışı
string[] allFiles = Directory.GetFiles(@"C:\BigFolder", "*", SearchOption.AllDirectories);
var largeFiles = allFiles.Where(path => new FileInfo(path).Length > 1024 * 1024).ToList();

// Daha sürətli - mövcud məlumatlardan istifadə edirik
var folder = new DirectoryInfo(@"C:\BigFolder");
var largeFiles = folder.GetFiles("*", SearchOption.AllDirectories)
                      .Where(file => file.Length > 1024 * 1024)
                      .ToList();
2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
Qovluğun məzmununun analizi
Qovluğun məzmununun analizi
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION