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);
}
Related
I'm reading a text file that contains continents , countries , capitals and the population of those countries. Here is the text file image of file with info. I then input a value , let's say I input "Birmanie" the StreamReader instance then takes the info from the NEXT line which would be "Bolivie". "Pays" is the input. My goal is to read the line of the country that the user inputs and then later on extract the info from that line.
Here's my code.
while (!srRecherche.EndOfStream)
{
lireLigneRechercher = srRecherche.ReadLine();
if (lireLigneRechercher.IndexOf(Pays,StringComparison.CurrentCultureIgnoreCase) >= 0)
{
for (int i = 1; i <= 35; i++)
{
lireCharacteres += (char)srRecherche.Read();
}
for (int i = 1; i <= 74; i++)
{
srRecherche.Read();
}
}
}
The for loops are there so that I can skip through the rest of the information and only read the country's name.
Here is an example that might help. The numbers (index positions on the lines) are completely made up, but hopefully you'll see where I'm going. Instead of trying to read with a reader, I would read all the lines and put them into a collection of some sort. I used a struct and a HashSet below, but you could use a class and a List, or a SortedSet, or a Collection, or many other options. By transforming each line into a struct/class, you gain the liberty of doing any sort of analysis or manipulation you want without having to back-track. Since your data seems relatively fixed, you can also gain some advantage by storing the entire list in memory and then finding (in your cached list) what the user asks for with a Where() or FirstOrDefault() instead of reading the file with each new input.
class Program
{
static void Main(string[] args)
{
string userInput = "Birmanie";
var lines = File.ReadAllLines("c:\\myfile.txt");
HashSet<FileLine> fileLines = new();
foreach (var line in lines)
{
var fileLine = new FileLine()
{
Country = line.Substring(0, 25).Trim(),
City = line.Substring(35, 20).Trim(),
Population = Convert.ToInt32(line.Substring(55, 20).Trim()),
Continent = line.Substring(75).Trim()
};
fileLines.Add(fileLine);
}
int pop = fileLines.FirstOrDefault(l => l.City == userInput).Population;
}
}
struct FileLine
{
public string Country;
public string City;
public int Population;
public string Continent;
}
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.
I have a program that is almost done. The issue is that when I print out the "new" CSV file every thing is correct except the very first column in excel. It is printing the information twice but only in the first column. I have looked throughout my code and am unable to see where I would be printing it out twice or calling the token twice.
The purpose of the program is to simply re-organize the columns and format them into a desired manner. The token I am accessing is at position inputBuffer[23] and I have it set to be equal to outputBuffer[0] and I only do this 1 time but when I run the program and check the file, the first column of the first record should hold the value 841 but instead it is coming up 841841 and I have no clue how. All of the other columns are perfectly fine.
Can anyone spot what's wrong?
My Method
/*
* This method uses the fields (array elements) in the output
* buffer to assemble a CSV record (string variable). The
* CSV record is then written to the output file.
*/
public static void BuildRecordAndWriteOutput()
{
string record = outputBuffer[0];
for (int i = 0; i < outputBuffer.Length; i++)
{
if (outputBuffer[i].Contains(","))
{
string x = "\"" + outputBuffer[i] + "\"";
record += x;
}
else
{
record += outputBuffer[i];
}
if (i < outputBuffer.Length - 1)
{
record += ",";
}
}
/*for (int i = 1; i < outputBuffer.Length; i++)
{
record = record + "," + outputBuffer[i];
}*/
output.WriteLine(record);
}
When I call the method
static void Main(string[] args)
{
input.SetDelimiters(",");
/*
* This loop reads input data and calls methods to
* build an output record and write data to a CSV file.
*/
while (!input.EndOfData)
{
inputBuffer = input.ReadFields(); // Read a CSV record in to the inputBuffer.
SetOutputBufferDefaultValues(); // Put default values in the output buffer.
MapInputFieldsToOutputFields(); // Move fields from the input buffer to the output buffer.
BuildRecordAndWriteOutput(); // Build record from output buffer and write it.
}
Console.WriteLine("done");
input.Close();
output.Close();
Console.Read();
}
Here is a screenshot in case my explanation was not clear
There is more data to the code and I have not posted it all , as of now, but I can if it will help.
Thanks!
in your BuildRecordAndWriteOutput, you assign record:
string record = outputBuffer[0];
then start your loop at 0, appending outputbuffer[0] to record:
for (int i = 0; i < outputBuffer.Length; i++)
{
record += ....
}
That's what's causing your first column to have the data duplicated.
You can fix this by simply initializing your record to an empty string before the loop:
string record = "";
Given a data text file which looks like
21,7,11
20,10,12
17,7,18
These represent height, temperature and carbon percentage.
I have read in the file as a .txt file using system.io. Is this correct? from here how would I calculate the maximum temperature?
{
string s;
System.IO.StreamReader inputFile = new System.IO.StreamReader(DataFile);
s = inputFile.ReadLine();
int noDataLines = int.Parse(s);
}
You need to read all the lines and compare each value to find out max temperature.
Something like below (untested code!) should be done. There are lot of assumptions in this code and you may have to change it to suit your case.
{
string s;
int maxValue=-1, temp=-1;
using(System.IO.StreamReader in = new System.IO.StreamReader(DataFile))
{
while (in.Peek() >= 0)
{
s = in.ReadLine();
if(int.tryParse(s.split(",")[1], out temp)
{
if(temp>maxValue)
maxValue = temp;
}
}
}
}
You will most likely want to create a two-dimensional list or array, and in this example I am using a list.
{
List<List<int>> intList = new List<int>(); // This creates a two dimensional list.
System.IO.StreamReader inputFile = new System.IO.StreamReader(DataFile);
string line = inputFile:ReadLine();
while (line != null) // Iterate over the lines in the document.
{
intList.Add( // Adding a new row to the list.
line.Split(',').Select(int.Parse).ToList()
// This separates the line by commas, and turns it into a list of integers.
);
line = inputFile:ReadLine(); // Move to the next row.
}
}
I will admit that this is certainly not a very concise method of doing it, but it is relatively straightforward.
To access it, do this:
int element = intList[1, 2]; // Accessing 2nd row, 3rd column.
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);