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 = "";
Related
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);
}
this is what the text file is the final digit is the ID. it is for a mock atm machine.the id is brought in threw a text file. So I need to search the file for the final number then change just that line.then reprint the text file. I am new to C# and coding and any help would be appreciated.
user1,1111,1000.00,15000.00,1
user2,2222,2000.00,25000.00,2
user3,3333,3000.00,35000.00,3
int i = 0,
int j = 0;
string[,] result = new string[3, 5];//call the 2d array
foreach (var row in file.Split('\n'))//split file into the rows or lines
{
j = 0;
foreach (var col in row.Trim().Split(','))//split the ,.
{
result[i, j] = Convert.ToString(col.Trim());
j++;
}
i++;
}
int b = 0;
while(b<3)
{
if (id == result[b, 5])//looking for the number from id in result.
{
result[b, 2] = cheq;//change the proper place with a variable that works from another text file
result[b, 3] = save;//change the proper place with a variable that works from another text file
}
b++;
}
MessageBox.Show(result[2,3]);
this is all done in forms in visual studio I am getting an exceptions error pop up index was outside the bounds of the array. If there is a better way to do all this I am all ears. I am a student and the goal is to save the changes the person made while in the atm machine to a text file when they press exit.
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 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);
}
I am trying to write a bubble sort on a large text file that has 1 column of numbers that are all between 1 and 99. I want to sort it without bringing the contents or the data in memory at the same time. I used a loop of 20 passes to get the logic down before I do this on the whole file. I am using streamreader and streamwriter to receive and send the numbers back and forth so only 2 numbers are processed at any one time. the numbers in the text file are coded int32.I converted them in the writing process. I have been unable to populate the "sorted" file with the data. Here is my code:
static void BubbleSort()
{
int bubbleOut, bubbleIn;
StreamReader readToSort = new StreamReader(#"C:Random # File.txt");
StreamWriter writeSorted = new StreamWriter(#"C:Sorted_File.txt");
bubbleIn = readToSort.Read();
bubbleOut = readToSort.Read();
for (bubbleIn = 1; bubbleIn <= 20; bubbleIn++)
{
for (bubbleOut = bubbleIn; bubbleIn < bubbleOut; bubbleOut++ )
{
if (bubbleOut > bubbleIn)
{
int temp = bubbleIn;
bubbleIn = bubbleOut;
bubbleOut = temp;
writeSorted.WriteLine(bubbleIn);
writeSorted.WriteLine(bubbleOut);
}
}
}
}
First of all, for large data sets you better use MergeSort because it is much faster (O(n log n)) than BubbleSort (O(n * n)).
Besides that, you are only reading the first two characters of the inputstream and after reading the data, you override the value in the for-loop.
I think you first have to copy the entire content of in input file, to the output file. Then you need a way to swap 2 characters in the output stream. After that, you can run the bubblesort algorithm on the inputfile and apply the swap on the output file.
Your for-loop should look something like:
// TODO: Copy input to output
for (int sortedElement = 0; sortedElement < StreamLength; sortedElement++)
{
// You don't have to loop till the end of the stream. Last
// character is sorted on each iteration.
for (int index = 0; index < StreamLength - sortedElements - 1; index++)
{
// read character from input stream at position 'index' as leftValue
// read character from input stream at position 'index+1' as rightValue
if (rightValue < leftValue)
{
// Perform swap values in outputfile
}
}
}
That should be it.