Вопрос по чтению и сравнению файлов - PullRequest
1 голос
/ 28 мая 2020

Во-первых, у меня есть файл, который выглядит так:

//Manager Ids

ManagerName: FirstName_LastName
ManagerLoginId: 12345

и текстовое поле с кодом 5 di git (например, 12345), который вводится. Когда нажата клавиша Enter, ей назначается строка с именем: "EnteredEmployeeId". Затем мне нужно выполнить поиск во всем файле выше для "EnteredEmployeeId", и если он совпадает, он откроет другую страницу, если не найдет этот номер затем отобразит сообщение (которое сообщает вам, что идентификатор сотрудника не найден).

Итак, по сути, я пытаюсь открыть файл, искать весь документ для идентификатора, затем возвращать true или false, чтобы он тоже отображал ошибку или откройте новую страницу и сбросьте EnteredEmployeeId на ничего.

Мой код на данный момент:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Rent_a_Car
{
    public partial class Employee_Login_Page : Form
    {
        public Employee_Login_Page()
        {
            InitializeComponent();
        }
        string ManagersPath = @"C:\Users\Name\Visual Studios Project Custom Files\Rent A Car Employee Id's\Managers\Manager_Ids.txt"; //Path To Manager Logins
        string EnteredEmployeeId;


        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void Employee_Id_TextBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) &&           //Checks Characters entered are Numbers Only and allows them
                (e.KeyChar != '0'))
            {
                e.Handled = true;
            }
            else if (e.KeyChar == (char)13)                                         //Checks if The "Enter" Key is pressed
            {
                EnteredEmployeeId = Employee_Id_TextBox.Text;                         //Assigns EnteredEmployeeId To the Entered Numbes In Text Box          

                bool result = ***IsNumberInFile***(EnteredEmployeeId, "ManagerLoginId:", ManagersPath);
                if (result)
                {
                             //open new window
                }
                else
                {
                    MessageBox.Show("User Not Found");
                }
            }
        }
    }
}

Ответы [ 3 ]

0 голосов
/ 28 мая 2020

Короткий ответ

У вас есть вопрос о том, как читать ваш файл?

private bool ManagerExists(int managerId)
{
    return this.ReadManagers().Where(manager => manager.Id == managerId).Any();
}

private IEnumerable<Manager> ReadManagers()
{
    using (var reader = System.IO.File.OpenText(managersFileName))
    {
        while (!reader.EndOfStream)
        {
            string lineManagerName = reader.ReadLine();
            string lineMangerId = reader.ReadLine();

            string managerName = ExtractValue(lineManagerName);
            int managerId = Int32.Parse(ExtractValue(lineManagerId));

            yield return new Manager
            {
                Id = managerId,
                Name = managerName,
            }
    }
}

private string ExtractValue(string text)
{
    // the value of the read text starts after the space:
    const char separator = ' ';
    int indexSeparator = text.IndexOf(separator);
    return text.SubString(indexSeparator + 1);
}

Длинный ответ

Я вижу несколько проблем в вашем дизайне.

Самое главное, что вы переплетаете работу вашего менеджера с вашей формой. Вы должны разделить свои проблемы .

Очевидно, у вас есть понятие последовательности менеджеров, у каждого менеджера есть имя (имя, фамилия) и идентификатор менеджера, а в будущем возможно другое properties.

Эта последовательность постоянна: она где-то сохраняется, и если вы загрузите ее снова, у вас будет та же последовательность менеджеров.

В этой версии вы хотите видеть, если Менеджер с данным ManagerId существует. Может быть, в будущем вам может понадобиться больше функций, например, получение информации о диспетчере с определенным идентификатором, или получение всех диспетчеров, или go сумасшедший: добавление / удаление / изменение диспетчеров!

Вы видите в этом описании Я вообще не упомянул твои формы. Поскольку я отделил его от ваших форм, вы можете использовать его в других формах или даже в классе, который не имеет ничего общего с формой, например, вы можете использовать его в модульном тесте.

Я описал, что Мне нужен был такой генерал из, что в будущем, возможно, даже поменяю его. Пользователи моей коллекции постоянных менеджеров даже не заметят этого: я могу поместить его в файл JSON или XML; Я могу сохранить данные в словаре, базе данных или, возможно, даже получить их из inte rnet.

Все, что нужно знать пользователям, это то, что они должны создать экземпляр класса, используя некоторые параметры, и bin go, вы можете получить менеджеров.

Вы также даете пользователям свобода решать, как данные должны быть сохранены: если они хотят сохранить их в файле JSON, изменения в вашем классе формы будут минимальными.

Объект, который хранит последовательности объектов, довольно часто называется репозиторием.

Давайте создадим несколько классов:

interface IManager
{
    public int Id {get;}
    public string Name {get; set;}
}

interface IManagerRepository
{
    bool ManagerExists(int managerId);

    // possible future extensions: Add / Retrieve / Update / Delete (CRUD)
    IManager Add(IManager manager);
    IManager Find(int managerId);
    void Update(IManager manager);
    void Delete(int ManagerId);
}

class Manager : IManager
{
    public Id {get; set;}
    public string Name {get; set;}
}

class ManagerFileRepository : IManagerRepository,
{
    public ManagerFileRepository(string fileName)
    {
         // TODO implement
    }

    // TODO: implement.
}

ManagerFileRepository сохраняет менеджеров в файл. Он скрывает от внешнего мира внутреннюю структуру файла. Это может быть ваш формат файла, это может быть CSV-файл или JSON / XML.

Я также разделил интерфейс, поэтому, если вы позже решите сохранить данные в другом месте, например в Словаре (для модульных тестов) или в базе данных пользователи вашего класса Repository не увидят разницы.

Давайте сначала посмотрим, можете ли вы использовать этот класс.

class MyForm : Form
{
    const string managerFileName = ...
    private IManagerRepository ManagerRepository {get;}

    public MyForm()
    {
        InitializeComponent();

        this.ManagerRepository = new ManagerFileRepository(managerFileName);
    }

    public bool ManagerExists(int managerId)
    {
        return this.ManagerRepository.ManagerExists(managerId);
    }

Теперь давайте обработаем ваш keyPress:

private void Employee_Id_TextBox_KeyPress(object sender, KeyPressEventArgs e)
{
    TextBox textBox = (TextBox)sender;
    ... // code about numbers and enter key

    int enteredManagerId = Int32.Parse(textBox.Text);
    bool managerExists = this.ManagerExists(enteredManagerId);

    if (managerExists) { ... }

}

Этот код, кажется, делает то, что вы хотите, простым способом. Выглядит прозрачным. ManagerRepository можно тестировать, использовать повторно, его легко расширить или изменить, потому что пользователи этого не заметят. Так что класс выглядит хорошо. Давайте реализуем

Implement ManagerFileRepository

Есть несколько способов реализовать чтение файла:

(1) Прочитать все во время построения
и сохранить прочитанные данные в памяти . Если вы добавите менеджеров, они не сохранятся, пока вы этого не скажете. Преимущества: быстро после первого запуска. Вы можете внести изменения, а затем решить все равно не сохранять их, так что это похоже на редактирование любого другого файла. Недостаток: если ваша программа выйдет из строя, вы потеряете свои изменения.

(2) Читайте файл каждый раз, когда вам нужна информация
Преимущество: данные всегда актуальны, даже если другие редактировали файл пока работает ваша программа. Если вы измените коллекцию менеджера, она будет немедленно сохранена, чтобы ее могли использовать другие.

Выбор решения зависит от размера файла и важности того, чтобы данные никогда не терялись. Если ваш файл содержит миллионы записей, возможно, было не очень разумно сохранять данные в файле. Рассмотрите возможность сохранения SQLite в небольшой, довольно быстрой базе данных.

class ManagerFileRepository : IManagerRepository, IEnumerable<IManager>
{
    private readonly IDictionary<int, IManager> managers;

    public ManagerFileRepository(string FileName)
    {
        this.managers = ReadManagers(fileName);
    }

    public bool ManagerExists(int managerId)
    {
        return this.Managers.HasKey(managerId);
    }

    private static IEnumerable<IManager> ReadManagers(string fileName)
    {
         // See the short answer above
    }
}

Возможности для улучшения

Если вы будете использовать репозиторий менеджера для других целей, подумайте о том, чтобы позволить репозиторию реализовать ICollection<IManager> и IReadOnlyCollection<IManager>. Это довольно просто:

public IEnumerable<IManager> GetEnumerator()
{
    return this.managers.Values.GetEnumerator();
}
public void Add(IManager manager)
{
    this.managers.Add(manager.Id, manager);
}
// etc.

Если вы добавляете функции для изменения коллекции менеджеров, вам также понадобится метод сохранения:

public void Save()
{
    using (var writer = File.CreateText(FullFileName))
    {
        const string namePrefix = "ManagerName: ";
        const string idPrefix = "ManagerLoginId: ";
        foreach (var manager in managers.Values)
        {
            string managerLine = namePrefix + manager.Name;
            writer.WriteLine(managerLine);

            string idLine = idPrefix + manager.Id.ToString();
            writer.WriteLine(idLine);
        }
    }
}

Другой метод улучшения: ваша файловая структура . Рассмотрите возможность использования более стандартной файловой структуры: CSV, JSON, XML. Существует множество пакетов NUGET (CSVHelper, NewtonSoft. Json), которые делают чтение и запись менеджеров намного более надежными. вы можете повторно использовать репозиторий менеджеров, особенно если вам нужна функциональность для добавления / извлечения / обновления / удаления менеджеров.

Из-за разделения намного проще проводить модульное тестирование ваших функций. И будущие изменения не будут мешать пользователям репозитория, потому что они не заметят, что данные изменились.

0 голосов
/ 29 мая 2020

Если ваш Manager_Ids.txt имеет следующий формат, вы можете использовать метод File.ReadLine() для обхода текста и запроса его.

ManagerName: FirstName_LastName1
ManagerLoginId: 12345
ManagerName: FirstName_LastName2
ManagerLoginId: 23456
...

Вот демонстрация, которая просматривает .txt.

string ManagersPath = @"D:\Manager_Ids.txt";
string EnteredEmployeeId;

private void textBox_id_KeyDown(object sender, KeyEventArgs e)
{
    int counter = 0;
    bool exist = false;
    string line;
    string str = "";

    if (e.KeyCode == Keys.Enter)
    {
        EnteredEmployeeId = textBox_id.Text;

        System.IO.StreamReader file =
            new System.IO.StreamReader(ManagersPath);
        while ((line = file.ReadLine()) != null)
        {
            str += line + "|";

            if (counter % 2 != 0)
            {
                if (str.Split('|')[1].Split(':')[1].Trim() == EnteredEmployeeId)
                {
                    str = str.Replace("|", "\n");
                    MessageBox.Show(str);
                    exist = true;
                    break;
                }
                str = "";
            }
            counter++;
        }

        if (!exist)
        {
            MessageBox.Show("No such id");
        }

        file.Close();
    }
}

Кроме того, я рекомендую использовать «xml», «json» или другие форматы для сериализации данных. О хранении данных в «xml» вы можете обратиться к следующей простой демонстрации.

<?xml version="1.0"?>  
<Managers>  
  <Manager>  
    <ManagerName>FirstName_LastName1</ManagerName>  
    <ManagerLoginId>12345</ManagerLoginId>  
  </Manager>  
  <Manager>  
    <ManagerName>FirstName_LastName2</ManagerName>  
    <ManagerLoginId>23456</ManagerLoginId>  
  </Manager>  
</Managers> 

А затем использовать LINQ to XML для запроса идентификатора.

string ManagersPath = @"D:\Manager_Ids.xml";
string EnteredEmployeeId;

private void textBox_id_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Enter)
    {
        EnteredEmployeeId = textBox_id.Text;

        XElement root = XElement.Load(ManagersPath);
        IEnumerable<XElement> manager =
            from el in root.Elements("Manager")
            where (string)el.Element("ManagerLoginId") == EnteredEmployeeId
            select el;
        if(manager.Count() == 0)
        {
            MessageBox.Show("No such id");
        }
        foreach (XElement el in manager)
            MessageBox.Show("ManagerName: " + (string)el.Element("ManagerName") + "\n"
                + "ManagerLoginId: " + (string)el.Element("ManagerLoginId"));
    }
}
0 голосов
/ 28 мая 2020

Эта функция прочитает весь файл и найдет вставленный код. Он будет работать со строками (так как это вывод из вашего текстового поля) и вернет только истину или ложь (сотрудник есть или нет в файле), а не его имя, фамилию и т. Д. c.

static bool IsNumberInFile(string numberAsString, string LineName, string FileName)
    {
        var lines = File.ReadAllLines(FileName);

        foreach(var line in lines)
        {
            var trimmedLine = line.Replace(" ", ""); //To remove all spaces in file. Not expecting any spaces in the middle of number
            if (!string.IsNullOrEmpty(trimmedLine) && trimmedLine.Split(':')[0].Equals(LineName) && trimmedLine.Split(':')[1].Equals(numberAsString))
                return true;

        }
        return false;
    } 

// Пример использования

    String ManagersPath = @"C:\Users\Name\Visual Studios Project Custom Files\Employee Id's\Managers\Manager_Ids.txt"; //Path To Manager Logins

String EnteredEmployeeId;

private void textBox1_TextChanged(object sender, EventArgs e)
{

}

private void Employee_Id_TextBox_KeyPress(object sender, KeyPressEventArgs e)
{
    if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) &&           //Checks Characters entered are Numbers Only and allows them
        (e.KeyChar != '0'))
            {
                e.Handled = true;
            }
    else if (e.KeyChar == (char)13)                                         //Checks if The "Enter" Key is pressed
    {
        EnteredEmployeeId = Employee_Id_TextBox.Text;                         //Assigns EnteredEmployeeId To the Entered Numbes In Text Box           


        bool result = IsNumberInFile(EnteredEmployeeId, "ManagerLoginId" , ManagersPath) 
        if(result)
           //User is in file
        else
          //User is not in file
    }
}

}

...