Resolved Edit and delete lines from a text file

titojd

Well-known member
Joined
Oct 12, 2018
Messages
63
Programming Experience
1-3
Hello Colleagues, I would like to take a doubt!
Personal apologies if this is something I could google, but as you know there are a lot of articles with no opinion on the subject, I spent days reading and got nowhere.
I prefer your opinion...

I recently changed my project, disconnected from the database and saved it in a Text file, as it was just a table and nothing confidential, I solved it this way, because I think that when installing it will make the process easier, but a doubt arose in me on how to edit, and delete just one line from the file following the Contest column which is the first column,

-Question: Is it possible to edit only a certain line in a text file with more than two thousand lines?
Is it possible to delete a particular row tabem?

if it is possible: what would be the best way (Indication),
If not, what would be the best way?
database or what other way?

I have a form like in the image where I can type the numbers and save
arraysarch.png


my Save button and your Save TXT method
C#:
private void salvarTXT()
        {
            if (!string.IsNullOrWhiteSpace(txtConcurso.Text))
            {
                resultUltimat();
                MessageBox.Show("Texto salvo com sucesso!");
            }
            else
            {
                MessageBox.Show("Insira um Resultado para salvar no arquivo Texto!", "Informação", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

        }

 private void resultUltimat()// salva lista de numeros do sorteio (Resultado)  // save list of raffle numbers (Result)
        {
            // salva ultimo sorteio no arquivo texto na primeira linha e vai acrescentando linhas
            // saves the last draw in the text file on the first line and adds lines
            const string nomeArquivo = @"C:\BoaSorte\Banco\Resultados.txt";
            List<string> linhas = File.ReadLines(nomeArquivo).ToList(); // Passo 1

            if (linhas.IndexOf(txtConcurso.Text + "," + ResultTextBox[0].Text + "," + ResultTextBox[1].Text + "," + ResultTextBox[2].Text + "," + ResultTextBox[3].Text + "," + ResultTextBox[4].Text
               + "," + ResultTextBox[5].Text + "," + ResultTextBox[6].Text + "," + ResultTextBox[7].Text + "," + ResultTextBox[8].Text + "," + ResultTextBox[9].Text
               + "," + ResultTextBox[10].Text + "," + ResultTextBox[11].Text + "," + ResultTextBox[12].Text + "," + ResultTextBox[13].Text + "," + ResultTextBox[14].Text) >= 0);
            //Element found in list.
            //MessageBox.Show("Resultado já Exists no arquivo de texto!");
            else
            {
                linhas.Insert(0, txtConcurso.Text + "," + ResultTextBox[0].Text + "," + ResultTextBox[1].Text + "," + ResultTextBox[2].Text + "," + ResultTextBox[3].Text + "," + ResultTextBox[4].Text
             + "," + ResultTextBox[5].Text + "," + ResultTextBox[6].Text + "," + ResultTextBox[7].Text + "," + ResultTextBox[8].Text + "," + ResultTextBox[9].Text
             + "," + ResultTextBox[10].Text + "," + ResultTextBox[11].Text + "," + ResultTextBox[12].Text + "," + ResultTextBox[13].Text + "," + ResultTextBox[14].Text); // Passo 2
                File.WriteAllLines(nomeArquivo, linhas);
                //MessageBox.Show("Gravndo!");
            }
        }

my text file is being saved like this

arquivoTEXTO.png

How I tried the edit method

C#:
 private void editar()
        {
            try
            {
                using (StreamReader lendo = new StreamReader(@"C:\BoaSorte\Banco\Resultados.txt"))
                {
                    while (lendo.Peek() != -1)
                    {
                        int linha = File.ReadAllLines(@"C:\BoaSorte\Banco\Resultados.txt").GetLength(0);

                        for (int i = 1; i <= linha; i++)
                        {
                            if (lendo.ReadLine() == txtConcurso.Text)
                            {
                                string caminhoArquivo = @"C:\BoaSorte\Banco\Resultados.txt";

                                //Numero da linha que o conteúdo vai ser alterado
                                // Line number where the content will be changed

                                //Lendo arquivo e atribuindo em um array de string
                                //Reading file and assigning it to a string array

                                string[] arquivo = File.ReadAllLines(caminhoArquivo);

                                //Mudando o valor da linha informada
                                // Changing the value of the informed line

                               // arquivo = ResultTextBox[i].Text; //here is the error
                                lendo.Close();
                                //gravando o conteúdo por cima do arquivo,porem trava nessa linha falando que ja esta em uso
                                // recording the content over the file, but it hangs on this line saying that it is already in use
                                System.IO.File.WriteAllLines(caminhoArquivo, arquivo);
                            }
                        }
                    }
                }
            }

            catch (Exception)

            {

            }

I appreciate any advice, opinion or indication
 
In general, you will have to rewrite all the contents of the file if it's a text file, but there are some special cases.

You cannot delete lines without rewriting the entire file, except if you are deleting the last line. In that case, you can truncate the file.

You can edit lines, as long as the edits effectively overwrite letters within the same line. You cannot insert extra characters or delete characters from within a line.
 
@Skydiver thanks for replying,
editing would basically be changing a number if it's wrong, EX, 01,05,06,08 for 02,04,05,07 just an example maybe the contest too
 
Then you can just replace characters within the the same line. You should be able to Seek() to a particular location and replace characters.

I just recalled, this is assuming that the old and new characters also occupy the same number of bytes for the encoding. So if your file is composed of ASCII characters then this would be very easy. If the file encoding is UTF-8 or UTF-16, then replacing characters can get tricking if the old character's encoding doesn't have the same number of bytes as the new character's encoding.
 
I'm actually saving it in a simple file in notepad, without formatting,
Until then I was saving it in the Database, and editing and deleting it via query, in a text file I never did, I'll do another search on the subject, thanks.
 
There are several zero config databases that are available nowadays. I suggest picking one and just using it instead of trying to bend over backwards doing this line editing. Essentially, you are doing record-like operations, rather than text-like operations. Databases excel at managing records.
 
Thank you very much for your suggestion, I've been reading about SqLite, it seems like a good option, my concern would be when installing Sql Server is very complicated, I'll follow your suggestion and I'll iterate on other lighter banks.
a hug and stay with God.
 
Hello @titojd
Wow! I have just finished writting your code and I see that now you will take a different way. Well, I post the code here so that you all can see that it was not so difficult. Actually, it was more a logic issue than a programming one, but those are the most feared even by most expert developers.
Sincerely, I don't think that a DB needs to be used by this so simple procedure/algorithm.
C#:
namespace WinFormsAppEditTextFile
{
    public partial class Form1 : Form
    {
        private TextBox[] numbers;
        private string fileText;
        private int lineIndex;
        private const int lineLength = 49;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            int X = txtContest.Location.X + txtContest.Size.Width + 8;
            int Y = txtContest.Location.Y;
            numbers = new TextBox[15];
            for (int i = 0; i < numbers.Length; i++)
            {
                numbers[i] = new TextBox();
                numbers[i].Size = new Size(23, 23);
                numbers[i].Location = new Point(X + i * (23 + 8), Y);
            }
            Controls.AddRange(numbers);
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            string contents = File.ReadAllText(txtFileName.Text);
            fileText = contents;
            txtFileContents.Text = contents;
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            int index = 0;
            string[] lines = File.ReadAllLines(txtFileName.Text);
            for (int i = 0; i < lines.Length; i++)
            {
                if (lines[i].Substring(0, 4) == txtContest.Text)
                {
                    for (int j = 0; j < 15; j++)
                    {
                        index = lines[i].IndexOf(',', index) + 1;
                        numbers[j].Text = lines[i].Substring(index, 2);
                    }
                    lineIndex = i;
                    break;
                }
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            File.WriteAllText(txtFileName.Text, fileText);
        }

        private void btnEdit_Click(object sender, EventArgs e)
        {
            string editedLine = txtContest.Text;
            for (int i = 0; i < 15; i++)
                editedLine += "," + numbers[i].Text;
            fileText = fileText.Replace(lines[lineIndex], editedLine);
            txtFileContents.Text = fileText;
        }

        private void btnExclude_Click(object sender, EventArgs e)
        {
            fileText = fileText.Replace(lines[lineIndex] + "\r\n", "");
            txtFileContents.Text = fileText;
        }
    }
}
Regards
Pablo
 

Attachments

  • raffle.png
    raffle.png
    9 KB · Views: 38
@Pablo : You are re-writing the entire file. (See line 57 in post #8) What the @titojd is hoping to do is just modify parts of the file without having to re-write the entire file.
 
Hello @Skydiver
I thought the problem (the biggest one) was another for @titojd, and that it was being able to search, edit, and delete lines from his text file. As you said, it is impossible to delete lines without rewritting the file, and for the edit using what you mentioned (Seek() and Write()) would be very heavy.
There is a missing var declaration in my previous code, i post the fixed:
C#:
namespace WinFormsAppEditTextFile
{
    public partial class Form1 : Form
    {
        private TextBox[] numbers;
        private string[] lines;
        private string fileText;
        private int lineIndex;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            int X = txtContest.Location.X + txtContest.Size.Width + 8;
            int Y = txtContest.Location.Y;
            numbers = new TextBox[15];
            for (int i = 0; i < numbers.Length; i++)
            {
                numbers[i] = new TextBox();
                numbers[i].Size = new Size(23, 23);
                numbers[i].Location = new Point(X + i * (23 + 8), Y);
            }
            Controls.AddRange(numbers);
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            string contents = File.ReadAllText(txtFileName.Text);
            fileText = contents;
            txtFileContents.Text = contents;
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            int index = 0;
            lines = File.ReadAllLines(txtFileName.Text);
            for (int i = 0; i < lines.Length; i++)
            {
                if (lines[i].Substring(0, 4) == txtContest.Text)
                {
                    for (int j = 0; j < 15; j++)
                    {
                        index = lines[i].IndexOf(',', index) + 1;
                        numbers[j].Text = lines[i].Substring(index, 2);
                    }
                    lineIndex = i;
                    break;
                }
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            File.WriteAllText(txtFileName.Text, fileText);
        }

        private void btnEdit_Click(object sender, EventArgs e)
        {
            string editedLine = txtContest.Text;
            for (int i = 0; i < 15; i++)
                editedLine += "," + numbers[i].Text;
            fileText = fileText.Replace(lines[lineIndex], editedLine);
            txtFileContents.Text = fileText;
        }

        private void btnExclude_Click(object sender, EventArgs e)
        {
            fileText = fileText.Replace(lines[lineIndex] + "\r\n", "");
            txtFileContents.Text = fileText;
        }
    }
}
 
You're reinventing a database. Consider just using SQLite

it is impossible to delete lines
Not always true; in your case your records are a fixed width, so they can be rewritten without regenerating the entire file. There isn't really any such thing as a "line" in a "text file" - files are just sequences of bytes, certain bytes being interpreted in certain ways to give the illusion of e.g. "lines". You could bring the final line over the top of the line to delete, then shorten the file by a line's worth of bytes, for example

would be very heavy
Erm.. it's not heavy from c#'s perspective. Seeking and writing bytes is a light weight operation; certainly a lot lighter than rewriting the file every time you want to make a change). It's heavy (to the extent of being pointless) work to code it though.. A SQLite db would be less coding, less effort and offer more features
 
Last edited:
Hello @Pablo , Thank you very much for the code, I'll see if I can use it, if not I'll do what @Skydiver suggested to me earlier,
I've been looking over the test files, Go to ParentText don't have lines: they have an "end of line" symbol which is recognized by the application and interpreted as an end of line marker - for C# applications it's usually "\n " or occasionally "\r\n " for some systems. They are stored by the operation as binary data which happens to be "human readable".

This means that you cannot "delete", "add" or even "change" a "Line" in a text file: to do this, you must create a new file, copy everything up to the point of change over, then write your new line in the output file (insert a line), skip a line in the input file (delete a line) or do both (change a line), copy the rest of the file and close both files, delete the original and rename the new one with the old filename.

This is considerably more work than using a database and much more error prone!
anyway thank you very much for taking your time to help me, a hug.
 
Last edited:
just a doubt @cjard, using SqLite, when installing the application on another pc, will I have to install a database? Or is it built into the app?
 
Most people would just:
- install a loose empty database file with the schema already in it into the AppData directory;
- copy an empty database file with the schema already in it from the program resources into the AppData directory on first run; or
- create the database in the AppData directory and set up the schema on first run.
 
Personally, for something lightweight, I would just use LiteDB. Here is demo code from their "Getting Started" documentation:
C#:
// Create your POCO class entity
public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string[] Phones { get; set; }
    public bool IsActive { get; set; }
}

// Open database (or create if doesn't exist)
using(var db = new LiteDatabase(@"C:\Temp\MyData.db"))
{
    // Get a collection (or create, if doesn't exist)
    var col = db.GetCollection<Customer>("customers");

    // Create your new customer instance
    var customer = new Customer
    { 
        Name = "John Doe", 
        Phones = new string[] { "8000-0000", "9000-0000" }, 
        IsActive = true
    };
    
    // Insert new customer document (Id will be auto-incremented)
    col.Insert(customer);
    
    // Update a document inside a collection
    customer.Name = "Jane Doe";
    
    col.Update(customer);
    
    // Index document using document Name property
    col.EnsureIndex(x => x.Name);
    
    // Use LINQ to query documents (filter, sort, transform)
    var results = col.Query()
        .Where(x => x.Name.StartsWith("J"))
        .OrderBy(x => x.Name)
        .Select(x => new { x.Name, NameUpper = x.Name.ToUpper() })
        .Limit(10)
        .ToList();

    // Let's create an index in phone numbers (using expression). It's a multikey index
    col.EnsureIndex(x => x.Phones); 

    // and now we can query phones
    var r = col.FindOne(x => x.Phones.Contains("8888-5555"));
}
 
Back
Top Bottom