Updating line of a file if array element matches text box - c#

I have a method which currently reads all lines of a directory file (3 fields per line) and updates a directory array with a record of text box entries if the extension code entered matches an extension code field in the file.
I had the updated directory array displaying to a list view, as soon as I attempted to update the directory file with the updated array, it all went downhill! Edit to clarify: with the latest version of the code below, the array no longer displays to the list view, and the file is not updated. No errors are thrown.
public void updateName()
{
int count = 0;
string[] lines = File.ReadAllLines(directoryFile);
// Set size of directory array equal to number of lines in file
int lineCount = lineCounter();
directory = new record[lineCount];
record currentRecord = new record();
// Iterate through each line in file
foreach (string line in lines)
{
// Split current line into three fields
string[] fields = line.Split(',');
// Save current line as new record with surname, forename and extCode fields
currentRecord.surname = fields[0];
currentRecord.forename = fields[1];
currentRecord.extCode = Convert.ToInt32(fields[2]);
// If extension code in current record matches text box entry
if (Convert.ToInt32(fields[2]) == Convert.ToInt32(txtExtCode.Text))
{
// Change surname and forname fields to match text box entries
currentRecord.surname = txtForename.Text;
currentRecord.forename = txtSurname.Text;
using (StreamWriter writer = new StreamWriter(directoryFile))
{
for (int currentLine = 1; currentLine <= lines.Length; ++currentLine)
{
if (currentLine == count)
writer.WriteLine(currentRecord);
else
writer.WriteLine(lines[currentLine - 1]);
}
}
}
// Save currentRecord as next element in directory array, then increment
directory[count] = currentRecord;
count++;
}
}

You don't need a linecounter(). The number of lines is lines.Length.
But why do you need this directory array? You are filling it, but you are not using it anywhere.
Another major problem is that you are creating a StreamWriter inside the foreach loop. You should open the file before the loop and close it after the loop to make it work.
Also, you are mixing writing currentRecord which is of type record and writing lines of type string to the output file. This cannot work.
You are also putting txtForename.Text into currentRecord.surname instead of currentRecord.forename and vice versa.
I suggest to first apply the change in the lines array and then to write this lines array back to to file with File.WriteAllLines which is the symmetric operation to File.ReadAllLines.
I'm applying the change directly to fields array, so that I can convert it back to a string with String.Join (it is the symmetric operation to String.Split).
public void updateName()
{
// Do this conversion before the loop. We need to do it only once.
int selectedCode = Convert.ToInt32(txtExtCode.Text);
string[] lines = File.ReadAllLines(directoryFile);
for (int i = 0; i < lines.Length; i++)
{
// Split current line into three fields
string[] fields = lines[i].Split(',');
int extCode = Convert.ToInt32(fields[2]);
if (extCode == selectedCode)
{
fields[0] = txtSurname.Text;
fields[1] = txtForename.Text;
lines[i] = String.Join(",", fields);
// If the extension code is unique, leave the for-loop
break;
}
}
File.WriteAllLines(directoryFile, lines);
}
I also use for instead of foreach in order to have an index i, so that I can replace a single line in the lines array at a specific index.
I don't know if the extension code in the directory file is unique. If it is, you can exit the for loop prematurely with break.

Related

How can I read a text file and write its values to an array

I have a text file with values and I need to read them. The first line is the size of my array and the second line has values that I need to put into to an array.
My main looks like:
public static void Main()
{
int n,i=0,k=1;
var plik_wejsciowy = new StreamReader("In0201.txt");
StreamWriter plik_wyjsciowy = new StreamWriter("Out0201.txt");
string[] wejscie = plik_wejsciowy.ReadLine().Split(' ');
n = int.Parse(wejscie[0]);
int[] tab = new int[n];
for (i=0;i<n;i++)
{
tab[i] = int.Parse(wejscie[k]);
k++;
}
plik_wyjsciowy.Close();
}
I don't really know what to do and where I'm making a mistake.
We can make life easier; you don't really need to use the first line to track how many lines are in the file; you can just read the lines into an array (skip the first if it's only a line counter) then parse the rest and turn them into an array:
var x = File.ReadAllLines(path).Skip(1).Select(int.Parse).ToArray();
If you switch the first line being a counter of lines, remove the Skip(1)

How to get specific data from text file

A part of my program has the user save their record within a text document along with their name. The way the program works is that if the user submits their own name, their previous record would be brought back and reinserted into the game. For example, if my name was Justin, I would enter "Justin" into the textbox and the program looks through the textfile, and if it finds someone named Justin, then it would look at the next three lines of data and assign those lines to playerwins, computerwins, and ties respectively. However, any examples I could find either dealt with adding those specific numbers up. I was hoping someone here could point me in the right direction with how I am supposed to structure this code.
private void FileReader(string playername, int playerwins, int computerwins, int ties)
{
StreamReader outputfile;
outputfile = File.OpenText("Records.txt");
while (!outputfile.EndOfStream)
{
if (string.Compare(playername, outputfile.ReadLine()) == 0)
{
//ReadLine() and variable assigning code goes here
}
}
}
If the text file is small enough (and most of them are), I prefer to read and write all of the file's lines at once, rather than one at a time. This separates "file handling" from "score updating", rather than having them intertwined. Resources are also cleaned up automatically (with StreamReader, you have to remember to use 'using' or 'Dispose()' to ensure that resources like file handles are properly released after an error occurs).
For the code below, if playername is already in the file, then playername's scores are updated. Otherwise, playername and playername's scores are added to the end of the file. If the file does not already exist, a new file is created.
The last suggestion would be to rename the method, to something like UpdateOrInsertPlayerScores().
private void FileReader(string playername, int playerwins, int computerwins, int ties)
{
string filename = "Records.txt";
string[] lines;
// read entire text file (if any) into lines
if (File.Exists(filename))
{
lines = File.ReadAllLines(filename);
}
else
{
lines = new string[0];
}
// find playername's line (or -1 if not present)
int p = -1;
for (int i = 0; i < lines.Length; ++i)
{
if (lines[i] == playername)
{
p = i;
break;
}
}
// update (or insert) playername's scores in lines[]
if (p == -1)
{
// playername does not have scores yet; append 4 new lines representing playername's scores
List<string> newLines = new List<string>(); // copy lines[] to a List<> so we can add new lines to it
newLines.AddRange(lines);
newLines.Add(playername);
newLines.Add(playerwins.ToString());
newLines.Add(computerwins.ToString());
newLines.Add(ties.ToString());
lines = newLines.ToArray(); // copy expanded List<> back to lines[]
}
else
{
// update the 3 lines after playername's line with playername's updated scores
// verify that the 3 lines to be updated are present after the playername's line P
if ((p + 3) > (lines.Length - 1))
{
throw new Exception("Player scores file is not in the expected format.");
}
// update the 3 lines in place
lines[p + 1] = playerwins.ToString();
lines[p + 2] = computerwins.ToString();
lines[p + 3] = ties.ToString();
}
// re-write entire text file (with updated lines)
File.WriteAllLines(filename, lines);
}

c# Read lines from a file and replace with text from DataGridView Data

I am relatively new to c#, I am creating an windows application which would read all the lines from a text file. The user will input the string which needs to be replaced in Column[0] and the text with which it needs to be replaced in Column1 of the DataGridView control.
I have created two string arrays column0 and column1.
However, I am getting an error while replacing the string in line (column0, column1)
The following is my code:
string[] column0 = new string[dgvMapping.Rows.Count];
string[] column1 = new string[dgvMapping.Rows.Count];
int j = 0;
foreach(DataGridViewRow row in dgvMapping.Rows)
{
if (!string.IsNullOrEmpty(Convert.ToString(row.Cells[0].Value)))
{
column0[j] = Convert.ToString(row.Cells[0].Value);
column1[j] = Convert.ToString(row.Cells[1].Value);
j++;
}
}
var _data = string.Empty;
String[] arrayofLine = File.ReadAllLines(ofd.FileName);
using (StreamWriter sw = new StreamWriter(ofd.FileName + ".output"))
{
for (int i = 0; i < arrayofLine.Length; i++)
{
string line = arrayofLine[i];
line = line.Replace(column0[i], column1[i]);
sw.WriteLine(line);
}
}
I am using OpenFileDialog to select the file.
The Error While Executing:
You are looping around a file of unknown number of lines, and assuming that the count of lines in the grid is exactly the same as that of the file. Your code will only work if both the file and the gridView have the same number of lines.
One of the solutions, is to loop over the array of lines (as you have already did), and search for the GridViewRow in which the current line contains a key in your DGV. If this is the case, then replace all the occurences of the key by the value (obtained from the gridView) in that line, otherwise do nothing.
Check out the code below :
// Convert the row collection to a list, so that we could query it easily with Linq
List<DataGridViewRow> mySearchList = dataGridView1.Rows.Cast<DataGridViewRow>().ToList();
const int KEY_INDEX = 0; // Search index in the grid
const int VALUE_INDEX = 1; // Value (replace) index in the grid
for (int i = 0; i < arrayofLines.Length; i++)
{
string line = arrayofLines[i];
// Get data grid view Row where this line contains the key string
DataGridViewRow matchedRow = mySearchList.FirstOrDefault(obj => line.Contains(obj.Cells[KEY_INDEX].Value.ToString()));
// If this row exists, replace the key with the value (obtained from the grid)
if (matchedRow != null)
{
string key = matchedRow.Cells[KEY_INDEX].Value.ToString();
string value = matchedRow.Cells[VALUE_INDEX].Value.ToString();
line = line.Replace(key, value);
sw.WriteLine(line);
}
else
{
// Otherwise, do nothing
}
}
Stuartd is correct… there are more lines in the file than there are elements to search. I am not sure what the search is doing in a sense that it seems somewhat limited. The code appears to search for each item depending on what line it is. The searched value in column 0 and the replace value in column 1 of row 0… will only replace those values for the FIRST line in the file. The DataGridViews second row values will search/replace only the SECOND line and so on. This seems odd.
Example the two string arrays (column0 and column1) have sizes set to the number of rows in dgvMapping. Let’s say there are 5 rows in the grid, then the array sizes will be 5 strings. When you start the loop to write the strings, the loop starts at 0 and stops at the number of lines in the file. The code uses this i variable as an index into the two arrays. If there are more lines in the file, than there are rows in the grid… then you will get the error.
Again, this seems odd to do the search and replace this way. Assuming you want to search for EACH term in all the rows in column 0 and replace the found searched string with the replace string in column 1, then you will need to loop through EACH row of the grid for EACH line in the file. This will replace ALL the search/replace terms in the grid with ALL the lines in the file. If this is what you what to accomplish below is one way to achieve this, however…there are possibly better ways to accomplish this.
The code below reads the file into one big string. Then the code loops through ALL the grid rows to search/replace the strings in the big string. Hope this helps.
string bigString = File.ReadAllText(ofd.FileName);
try {
using (StreamWriter sw = new StreamWriter(ofd.FileName + ".output")) {
for (int k = 0; k < dgvMapping.Rows.Count; k++) {
if (dgvMapping.Rows[k].Cells[0].Value != null && dgvMapping.Rows[k].Cells[1].Value != null) {
string searchTerm = dgvMapping.Rows[k].Cells[0].Value.ToString();
string replaceTerm = dgvMapping.Rows[k].Cells[1].Value.ToString();
if (searchTerm != "") {
bigString = bigString.Replace(searchTerm, replaceTerm);
} else {
// one of the terms is empty
}
} else {
// one of the terms is null}
}
}
sw.WriteLine(bigString);
}
}
catch (Exception ex) {
MessageBox.Show("Write Erro: " + ex.Message);
}

Delete, copy, and paste string in an array in a text file to a new arry in a text file

I need some help with file streaming. I have a program that will record names into a string array that will be written to a .txt file. Then if a user wants to delete a specific string from the array in the .txt file. the program will search for the string in the array in the .txt file, copy all the lines in the .txt file except the matching string. Then, paste all of the lines in a temp .txt file except the 1 matching string. Then copy and paste all of the string lines in the temp .txt file back to the original .txt file and then delete the temp file.
The issue that i am having is, i can't figure out how to copy all of the string lines to the temp .txt file. I know that they are not getting copied because i am use a listbox (for diagnostic reasons) to output everything in the temp file, but nothing ever get displayed. I even F8 through the whole process and it seems like its writing, but it really isnt. I cant even start thinking about the rest of the programing until this part is solved and i need to know why it isnt writing to the temp file. Any help you provide would be really help. Thank you again.
string[] names = File.ReadAllLines("name.txt");
string fullName, firstName, lastName;
fullName = tbInput.Text.ToUpper();
double Fullname;
int space;
int fullNameLength;
if (fullName.Contains(" "))
{
//This is for the Last name//
space = fullName.IndexOf(" ");
fullNameLength = fullName.Length;
space++;
lastName = fullName.Substring(space, fullNameLength - space);
//This is for the first name//
firstName = fullName.Substring(0, space);
fullName = lastName + "," + firstName;
//If the input name is valid, then it will procceed to the next if statment//
Array.Sort(names);
//if the fullname matches a string in the array, get the position. If no match is found then name was never recorded//
int Position = Array.IndexOf(names, fullName);
//Since arrays start at 0, if a position is found, the position WILL be greater than -1, so run the if statment//.
if (Position > -1)
{
//Please ingnore these 2 lines, these are a work in progress for when i can move onto the next step of deletion and what not.//
// FileStream name = new FileStream("name.txt", FileMode.Open, FileAccess.Write);
//StreamWriter write = new StreamWriter(name);
//I want to Open the Temps.txt file and seek the last line in the file to indicate where it need to write the next string//
//while looping through the array "names"//
for (int i = 0; i < names.Length; i++)
{
//While looping through the array, "i" will increase by 1 each time the loop runs, when "i" equals the position(or index)//
//skip it. For everything else, read the line of the current index in the arry and write it to the temp.txt file//
if (i == Position)
{
names.Skip(Position);
}
else
{
FileStream sw = new FileStream("Temp.txt", FileMode.Append, FileAccess.Write);
StreamWriter write2 = new StreamWriter(sw);
string input = names[i];
write2.WriteLine(input);
sw.Close();
}
}
//This part is used to loop through the temp file and output to a temp listbox to see if data is actually writing//
string[] Temp = File.ReadAllLines("Temp.txt");
for (int j = 0; j < Temp.Length; j++)
{
lbtest.Items.Add(Temp[j]);
}
I added many comments so everyone can get something of an understanding of my thought process.
Why bother with the temp file? Since you're doing a File.ReadAllLines() store that result in a List<string>. Perform an IndexOf() check is in the List and remove it if it's greater than -1 (You're doing that with your Position variable). Then use File.WriteAllLines() and give it your list.
List<string> names = new List<string>(File.ReadAllLines("name.txt"));
string fullName = tbInput.Text.ToUpper();
int fullNameIndex = names.IndexOf(fullName);
if (fullNameIndex > -1)
{
names.RemoveAt(fullNameIndex);
}
File.WriteAllLines("name.txt", names);

How can I copy an Array to another minus user specified Elements AND write and replace the new list the a .txt file

Here is what I have so far, obviously you can subtract arrays the way i did. And I also need to know how to write the new list to a .txt file that i already have ("records.txt")
public static int deleteRecord(string num)
{
int amount;
int.TryParse(num, out amount);
string[] arrayRecords = File.ReadAllLines("Records.txt").ToArray();
string[] newArrayRecords = arrayRecords - arrayRecords[amount];
for (int i = 0; i < amount; i++)
{
Console.WriteLine(newArrayRecords[amount]);
}
Console.WriteLine(amount);
return amount;
}
I assume that you want to delete a particular value from a file and that is why you have chosen the "num" parameter to be a string.
If so then this will work:
public static void deleteRecord(string num)
{
var lines = File.ReadAllLines("Records.txt").ToList();
if (lines.Remove(num) == true)
{
File.WriteAllLines("Records.txt", lines.ToArray<string>());
}
}
There are a couple of things to point out in your code. Firstly in your example, if you couldn't convert num to an int then you would be trying to remove the value of 0 from your file - which you may not want.
Secondly File.ReadAllLines already returns an Array of strings, so you don't need the .ToArray() at the end. In fact that converts the string[] array to an object[] array - which is not what you want.
I've converted it to a List as they are easier to work with. I only save the file if the item has been removed.
Hope that helps...
I presume that you want to remove the line that contains specified amount, if so you can try this:
var lines = File.ReadLines("Records.txt")
.Where(x => !x.Contains(amount.ToString());
// this will replace all prev. lines with the new ones
File.WriteAllLines("Records.txt", lines);
If you want to remove all lines that comes before this line then you can try:
var allLines = File.ReadLines("Records.txt");
var line = allLines.Where(x => x.Contains(amount.ToString()).First();
var lineIndex = allLines.IndexOf(line);
File.WriteAllLines("Records.txt",lines.GetRange(lineIndex, allLines.Count - lineIndex));
Ofcourse that answer assumes that there is line that contains amount.If there isn't then second code snippet could possibly throw exception.

Categories