Read a txt file, insert into an array and display in a textbox in C#

Asked

Viewed 263 times

-1

I need to open the txt file with the data already inserted with three columns and separated by ';' and after opening the file I insert it into an Array with List, save the data and need the values inserted inside the file to appear in a textbox. However I need to take an exact and/or close value of the value typed in a previous textbox and these value is in column 1 of the file and when the value is selected I need it to show me the value of column 3 of the same row of the selected value.

I already managed to open the file, throw the data of the file in the Array, but it does not return me the values of column 3 that I need. I finished this code, but it shows me the last line of the file with the three columns. I believe the error is from the foreach, because it reads only the last line. And I don’t know how to do an If (if it’s the If I need to do) so that it reads the value of the previous textbox and read the next value in the file and select column 3. I have tried to make if or insert the iterations inside the code in the foreach, but no success.

Note: I have read several websites/forums about this, but none was according to what I need.

In the txt file is thus the data:

inserir a descrição da imagem aqui

For example: the value typed in the previous textbox gave 173.10 so the next value in the txt file is 172.0585213 so I want it to select this value and show the value of the third column (16) in the following textbox.

I’ll enter my code below:

    List<string> lista = new List<string>(); 

        string dados = (@"C: .... .txt"); // // caminho do documento em C: com a extensão em .txt
        string linha; // //declara uma variável para receber linha por linha do doc.

        using (StreamReader Str = new StreamReader(dados)) // a leitura do arquivo.
        {
            while ((linha = Str.ReadLine()) != null) //cria um loop para adicionar linha por linha do doc até sua ultima linha.
            {
                lista.Add(linha);
            }

           for (int i = 0; i < dados.Length; i++) // Percorro o array e para cada linha.
            {
                foreach (var item in lista)
                {

                    var coluna1 = Convert.ToInt32(item[0]);
                    var coluna3 = Convert.ToInt32(item[2]);

                    var valores = File.ReadAllLines(dados).Select(linha => linha.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
                        .Where(Split => Split.Length >= 3).Select(Split => Split[2]).ToList();
                    Txtbox2.Text = (item).ToString();

                }

            }
  • It’s very confusing... is it Textbox or Listbox/Combobox? It could be a text box and a list box, where the list items are filtered based on the value typed in the text box, would that be?

  • What do you mean Convert.ToInt32(item[0]); read the first character? Why are you reading the file twice????

  • @Kiritonito That’s right, I want it to Filter in the file the value typed in the previous textbox and and and show the value in the next textbox (but it would be the value of the third column as it will filter the value of column 1). I will clarify further in the question.

  • @Leandroangelo I wouldn’t have to insert the items (columns) of my txt file to make it filter? Saying that column 1 is [0] and column 3 is [2].

1 answer

0


I tested via console application, but it is fully possible to use this class in winforms.

class Arquivo_Dados
{
    private List<string[]> _data;

    private List<double> _fmtData;

    // Chamar apenas uma vez, não tem pq ler o arquivo várias vezes.
    public void Load() {
        _data = File.ReadAllLines("H:/arquivo.txt").Select(
            // l = 43,01463032;    46,8918;      9,5;
            // output = ["43,01463032", "46,8918", "9,5"]
            l => l.Split(';').Select(v => v.Trim()).ToArray()
        ).ToList();

        _fmtData = _data.Select(l => double.Parse(l[0])).ToList();
    }

    public (int lineIndex, string valor)? SearchData(string input) {
        if (!double.TryParse(input, out double di)) {
            return null;
        }

        // Se o elemento for menor ou igual que o primeiro,
        // retornamos ele.
        if (di <= _fmtData[0]) {
            return (0, _data[0][2]);
        }

        // Se o elemento for maior ou igual que o último,
        // retornamos ele.
        if (di >= _fmtData[^1]) {
            return (_fmtData.Count - 1, _data[^1][2]);
        }

        // Retornamos o que tiver a menor diferença.
        var difs = _fmtData.Select(savedData => Math.Abs(savedData - di)).ToList();
        var idx = difs.IndexOf(difs.Min());

        return (idx, _data[idx][2]);
    }

    // Retorna somente a coluna 3.
    public string SearchDataValueOnly(string input) {
        if (!double.TryParse(input, out double di)) {
            return "";
        }

        // Se o elemento for menor ou igual que o primeiro,
        // retornamos ele.
        if (di <= _fmtData[0]) {
            return _data[0][2];
        }

        // Se o elemento for maior ou igual que o último,
        // retornamos ele.
        if (di >= _fmtData[^1]) {
            return _data[^1][2];
        }

        // Retornamos o que tiver a menor diferença.
        var difs = _fmtData.Select(savedData => Math.Abs(savedData - di)).ToList();
        var idx = difs.IndexOf(difs.Min());

        return _data[idx][2];
    }
}

My txt file:

43,01463032;    46,8918;      9,5;
60,65734978;    67,14495;     1,5;
88,88570093;    90,7425;      13;
113,5855082;    149,5044;     14,5;
141,6293991;    183,29985;    16;
242,3097816;    261,6327;     19;

App:

class Program
{
    static void Main(string[] args) {
        var lk = new Arquivo_Dados();
        lk.Load();
        
        var r = lk.SearchData("512,50");
        Console.WriteLine("Index: {0}; Valor: {1}", r?.lineIndex, r?.valor);
        
        var r = lk.SearchData("10,688");
        Console.WriteLine("Index: {0}; Valor: {1}", r?.lineIndex, r?.valor);
        
        var r = lk.SearchData("64,355");
        Console.WriteLine("Index: {0}; Valor: {1}", r?.lineIndex, r?.valor);
        
        var r = lk.SearchData("117,92");
        Console.WriteLine("Index: {0}; Valor: {1}", r?.lineIndex, r?.valor);
    }
}

Upshot:

Index: 5; Valor: 19
Index: 0; Valor: 9,5
Index: 1; Valor: 1,5
Index: 3; Valor: 14,5

Observing

As you will filter data in response to an event of a textbox, that is, event coming from the user, it would be good for you to implement some system debauch in the textbox where the user type, preventing the pc to explode.

Another point is that I put tuple as nullable, in case the user sends an invalid value, although there in my example I am not doing the check, it would be good for you to do.

Edit - Combobox

I added these two functions in the data file class:

public string[] ListarColuna3() {
    return _data.Select(d => d[2]).ToArray();
}

public string[] BuscarPelaColuna3(int index) {
    // return _data.Where(d => d[2] == input).FirstOrDefault();
    return _data[index];
}

In my form:

public Form1() {
    InitializeComponent();

    _arqDados = new Arquivo_Dados();
    _arqDados.Load();

    comboBox1.Items.AddRange(_arqDados.ListarColuna3());
}

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) {
    var linha = _arqDados.BuscarPelaColuna3(comboBox1.SelectedIndex);

    textBox1.Text = linha[0];
    textBox2.Text = linha[1];
}

That one comboBox1_SelectedIndexChanged is a Combobox event. You can add it from the window properties or via code: comboBox1.SelectedIndexChanged += comboBox1_SelectedIndexChanged;. As the name suggests, it will be called when the selected index is changed.

Upshot:

inserir a descrição da imagem aqui

  • Thank you so much for the help you have given so far. I have done exactly your code by changing just some names. But at the moment of reading the class data and showing in my textbox, it appears the row that is the value and the value of column 3 (I just want to show the value of column 3, without index. var Arq_Dados = new Arquivo_Dados();&#xA;Arq_Dados.Load();&#xA;&#xA;var num = Arq_Dados.SearchDados(txtFcmin.Text);&#xA;txtDc.Text = (num?.lineIndex, num?.valor).ToString(); But if I take num?. lineIndex it gives error, I believe I have to change something in the class, correct??

  • @Cristina You could do it like this: txtDc.Text = num?.valor;. But since you won’t need the index, I added the function in the answer that returns only column 3. You don’t need to use the ToString() pq the returned column is already a string.

  • Thank you so much for your help and the tips, it worked here! Gratitude!!

  • I am also optimizing the form with the data, because it is a calculation form. And I changed it to instead of showing in the textbox show in a combobox, it worked. And I wonder if I can select a value of the combobox (column 3) and it returns me the values of column 1 or 2 in the textbox, (do the reverse now). I tested, but he ends up doubling the values and I stuck in this logic I do not know if it is possible an if, It is. Or would I have to leave in the same texbox the result and program the combobox? Is that I would like to leave the two applications in one location only.

  • In the combobox is only the value of column 3, right? No Arquivo_Dados, you create a function that accepts a single parameter (string type), and puts there: return _data.Where(d => d[2] == valorColuna3).FirstOrDefault();. It will return the entire array of the line (or null if not found). With the result, just set the text of the textbox to each index of the result.

  • @Cristina added an example in the reply.

  • 1

    That’s exactly what I wanted, thank you very much!!

  • I was left with a question in the matter of taking only the larger values equal to the value of column 1. It would be the same code? if (di >= _fmtData[^1]) { return _data[^1][2];} But I would have to change that, correct? var difs = _fmtData.Select(savedData => Math.Abs(savedData - di)).ToList();&#xA; var idx = difs.IndexOf(difs.Min()): I’m trying to understand to change this Min(). Correct?

  • Do you want to return only if the value of column 1 is greater than or equal to the input? If it is, I will leave a print with a code, changing the function SearchData. https://ibb.co/6BZxdzd. di >= fd.

  • That, I want to return only the larger values equal to input (textbox). This code I enter after the if, correct? It is giving error, follow the print: (https://ibb.co/0ZGBVL5) And the error: cannot convert from 'System.Collections.Generic.List<double>' to 'int' What could I be doing wrong??

  • It follows: https://ibb.co/kJ16059 . There, he draws the smallest difference between the values that are greater than the input.

  • Thank you so much, you helped me so much !!!

  • In my combobox when I select the value (column 3) for it to search again in the file, it does not return me the value of (column 2) of the same row, it returns the next value of the row. Is this happening on account of, I changed to return only the largest or equal? But it was for this happening.

  • Could help me with the error above that I commented ??

  • In fact, it wasn’t supposed to happen... I don’t have access to the code, there’s no way I know what happens.

Show 10 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.