Теория
Всичко в променливите живее само докато програмата работи. За да запазим данни трайно (резултати, настройки, логове), ги записваме във файлове. В C# за това отговаря именното пространство System.IO с класовете File и Directory.
Класът File предлага "всичко-в-един-ред" методи: WriteAllText записва (и презаписва!) файл, AppendAllText добавя в края, ReadAllText чете целия файл като един низ, а ReadAllLines — като масив от редове, което е удобно за обработка ред по ред.
Пътищата биват относителни ("data.txt" — търси се в папката на програмата) и абсолютни (@"C:\MyFolder\data.txt"). Знакът @ пред низа го прави дословен (verbatim) — обратните наклонени черти не се тълкуват като специални символи и пътят се пише естествено.
Файловите операции са "опасни": файлът може да не съществува, да е заключен, да нямаме права. Затова винаги проверяваме с File.Exists() преди четене, а в по-сериозен код ограждаме операциите с try-catch.
За работа ред по ред има удобна двойка: File.WriteAllLines(path, масив) записва всеки елемент на нов ред, а File.ReadAllLines(path) връща string[] — и оттам нататък важи всичко за масивите от Модул 4: обхождане, парсване, броене. Това е най-естественият формат за прости данни.
Пътищата е най-добре да се сглобяват с Path.Combine("папка", "файл.txt") — той сам слага правилните наклонени черти. А програмата по подразбиране работи в своята изпълнима папка (bin/Debug…), не в папката на проекта — затова "изчезналите" файлове обикновено са просто там.
Златни правила
Освобождаване на ресурси
Когато четете или записвате във файл, файлът се "заключва" от вашата програма. Методите на File (ReadAllText и др.) сами отварят и затварят файла — затова са най-безопасният избор за начинаещи.
Пътища до файлове
Правете разлика между относителен път (напр. "data.txt" — търси файла в папката на програмата) и абсолютен път (напр. "C:\MyFolder\data.txt"). При пътища с наклонени черти добавяйте @ пред стринга (напр. @"C:\Folder\file.txt"), за да избегнете грешки.
Проверка преди действие
Винаги проверявайте дали даден файл съществува (File.Exists()), преди да се опитате да го прочетете — иначе рискувате срив на програмата с FileNotFoundException.
WriteAllText трие!
WriteAllText презаписва файла изцяло — старото съдържание изчезва безвъзвратно. Ако искате да добавяте, използвайте AppendAllText.
Бърз справочник
Класове File и Directory
| Метод | Какво прави? | Пример |
|---|---|---|
File.ReadAllText() | Чете целия текст от файл и го връща като един string. | string text = File.ReadAllText("test.txt"); |
File.ReadAllLines() | Чете файла като масив от редове (string[]). | string[] lines = File.ReadAllLines("test.txt"); |
File.WriteAllText() | Създава файл (или го презаписва) и записва текст вътре. | File.WriteAllText("test.txt", "Здравей!"); |
File.AppendAllText() | Добавя текст в края на съществуващ файл, без да трие старото съдържание. | File.AppendAllText("test.txt", " Нов ред."); |
File.Exists() | Проверява дали файлът съществува (връща bool). | bool exists = File.Exists("test.txt"); |
File.Delete() | Изтрива файл (не гърми, ако липсва). | File.Delete("old.txt"); |
Directory.CreateDirectory() | Създава нова папка на посочения път. | Directory.CreateDirectory(@"C:\NewFolder"); |
Directory.Exists() | Проверява дали папката съществува. | if (Directory.Exists("data")) { } |
Код за анализ и пренаписване
Записване, добавяне и четене с проверка
using System;
using System.IO;
namespace ModuleSeven
{
class Program
{
static void Main(string[] args)
{
string filePath = "students_list.txt";
// 1. Записване във файл (презаписва, ако вече съществува)
File.WriteAllText(filePath, "1. Иван Иванов\n");
// 2. Добавяне към съществуващ файл
File.AppendAllText(filePath, "2. Мария Петрова\n");
Console.WriteLine("Данните са записани успешно!");
// 3. Четене от файл с проверка
if (File.Exists(filePath))
{
Console.WriteLine("\n--- Съдържание на файла ---");
string content = File.ReadAllText(filePath);
Console.WriteLine(content);
}
else
{
Console.WriteLine("Грешка: Файлът не е намерен!");
}
}
}
}Какво се случва тук?
-
using System.IO;най-отгоре е задължителен — там живеятFileиDirectory. - Пътят "students_list.txt" е относителен — файлът се създава в папката, от която се изпълнява програмата (обикновено bin/Debug).
-
WriteAllTextсъздава файла, а ако вече съществува — го изтрива и записва наново. Затова е първата операция. -
AppendAllTextдобавя втория ред в края, без да пипа първия.\nв края на низовете осигурява нов ред. - Преди четенето проверяваме с
File.Exists(filePath)— добрата практика, която предпазва отFileNotFoundException. В този пример файлът гарантирано съществува (току-що го създадохме), но навикът е важен. -
ReadAllTextвръща цялото съдържание като един низ, който отпечатваме наведнъж.
Среден успех от файл с ReadAllLines
using System;
using System.IO;
namespace ModuleSevenExtra
{
class Program
{
static void Main(string[] args)
{
string path = "grades.txt";
// Подготвяме тестов файл: всяка оценка на отделен ред
string[] lines = { "5", "6", "4", "5", "6" };
File.WriteAllLines(path, lines);
// Четене с проверка
if (!File.Exists(path))
{
Console.WriteLine("Файлът липсва!");
return; // ранен изход - няма какво да четем
}
string[] read = File.ReadAllLines(path);
double sum = 0;
foreach (string line in read)
{
sum += double.Parse(line);
}
double average = sum / read.Length;
Console.WriteLine($"Прочетени {read.Length} оценки.");
Console.WriteLine($"Среден успех: {average:F2}");
// Записваме резултата в отчет (с добавяне, не презапис)
File.AppendAllText("report.txt",
$"{DateTime.Now}: среден успех {average:F2}\n");
}
}
}Какво се случва тук?
-
WriteAllLinesприема масив и записва всеки елемент на отделен ред — без ръчни\n. ОгледалниятReadAllLinesвръща редовете обратно катоstring[]. - Проверката е обърната:
if (!File.Exists(path)) return;— шаблонът "ранен изход" пази основната логика от влагане в голям if. - Редовете са текст, затова
double.Parse(line)ги превръща в числа — комбинация от уменията от Модул 1 и Модул 4. -
sum / read.Lengthтук е безопасно дробно делене, защотоsumеdouble— стига едната страна да е дробна, резултатът е дробен. - Отчетът се записва с
AppendAllText, не сWriteAllText— всяко пускане добавя нов ред към историята, вместо да изтрие старата. За логове и отчети — винаги Append.
Внимавай! Чести грешки
Грешките, които почти всеки прави в тази тема — виж разликата между грешния и правилния код.
WriteAllText в цикъл
Грешно
foreach (string name in names)
{
File.WriteAllText("list.txt", name + "\n");
}
// във файла остава САМО последното имеПравилно
foreach (string name in names)
{
File.AppendAllText("list.txt", name + "\n");
}
// или още по-добре: File.WriteAllLines("list.txt", names);WriteAllText презаписва файла при всяко извикване — всяка итерация трие предишната. За натрупване ползвайте AppendAllText, а за готова колекция — WriteAllLines с един ред код.
Четене без проверка за съществуване
Грешно
string text = File.ReadAllText("data.txt");
// FileNotFoundException, ако файлът липсваПравилно
if (File.Exists("data.txt"))
{
string text = File.ReadAllText("data.txt");
}
else
{
Console.WriteLine("Файлът не е намерен!");
}Файлът може да липсва по хиляда причини (първо пускане, изтрит, друг компютър). File.Exists струва един ред и спасява програмата от срив.
Обикновен низ за път с обратни черти
Грешно
string path = "C:\new\table.txt";
// \n и \t се тълкуват като нов ред и табулация!Правилно
string path = @"C:\new\table.txt";
// @ = дословен низ, чертите са си чертиВ обикновен низ \n е нов ред, \t — табулация: пътят се чупи тихо и файлът "не се намира". Знакът @ пред кавичките изключва специалните последователности — правило за всички Windows пътища.
Задачи за самостоятелна работа
Опитай първо сам — подсказката е там само ако наистина закъсаш.
Задача 1: Логване на грешки
Напишете програма, която симулира грешка и записва часа на грешката и съобщение в текстов файл errors.log. Използвайте DateTime.Now, за да вземете точния час.
Задача 2: Четене на масив от файл
Създайте текстов файл ръчно с няколко числа на отделни редове. Напишете програма, която използва File.ReadAllLines(), за да ги прочете, преобразува ги в int и отпечатва тяхната сума.
Задача 3: Бележник със задачи
Направете конзолен "бележник": команда "добави <текст>" добавя ред във файла todo.txt, команда "покажи" отпечатва всички задачи с номера, команда "край" спира програмата.
Мини-тест за проверка
Отговори си наум (или на глас!) и чак тогава разкрий отговора.
1. Кой namespace (именно пространство) трябва да включите най-отгоре, за да работите с класовете File и Directory?
2. Каква е разликата между WriteAllText и AppendAllText?
3. Защо е важно да използваме метода File.Exists()?
4. Какво връща File.ReadAllLines() и защо е удобно?
Речник на термините
Виж пълния речник на курсаDirectory."data.txt" се търси в bin/Debug на проекта.@"C:\MyFolder\data.txt" — еднозначен, но непреносим между компютри.@ пред кавичките, в който \ не е специален символ — задължителен за Windows пътища.AppendAllText.File, Directory, Path.Провери знанията
Бърз тест с избор от отговори върху термините на модула — с точки и моментална обратна връзка.
Провери знанията си
7 въпроса върху термините от модула. Показваме определение — ти избираш правилния термин.
Препоръки за този модул
- Докато се учите, работете с относителни пътища — файлът се появява в папката bin/Debug на проекта; намерете го и го отворете, за да видите резултата.
- Тествайте "лошия" сценарий нарочно: изтрийте файла и пуснете програмата — добре написаният код трябва да съобщи грешка, а не да гръмне.
- Помнете
\nза нов ред при записване — иначе всичко се слива на един ред. - Логването във файл (както в Задача 1) е реална практика — всяко сериозно приложение пише лог.