Resolved access a txt file and change individual fields?

sock1992

Well-known member
Joined
May 20, 2020
Messages
107
Programming Experience
Beginner
I've managed to change individual fields but then end up deleting everything else in the file. I only want to edit one field. Any help would be greatly appreciated. Thankyou

Heres my current code:

C#:
  public static void UpdatePatientData()
        {
            string detail, choice;
       
            Console.WriteLine("Please enter the ID of the customer you would like to Update: ");
            ID = Console.ReadLine();

            string[] Name = File.ReadAllText("user.txt").Split('|'); // each field will represent an index from 1-4

            for (int i = 0; i < Name.Length; i++)
            {
                if (Name[i].Contains(ID))
                {
                    // here is where i would like to edit the name/gender/age etc and write it back to the file

                }
            }
        }
 
Last edited:
With text files there is no inserting or deleting of fields. You'll have to rewrite the entire file with your edits.

It seems like you are using a text delimited file when you really should be using a database instead.

Or if you really want to use a text file, make sure that you use fixed sized fields. That way you can seek to a particular line and just overwrite the fields in that line.
 
With text files there is no inserting or deleting of fields. You'll have to rewrite the entire file with your edits.

It seems like you are using a text delimited file when you really should be using a database instead.

Or if you really want to use a text file, make sure that you use fixed sized fields. That way you can seek to a particular line and just overwrite the fields in that line.
I'm currently making a console application to save patient data so I thought a text file would be most appropriate?

would it work if I were to save each object to a dictionary?

delete/edit each field through the dictionary when needed

then rewrite all the data back to the txt file
 
I'm currently making a console application to save patient data so I thought a text file would be most appropriate?
Unless it is a very small amount of data, a database would be more appropriate. Even if the amount of data is very small, it's probably still more appropriate to use a database because that will teach you how to use a database, which is what you'll be doing in pretty much any "real" application. Text files can be good for transferring data between systems but not so much for storing data with a system.
would it work if I were to save each object to a dictionary?

delete/edit each field through the dictionary when needed

then rewrite all the data back to the txt file
It certainly would. The acts of loading, editing and saving the data are then completely independent, so you can tackle each one that way. Editing a Dictionary has nothing to do with text files.

If you are going to use delimited files then you might consider using a dedicated CSV library, for the reading at least. One option is to reference the Microsoft.VisualBasic.dll assembly and use the TextFieldParser class for reading the data. There are also various third-party options, often available as NuGet packages.
 
And even with the JSON files, he'll still need to completely rewrite the file. He can't just go seek to a particular location with in the file and overwrite a value (unless the new value has the exact same number of characters as the old value).
 
I'm currently making a console application to save patient data so I thought a text file would be most appropriate?

would it work if I were to save each object to a dictionary?

delete/edit each field through the dictionary when needed

then rewrite all the data back to the txt file
And a list instead of dictionary would also work.
 
You'll have to rewrite the entire file with your edits.
No they don't. Why? What's wrong with find and replace?
He can't just go seek to a particular location with in the file and overwrite a value (unless the new value has the exact same number of characters as the old value).
Again, why not? Nodes can be replaced. Anything is possible if we try hard enough. Who said that again? Peter Pan.

Sure anything is possible if you try hard enough. Seems like yous are making it sound harder than it is.

Edit : Fixed typo
 
Last edited:
Don't forget you can create a Json object from class data and vice versa, create a class object from Json data etc. And by using a list of that class items (json object), you would accumulate a list of class items - ie List<PatientInfo>. Seems not impossible and more practical if you ask me.
 
No they don't. Why? What's wrong with find and replace?

Again, why not? Nodes can be replaced. Anything is possible if we try hard enough. Who said that again? Peter Pan.

Sure anything is possible if you try hard enough. Seems like yous are making it sound harder than it is.

Edit : Fixed typo
Yes, nodes can be replaced in memory. But how do you get those nodes back into the file without overwriting the entire file?
 
C#:
    string[] lines = System.IO.File.ReadAllLines("patinfo.csv");
            StreamWriter Write = new System.IO.StreamWriter("temp.csv");
                               
            for (int i = 0; i < lines.Length; i++)          
            {
                string[] fields = lines[i].Split(',');

                if (fields[0] == ID)
                {                                    
                    for (int k = 1; k <= fields.Length; k++)
                    {
                        if(k == choice)
                        {
                            fields[choice-1] = change;
                            Write.WriteLine(fields[0] + "," + fields[1] + "," + fields[2] + "," + fields[3] + "," + fields[4] + "," + fields[5]); 
                        }
                    }            
                }
                else
                {
                    if (!edited )
                    {
                        Write.WriteLine(fields[0] + "," + fields[1] + "," + fields[2]+ "," + fields[3] + "," + fields[4] + "," + fields[5]);             
                    }
                   
                }                                  
            }      
            Write.Close();
 
Last edited:
Here is a blunt but quick rewrite of your code using Json. I prefer this than using the CSV recommendation by @jmcilhinney personally, but that's just me. There is nothing wrong with using a CSV file, but Json is better to work with. You don't have to use this example. I am just providing it as a working --work in progress-- alternative to your current approach, and you can easily modify it to your taste if you prefer.

Put a break point on line 12, and step through the code until line 18 where it terminates. You can find a debugging tutorial in my signature if you need it.

This : var patient1 = WithPatient(0, "Tom", 33, Patient.GenderChoice.Male.ToString(), "666 Home Vile St.", "052895566", 0); calls the WithPatient method which determines the course of action to take based on the last parameter passed to the method. Ie. If the value is 0, it will call the constructor in the Patient class and creates a new Patient each time. We created two patients, and here is your second :
var patient2 = WithPatient(1, "Bob", 36, Patient.GenderChoice.Male.ToString(), "888 Home Vila St.", "052895567", 0); and then we update the first patient we created. Set new credentials such as phone number and gender change.

Notice on the WithPatient method, we have an integer on the end of that method. If it's set to 0, it will create a new patient. If it's set to 1, it will update a patient with the new details passed to the method, and then with those details it creates a new Patient by calling the constructor of your Patient class. This takes place on line 24 : Patient patient = new Patient(id, name, age, gender, address, phonenumber);. Note line 47 requires you to remove the Patient you don't want any longer. Here is the complete code. See the additional notes below this code :

C#:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace CTestConsole
{
    internal static class Program
    {
        public static void Main(string[] args)
        {
            var patient1 = WithPatient(0, "Tom", 33, Patient.GenderChoice.Male.ToString(), "666 Home Vile St.", "052895566", 0);
            var patient2 = WithPatient(1, "Bob", 36, Patient.GenderChoice.Male.ToString(), "888 Home Vila St.", "052895567", 0);
            /* We now have 2 patients in our Dictionary. Now lets update Tom */
            patient1 = WithPatient(0, "Tom", 33, Patient.GenderChoice.Female.ToString(), "999 Lala land", "086997513", 1);

        }
        public static Dictionary<int, Patient> Patients = new Dictionary<int, Patient>();
        static readonly string PathToDBFile = AppDomain.CurrentDomain.BaseDirectory;
        static readonly string FileName = "db.json";
        public static Patient WithPatient(int id, string name, int age, string gender, string address, string phonenumber, int action)
        {
            Patient patient = new Patient(id, name, age, gender, address, phonenumber);
            if (action == 0)
            {
                Patients.Add(patient.ID, patient);
                File.WriteAllText(Path.Combine(PathToDBFile, FileName), JsonConvert.SerializeObject(Patients, Formatting.Indented));
                return patient;
            }
            else if (action == 1)
            {
                string json_Data = File.ReadAllText(Path.Combine(PathToDBFile, FileName));
                Patients.Clear();
                Patients = JsonConvert.DeserializeObject<Dictionary<int, Patient>>(json_Data);

                Patients.Values.Where(x => x.Name == name).Single().Name = name;
                Patients.Values.Where(x => x.Name == name).Single().Age = age;
                Patients.Values.Where(x => x.Name == name).Single().Gender = gender;
                Patients.Values.Where(x => x.Name == name).Single().Address = address;
                Patients.Values.Where(x => x.Name == name).Single().PhoneNumber = phonenumber;
                File.WriteAllText(Path.Combine(PathToDBFile, FileName), JsonConvert.SerializeObject(Patients, Formatting.Indented));
                return patient;
            }
            else if (action == 2)
            {
                /* Read all and remove the one you don't want */
            }
            return null;
        }
    }
    public class Patient
    {
        public Patient(int iD, string name, int age, string gender, string address, string phoneNumber)
        {
            ID = iD;
            Name = name;
            Age = age;
            Gender = gender;
            Address = address;
            PhoneNumber = phoneNumber;
        }
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Gender { get; set; }
        public enum GenderChoice
        {
            Male,
            Female
        };
        public string Address { get; set; }
        public string PhoneNumber { get; set; }
    }
}
The reason why I used a Dictionary<int, Patient> here and not a List<Patient> is solely to make the Json data more readable and easier to work with. For example, this is what the above code creates :
JSON:
{
  "0": {
    "ID": 0,
    "Name": "Tom",
    "Age": 33,
    "Gender": "Female",
    "Address": "999 Lala land",
    "PhoneNumber": "086997513"
  },
  "1": {
    "ID": 1,
    "Name": "Bob",
    "Age": 36,
    "Gender": "Male",
    "Address": "888 Home Vila St.",
    "PhoneNumber": "052895567"
  }
}
But had I used a list, you would have had a completely different structure. For example. If we used a list of Patient, the data would have looked something like this (May not be exact) :
JSON:
{
  {
    "ID": 0,
    "Name": "Tom",
    "Age": 33,
    "Gender": "Female",
    "Address": "999 Lala land",
    "PhoneNumber": "086997513"
  },
  {
    "ID": 1,
    "Name": "Bob",
    "Age": 36,
    "Gender": "Male",
    "Address": "888 Home Vila St.",
    "PhoneNumber": "052895567"
  }
}
Noticing that the ID is removed from the opening tag :
C#:
  "0": {
    "ID": 0,
This is actually important, because it allows us to later work with that ID later on when selecting data from the file, providing you decide to use this blunt example to get started. None the less, it does work, and will likely give you a faster head-start in your project, with only a few edits to make yourself.

Now regarding your updated code on p1/#11.
If I attempt to input a patient ID located on the second or third row it will not edit any of that data. Anyone know why this is?

Click the spoiler on my signature and press Ctrl+F type Debug, and read that link on how to debug your code. Debugging is a fundamental need to know trait all programmers should know how to do. And that tutorial explains how to troubleshoot your own code and demonstrates how to use the debugger properly. Remember, we are here to advise you and help you write better code. We are not here to debug your code for you. If there is something you don't know or understand in your own code, then we are happy to answer direct questions regarding why something functions differently than you anticipate.

Yes, nodes can be replaced in memory. But how do you get those nodes back into the file without overwriting the entire file?
There are a few ways. One is Regex, but likely overkill when you can also just use some Linq and replace a line the same way as our OP did on p1/#11 @ line 24. Given if the original poster uses Json, it will be easier to manipulate the data in a Json structure. Somehow I get the feeling this database isn't designed to be huge. So simply reading the file back to Json won't be a problem or a performance issue. However, I will dig into the Json docs to see if there is a better alternative way to manipulate lines using the Json lib instead.
 
Last edited:
Notice that in post #11, the OP is rewriting the file. He reads the inputs from the original file, and writes the data into a temporary file, and then goes and replaces the original file with the temporary file.

Here's a simple problem: Let's start with a simple JSON file:
JSON:
{
    "Name" : "Batman"
}

We want to change the Name to "Bruce Wayne" and get this:
JSON:
{
    "Name" : "Bruce Wayne"
}

The file data for the original file looks like this:
C#:
          Offset Bytes                                           Ascii
                 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
          ------ ----------------------------------------------- -----
0000000000000000 7B 0D 0A 20 20 20 20 22 4E 61 6D 65 22 20 3A 20 {��    "Name" :
0000000000000010 22 42 61 74 6D 61 6E 22 0D 0A 7D                "Batman"��}

The result that is needed is:
C#:
          Offset Bytes                                           Ascii
                 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
          ------ ----------------------------------------------- -----
0000000000000000 7B 0D 0A 20 20 20 20 22 4E 61 6D 65 22 20 3A 20 {��    "Name" :
0000000000000010 22 42 72 75 63 65 20 57 61 79 6E 65 22 0D 0A 7D "Bruce Wayne"��}

How do you replace 6 bytes at offset 0x11 to 0x16 with 11 bytes to span from 0x11 to 0x1B? What magic operation can be done to Stream to make 11 bytes fit into 6 bytes (and still comply with the JSON format)? (Yes, compression could potentially pack 11 bytes worth of data in 6 bytes, but JSON currently doesn't have compression as part of the standard.)
 
Last edited:
string[] lines = System.IO.File.ReadAllLines("patinfo.csv");
StreamWriter Write = new System.IO.StreamWriter("temp.csv");
Seems very counterproductive does it not?
Was my use of data creation not sufficient?
Does my example lack better practices?
Is the example I provided to hard for the OP to adapt their current code?
Would you not personally consider this more of an improvement on what the OP already has?
Should we fall back to writing shitty code because its what someone else wants?

I don't like the code the OP provided. So I rewrote it to effectively do the same thing, did I not?

Why write to two files at all. It's simply double work.... The only thing I didn't add was the options of choice from line 7/17.
 
Back
Top Bottom