2

I am currently making a text file of three different types of accounts, which could be FreeTest, BasicTest, or PremiumTest. I am looking for a solution that will edit a line where the account number is located and edit the properties in that line. Here is what I have tried on the else block. I need to update the properties on the text file line with the parameter from account that is being passed in to this function.

public void SaveAccount(Account account)
    {
        if (!fileAccounts.Any(x => x.AccountNumber == account.AccountNumber))
        {
            fileAccounts.Add(account);
            string path = @"C:\testfolder\accounts.txt";
            string[] line = new string[fileAccounts.Count + 1];
            //line[0] = "AccountNumber,Name,Balance,Type";

            int i = 0;
            foreach (var a in fileAccounts)
            {
                line[i] = a.AccountNumber + "," + a.Name + "," + a.Balance + "," + a.Type.ToString().Substring(0, 1);
                i++;
            }

            File.AppendAllLines(path, line);
        } else
        {
            string path = @"C:\testfolder\accounts.txt";
            //var line = fileAccounts.Where(x => x.AccountNumber == account.AccountNumber);

            using (var reader = new StreamReader(path))
            {
                var index = 0;

                while(!reader.EndOfStream)
                {
                    var line = reader.ReadLine().Split(',');
                    var _accountNumber = line[0];
                    var _name = line[1];
                    var _balance = line[2];
                    var _type = line[3].ToString().Substring(0, 1);


                }
            }

            //File.WriteAllLines(path, line);

        }

    }

accounts.txt

AccountNumber,Name,Balance,Type
10001,Free Account,100,F
20001,Basic Account,500,B
30001,Premium Account,1000,P
Alejandro H
  • 388
  • 1
  • 9
  • 32
  • Doest it need to be .txt? Why not use .json – MrLu Dec 14 '19 at 02:16
  • as far is this project goes, I am only using txt. Not sure about json being better though. – Alejandro H Dec 14 '19 at 02:34
  • 1
    with .json you can read the file, mod a specific property then write back to file, you can even use a model to make your life simpler. I'll write something up give me a few. – MrLu Dec 14 '19 at 02:47
  • You can use the csv helper to use this file format but normally you need to read in the whole thing and then write out the new one – BugFinder Dec 14 '19 at 03:07
  • You might want also to consider the `xml` serialization. [Here's](https://stackoverflow.com/questions/58686509/trouble-serializing-and-deserializing-multiple-objects/58687570#58687570) a c# example, and [another](https://stackoverflow.com/questions/59074005/saving-listbox-with-additional-information-in-my-settings/59097544#59097544) vb.net example might also be useful. –  Dec 14 '19 at 03:49
  • @MrLu, you can do same things with other file types. In OP case it seems to be `.csv` format. – Fabio Dec 14 '19 at 08:54

3 Answers3

3

This is another way of adding an object of Type Account to a text file with comma separated values.

Use Enum class to select Account Type

        public enum AccountType
        {
            Free,
            Basic,
            Premium
        }

this is your Account class

  1. This has built in Account method that will convert the string into an Account. Can be used in many different places.
  2. Has a method that converts the class to a string (comma seperated).
        public class Account
        {
            public int AccountNumber { get; set; }
            public AccountType Type { get; set; }
            public int Balance { get; set; }
            public string AccountType { get; set; }

            public Account() { }

            // Built in constructor that converts the string to account.
            public Account(string account)
            {
                List<string> accountInfo = account.Split(',').ToList();
                int.TryParse(accountInfo.FirstOrDefault(), out int accountNum);
                AccountNumber = accountNum;
                Type = (AccountType)Enum.Parse(typeof(AccountType), accountInfo.Skip(1).FirstOrDefault().Split(' ').First());

                int.TryParse(accountInfo.Skip(2).FirstOrDefault(), out int balance);
                Balance = balance;
                AccountType = accountInfo.Skip(3).FirstOrDefault();
            }

            // built in the Account the method to convert to string.
            public override string ToString()
            {
                return $"{AccountNumber},{Type.ToString()},{Balance},{AccountType}";
            }
        }

And, save method to save a new account to existing file

Loads the accounts in a list and validates the account does not already exists in the file. Updates it with a new account and saves it.

        public static void SaveAccount(Account account)
        {
            string path = @"C:\temp\Accounts.txt";
            (string header, List<Account> allAccounts) = LoadAccounts(path);

            if (!allAccounts.Any(x => x.AccountNumber == account.AccountNumber))
                allAccounts.Add(account);
            else {
                 var existingAccount = allAccounts.FirstOrDefault(x => x.AccountNumber == account.AccountNumber);
                 existingAccount.AccountType = account.AccojntType;
                 existingAccount.Balance = account.Balance;
                 existingAccount.Type = account.Type;
            }

            List<string> accountsToSave = new List<string>() { header };
            accountsToSave.AddRange(allAccounts.Select(x => x.ToString()).ToList());

            File.WriteAllLines(path, accountsToSave);
        }

You can use this method to load all Accounts to memory


        public static (string, List<Account>) LoadAccounts(string path)
        {
            var accounts = File.ReadAllLines(path);
            string header = accounts.FirstOrDefault();

            List<Account> allAccounts = new List<Account>();
            foreach (string accountInfo in accounts.Skip(1))
            {
                var accountToAdd = new Account(accountInfo);
                if (!allAccounts.Any(x => x.AccountNumber == accountToAdd.AccountNumber))
                    allAccounts.Add(accountToAdd);
            }

            return (header, allAccounts);
        }
Jawad
  • 11,028
  • 3
  • 24
  • 37
  • Loved the `enum` part. –  Dec 14 '19 at 03:50
  • currently my LoadAccount() method looks like this: `public Account LoadAccount(string AccountNumber)` should it still be ok to change to static? And contains one line `{return fileAccounts.FirstOrDefault(x => x.AccountNumber == AccountNumber);}` – Alejandro H Dec 14 '19 at 23:21
  • I think I have a solution based on what you posted. – Alejandro H Dec 15 '19 at 00:57
  • I'm glad you got a working solution... please do mark a post as answer – Jawad Dec 15 '19 at 01:04
  • I decided not to change `LoadAccount()`, however only getting one account number to save to the text file. I am trying to figure out what it is. – Alejandro H Dec 15 '19 at 01:15
  • If you notice carefully at my accounts.txt I posted above, I am outputting, P, B, or F. In the account class, its outputting Premium, Basic, or Free. I know that you would have expected AccountNumber to be an integer, but in my case is a string. – Alejandro H Dec 15 '19 at 15:25
  • You have `return $"{AccountNumber},{Type.ToString()},{Balance},{AccountType}";` but I think you mean, `return $"{AccountNumber},{AccountType},{Balance},{Type.ToString()}";` – Alejandro H Dec 15 '19 at 15:30
  • The type is already a string that should have one character. You dont need to use tostring() – Jawad Dec 15 '19 at 15:34
  • I used in if statement that checks `if (Type == AccountType.Free){ strType = "F";}` – Alejandro H Dec 15 '19 at 15:56
0

I'd recommend using List<string> instead of arrays if you're in C# and don't have a specific reason for using arrays.

use a foreach loop to loop through a List of strings for each line and check if the line contains your account number then edit it accordingly and save back into a new file.

EDIT: Jawad is right, changed to make this more specific but slightly less efficient

            //instantiate your List<string> from reading the path
            List<string> lines = System.IO.File.ReadAllLines(path).ToList<string>();

            //use a line index to check where you're at
            int lineIndex = 0;

            //I'd use foreach loops in C# .. they're really nice
            foreach (string line in lines)
            {
               //split the line to get the fields
                var lineSplit = line.Split(',');

                //if the first part is your account number then we can edit it
                if (lineSplit[0] == account.AccountNumber.ToString())
                {
                    //replace any one of these with a new value
                    var _accountNumber = lineSplit[0];
                    var _name = lineSplit[1];
                    var _balance = lineSplit[2];
                    var _type = lineSplit[3].ToString().Substring(0, 1);

                    //then put the newline back into a string var
                    string newline = _accountNumber + "," + _name + "," + _balance + "," + _type + "\r\n";

                    //assign the string back into our list at the index point
                    lines[lineIndex] = newline;
                }
                //add one to the index
                lineIndex++;
            }

            //then write back to your file
            System.IO.File.WriteAllLines(pathNew, lines);
hexagod
  • 449
  • 3
  • 15
0

I don't know how the rest of your code looks, but this is a quick read, modify and save in json,

    public void SaveAccount(Account account)
    {

        if(File.Exists(@"c:\account.json"))
        {
            //Read it
            Account acc = JsonConvert.DeserializeObject<Account>(File.ReadAllText(@"c:\account.json"));

            //Mod it
            acc.AccountNumber = 0;
            acc.Balance = 0;
            acc.Name = "";
            acc._Type = "";

            //Save it
            File.WriteAllText(@"c:\account.json", JsonConvert.SerializeObject(acc));
        }
        else
        {
            // Create it
            File.WriteAllText(@"c:\account.json", JsonConvert.SerializeObject(account));
        }


    }

you will need "using Newtonsoft.Json;"

MrLu
  • 376
  • 2
  • 9