Как работать с файлами
Возможность записывать/читать/изменять данные является одним из основополагающих процессов в работе компьютера. Грубо говоря больше то компьютер ничего и не умеет. Он только все время что-то меняет. А устройства на это реагируют и показывают картинку в случае монитора, издают звук если это колонка и т.д.
Нам будет интересовать работа с постоянной памятью. А именно, с файликами. Для начала мы ограничимся работой с текстовыми файлами.
Постановка задачи
Задача: посчитать сумму введенных пользователем чисел больших заданного числа T.
Если в исходной постановке задачи мы ожидали что пользователь будет последовательно вводить числа. То тут будем ожидать, что пользователь создаст файлик, а в файл пропишет набор чисел в виде строки, и само число T отдельной строкой:
3
1 2 3 4 5 6
То есть для такой записи у нас получается индивидуальная задача вида:
- Среди чисел {1, 2, 3, 4, 5, 6} выбрать те, которые больше 3 и подсчитать их сумму.
Добавляем интерфейс
Не будем мудрить и для начала просто создадим форму с одной кнопкой (я изменил свойство Text кнопки, чтобы на ней была осознанная надпись):
кликнем два раза на кнопку чтобы добавить ей обработчик, нас перекинет в редактор кода:
Добавляем файл в проект
Для тестовых целей создадим файлик, кликнем правой кнопкой на название проекта и выберем Добавить/Создать элемент
в списке найдем текстовый файл и дадим ему название task.txt
файлик должен появится в обозревателе решений:
кликнем на этот файлик два раза, чтобы отредактировать его и добавим в него наши несчастные две строчки:
3
1 2 3 4 5 6
Чтобы файлик был доступен в момент запуска программы, установим ему свойство Копировать в выходной каталог на Всегда копировать
Теперь переключимся на код формы (два раза кликнем на файл Form1.cs, затем нажмем F7). И приступим к редактированию обработчика события клика.
Читаем строчки из файла
Правим код:
запускаем и проверяем:
Выводим данные на форму
Данные читать умеем теперь давайте выведем их на форму. Я добавлю
- два TextBox, один под строку с числами (имя: txtNumbers), второй под число T (имя: txtT);
- два Label для подписей для текстбоксов;
- кнопку c надписью Решить Задачу, на будущее.
теперь давайте сделаем чтобы по нажатию кнопки Считать данные, вместо MessageBox данные записывались в соответствующие поля на форме. Правим обработчик:
запускаем, проверяем:
Ура! Мы свели задаче к лабе 1, только заполнение у нас теперь автоматическое. Давайте теперь добавим возможность выбрать произвольный файл, и вывести его содержимое на форму.
Добавляем диалоговое окно выбора файла
Правим обработчик:
теперь при нажатии на кнопку считать данные будет предложено выбрать файл, директория по умолчанию как правило папка Мои документы. Соответственно, чтобы было что открывать, туда надо файлик с данными для задачи положить.
Папку по умолчанию можно поменять, например, на путь к exe файлу программы:
тогда файлик никуда ложить не придется, он в папке рядом с программой будет уже лежать. Это потому, что мы указали файлу task.txt, свойство Копировать в выходной каталог на Всегда копировать.
Вернемся собственно к задаче.
Добавляю логику
Внедряем класс Logic, как и раньше, класс Form1 не трогаем, а после него добавляем класс Logic:
Добавим обработчик для решения задачи
Переключимся на форму, и кликнем дважды на кнопку Решить задачу чтобы добавить обработчик события клика для этой кнопки.
Конвертируем данные
И так, у нас есть данные на форме, теперь надо их передать нашей функции в логике.
Давайте думать в чем у нас проблема. Мы знаем, что в txtNumbers у нас массив чисел, а в txtT число T, но мы не можем написать наш обработчик как
такой код даже не скомпилируется, ведь txtNumbers.Text и txtT.Text просто возвращает текст. Следовательно, нам надо этот текст преобразовать. Преобразовать значение txtT в число это как раз чихнуть, мы делали это уже много раз, достаточно написать:
а вот как нам разбить значение txtNumbers.Text на набор чисел? Тут нам пригодится метод Split, который позволяет разбить строку с помощью указанного разделителя (в нашем случае это будет пробел)
Преобразуем строку в массив чисел
Есть как минимум два способа сделать, первый весьма громоздкий:
но такая форма записи очень страшная, так что предлагаю альтернативный способ из прекрасного мира лямбда-выражений:
И так, получим такой обработчик:
навешаем обработку ошибок, чтобы не падал на пустых TextBox`ах:
Выводим результат на форму
Для вывода на форму, добавим:
- новое поле типа RichTextBox, установим его свойству (Name) значение txtAnswer
- новую кнопку со свойством Text равным Сохранить в файл.
кликнем два раза на вторую кнопку Решить задачу, чтобы перейти на ее разработчик. И откорректируем его:
Сохраняем результат в файл
Переключимся на форму (кликнув два раза на Form1.cs в обозревателе решений). Затем кликнем два раза на кнопку Сохранить в файл чтобы добавить ей обработчик события. Окажемся в редакторе кода:
записывать в файл не сильно сложнее чем читать из него, достаточно сделать следующее:
так как, бог его знает где этот файл находится, можно либо предложить пользователю указать путь к сохраняемому файлу, абсолютно по аналогии с чтением из файла:
либо можно прям этот файл открыть:
Вот собственно все так просто.
Как преобразовать текст в матрицу (добавлено 21/11/2018)
Чтобы преобразовать текст в число добавьте себе в код куда-нибудь такую функцию, например прям в класс Form
namespace WindowsFormsApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public static int[,] TextToMatrix(string text)
{
var lines = text.Split(new string[] { Environment.NewLine, "\n" }, StringSplitOptions.RemoveEmptyEntries);
var colsCount = lines[0].Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Length;
var rowsCount = lines.Length;
var matrix = new int[rowsCount, colsCount];
for (var i = 0; i < lines.Length; ++i)
{
var elements = lines[i].Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
for (var j = 0; j < elements.Length; ++j)
{
matrix[i, j] = int.Parse(elements[j]);
}
}
return matrix;
}
// ...
}
}
Допустим вы создали файлик в проекте matrix.txt, с содержимым:
1 2 3 4
6 7 8 9
10 12 12 13
14 15 16 17
указали у него свойство “Копировать в выходной каталог” на Всегда копировать
Теперь если вам нужно текст из файла преобразовать в матрицу вы пишите
namespace WindowsFormsApp
{
public partial class Form1 : Form
{
// ...
public static int[,] TextToMatrix(string text)
{
// ...
}
private void button1_Click(object sender, EventArgs e)
{
var text = File.ReadAllText("matrix.txt"); // считали содержимое из файла, сохранили в переменную text
int[,] matrix = TextToMatrix(text); // превратили текст в матрицу
// а дальше работаете с ней как обычно
// например тут я собираю матрицу в строку чтобы отобразить ее в сообщении
string message = "";
for (var i = 0; i < matrix.GetLength(0); ++i)
{
for (var j = 0; j < matrix.GetLength(1); ++j)
{
message += matrix[i, j].ToString() + " ";
}
message += "\n";
}
MessageBox.Show(message);
}
}
}
Но по заданию вам надо будет считать содержимое файла в компоненту, а потом брать текст уже с компоненты, тут в приниципе почти ничего не меняется:
namespace WindowsFormsApp
{
public partial class Form1 : Form
{
// ...
public static int[,] TextToMatrix(string text)
{
// ...
}
private void button1_Click(object sender, EventArgs e)
{
var text = txtMatrix.Text; // считали значение компоненты RichTextBox со свосйством (Name):txtMatrix, сохранили в переменную text
int[,] matrix = TextToMatrix(text); // превратили текст в матрицу
// а дальше работаете все то же самое
string message = "";
for (var i = 0; i < matrix.GetLength(0); ++i)
{
for (var j = 0; j < matrix.GetLength(1); ++j)
{
message += matrix[i, j].ToString() + " ";
}
message += "\n";
}
MessageBox.Show(message);
}
}
}