C# Reader Text File, Search for String, Overwrite Line - c#

I'm attempting to read a text file if it exists and then search for a specific string at the beginning of each line. If it exists, I want to overwrite that line with newly input variables. I'm getting an error when the Enter/Update Player button is clicked. I've noted in the code where the error occurs.
The error I receive:
"The process cannot access the file because it is being
used by another process. "
I'm assuming this is related to StreamReader/StreamWriter interference, but I can't figure out where the error is coming from. Any help would be greatly appreciated!
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Text;
using System.Windows.Forms;
namespace Namespace1
{
public partial class FormPokerStats : Form // FormPokerStats inheriting from class Form
{
// declaring and assigning of variables needed for file read/write
const char DELIM = ',';
const string FILEPATH = #"C:\C# Project Output\";
const string FILENAME = "PokerPlayers.txt";
// declaring instances of Person, Location, and Winnings classes
Location mycasino = new Location();
Winnings mywinnings = new Winnings();
public delegate void Total(double[] total);
// constructing in/out FileStream/StreamReader/StreamWriter objects
static FileStream inFile = new FileStream(FILEPATH + FILENAME, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite);
StreamWriter writer = new StreamWriter(outFile);
static FileStream outFile = new FileStream(FILEPATH + FILENAME, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
StreamReader reader = new StreamReader(inFile);
public FormPokerStats()
{
InitializeComponent();
}
// "Enter/Update Player" tab Enter Player button: read/assign user input, write to file, close file stream
private void buttonEnterPlayer_Click(object sender, EventArgs e)
{
Player myplayer = null;
// if directory does not exist, create it
if (!(Directory.Exists(FILEPATH)))
{
// create directory
Directory.CreateDirectory(FILEPATH);
}
try
{
// read user input and assign to variables; test for empty player inputs and reprompt for input, if necessary
// Player Information fields
// if any or all textboxes are left blank
if ((maskedTextBoxSSN.Text == String.Empty || textBoxFirstName.Text == String.Empty || textBoxLastName.Text == String.Empty
|| textBoxCasinoName.Text == String.Empty || textBoxCasinoState.Text == String.Empty) ||
(maskedTextBoxSSN.Text == String.Empty && textBoxFirstName.Text == String.Empty && textBoxLastName.Text == String.Empty
&& textBoxCasinoName.Text == String.Empty && textBoxCasinoState.Text == String.Empty))
{
MessageBox.Show("Please complete all player information fields.", "Input Error!");
}
else
{
// if all textboxes are completed, assign to variables
myplayer = new Player(maskedTextBoxSSN.Text, textBoxFirstName.Text, textBoxLastName.Text);
mycasino.CasinoName = textBoxCasinoName.Text;
mycasino.CasinoState = textBoxCasinoState.Text;
}
// read weekly winnings input and assign to appropriate array position; test for empty inputs and assign default value of 0 if empty
// Week1
if (textBoxWeek1Winnings.Text == String.Empty)
{
mywinnings.AddNewWinnings(0, 0);
}
else mywinnings.AddNewWinnings(0, Convert.ToDouble(textBoxWeek1Winnings.Text));
// Week2
if (textBoxWeek2Winnings.Text == String.Empty)
{
mywinnings.AddNewWinnings(1, 0);
}
else mywinnings.AddNewWinnings(1, Convert.ToDouble(textBoxWeek2Winnings.Text));
// Week3
if (textBoxWeek3Winnings.Text == String.Empty)
{
mywinnings.AddNewWinnings(2, 0);
}
else mywinnings.AddNewWinnings(2, Convert.ToDouble(textBoxWeek3Winnings.Text));
// Week4
if (textBoxWeek4Winnings.Text == String.Empty)
{
mywinnings.AddNewWinnings(3, 0);
}
else mywinnings.AddNewWinnings(3, Convert.ToDouble(textBoxWeek4Winnings.Text));
// Week5
if (textBoxWeek5Winnings.Text == String.Empty)
{
mywinnings.AddNewWinnings(4, 0);
}
else mywinnings.AddNewWinnings(4, Convert.ToDouble(textBoxWeek5Winnings.Text));
// Week6
if (textBoxWeek6Winnings.Text == String.Empty)
{
mywinnings.AddNewWinnings(5, 0);
}
else mywinnings.AddNewWinnings(5, Convert.ToDouble(textBoxWeek6Winnings.Text));
// Week7
if (textBoxWeek7Winnings.Text == String.Empty)
{
mywinnings.AddNewWinnings(6, 0);
}
else mywinnings.AddNewWinnings(6, Convert.ToDouble(textBoxWeek7Winnings.Text));
// Week8
if (textBoxWeek8Winnings.Text == String.Empty)
{
mywinnings.AddNewWinnings(7, 0);
}
else mywinnings.AddNewWinnings(7, Convert.ToDouble(textBoxWeek8Winnings.Text));
// calculate total winnings by summing WeeklyWinnings array values and assigning to TotalWinnings
Total pointer = null;
pointer += new Total(mywinnings.compileTotal);
pointer(mywinnings.WeeklyWinnings);
///////////////////////////////////ERROR HERE////////////////////////////////////
// check file for input SSN; if exists, overwrite that record and rewrite to file
if (!(File.Exists(FILEPATH + FILENAME)))
{
List<string> lines = new List<string>(File.ReadAllLines(FILEPATH + FILENAME));
int lineIndex = lines.FindIndex(line => line.StartsWith(myplayer.SocialSecurityNumber));
if (lineIndex != -1)
{
lines[lineIndex] = myplayer.ToString() + mycasino.ToString() + mywinnings.ToString();
File.WriteAllLines(FILEPATH + FILENAME, lines);
}
else
{
// writing record to text file
writer.WriteLine(myplayer.ToString() + mycasino.ToString() + mywinnings.ToString());
}
}
// if record is successfully written, display messagebox
MessageBox.Show("Wrote " + myplayer.FirstName.ToString() + ' ' + myplayer.LastName.ToString() + " to file with winnings totaling " + mywinnings.TotalWinnings.ToString("C2") + ".", "File Written");
}
catch (FormatException)
{
// if format exception is thrown in try, display messagebox with message
MessageBox.Show("Winnings must be entered at xx.xx (e.g. 34.56).", "Input Error!");
}
catch (Exception f)
{
// if exception is thrown in try, display messagebox with message
MessageBox.Show(f.Message, "Error!");
}
// clear form textboxes
ClearTextBoxes();
maskedTextBoxSSN.Clear();
writer.Close();
}
// "Enter/Update Player" tab Exit button: closes file streams and quits the application
private void buttonExit_Click(object sender, EventArgs e)
{
// closing file streams
reader.Close();
inFile.Close();
writer.Close();
outFile.Close();
// close application
Application.Exit();
}
// "Player List" tab View Player Winnings button: read file records, display records sorted by total winnings descending
private void buttonRead_Click(object sender, EventArgs e)
{
// clear listbox items
listBoxOutputRecords.Items.Clear();
// if file exists
if (!(File.Exists(FILEPATH + FILENAME)))
{
// if file does not exist, display messagebox
MessageBox.Show("File does not exist.", "File Does Not Exist!");
}
else
{
string[] fields;
// output header row labels to listbox
listBoxOutputRecords.Items.Add("First Name\tLast Name\tCasino Name\tCasino State\tTotal Winnings\t");
// read first record in file
string recordIn = reader.ReadLine();
// instantiate an instance of playerList list of tuples
List<Tuple<string, string, string, string, double>> playerList = new List<Tuple<string, string, string, string, double>>();
// loop through text file records until last record is reached
while (recordIn != null)
{
// split record into array and assign
fields = recordIn.Split(DELIM);
Player myplayer = new Player(fields[0], fields[1], fields[2]);
mycasino.CasinoName = fields[3];
mycasino.CasinoState = fields[4];
mywinnings.TotalWinnings = Convert.ToDouble(fields[13]);
// add player to the playerList list of tuples
playerList.Add(new Tuple<string, string, string, string, double>(myplayer.FirstName, myplayer.LastName, mycasino.CasinoName, mycasino.CasinoState, mywinnings.TotalWinnings));
// read next record in file
recordIn = reader.ReadLine();
}
// sort playerList list of tuples by total winnings descending
playerList.Sort((a, b) => b.Item5.CompareTo(a.Item5));
// display each record of the playerList list of tuples in the listbox
foreach (var element in playerList)
{
listBoxOutputRecords.Items.Add(element.Item1 + "\t\t" + element.Item2 + "\t\t" + element.Item3 + "\t\t" + element.Item4 + "\t\t" + element.Item5.ToString("C2"));
}
}
// return file position to 0
inFile.Seek(0, SeekOrigin.Begin);
}
// "Player List" tab Exit button: call buttonExit_Click method
private void buttonExit2_Click(object sender, EventArgs e)
{
// call buttonExit_Click method
buttonExit_Click(sender, e);
}
// method to clear listbox items when "Player List" tab is left
private void tabPagePlayerList_Leave(object sender, EventArgs e)
{
// clear listbox items
listBoxOutputRecords.Items.Clear();
}
// method to clear textbox controls
private void ClearTextBoxes()
{
Action<Control.ControlCollection> func = null;
func = (controls) =>
{
foreach (Control control in controls)
if (control is TextBox)
(control as TextBox).Clear();
else
func(control.Controls);
};
func(Controls);
}
}

As I can see, you're closing all the streams on existing the application. You need to close the streams as soon as you have used them. For example, once you have read the file contents to reader, you can close file stream. Similarly, when you have moved the reader stream to writer stream, you need to close the reader stream right away.
Your above error is surely occurring due to some open stream. So to make sure file is not somehow being accessed by another process, just close your streams as soon as they're used. Try this and if further help required, do share.

Related

Reading from file and writing to a temporary .txt file in C#?

I know there are a lot of similar topics on this website, but I think that I went through most of them and still cannot debug this piece of code. I really need to get this working. I'm newbie to C# and programming. Tho, I did this same assignment in Java, but for some reason, I can't make it work here. If some could please pitch in...
So I have some objects, which I am keeping in .txt file, one line = data for one object. First data of the line is an Id of an object, primary key basically. Right now I am implementing CRUD operations, that is, an Update. This edit function is supposed to contribute to that functionality.
If a user edit some of the selected object properties, that change needs to be reflected in .txt file. So, I will go through every object/line in the file, write them to some temp.txt file, once I hit object which has same Id as the passed object o, that means I need to write that edited object to temp.txt. After that I need to rename temp.txt to original file and delete temp.txt.
I have tried bunch of options and combinations, but none worked.
I really make sure that GetTxtPath returns correct absolute path from within my project.
Version 1:
public static void edit(Transformable o, string fileName)
{
try
{
if (!File.Exists(FileUtils.GetTxtPath("temp.txt")))
{
File.Create(FileUtils.GetTxtPath("temp.txt"));
}
using (FileStream stream = File.OpenRead(FileUtils.GetTxtPath(fileName)))
using (FileStream writeStream = File.OpenWrite(FileUtils.GetTxtPath("temp.txt")))
{
StreamReader reader = new StreamReader(stream);
StreamWriter writer = new StreamWriter(writeStream);
String line;
while ((line = reader.ReadLine()) != null)
{
if (!line.Equals(""))
{
if (o.GetId() == getIdFromString(line))
{
writer.Write(o.WriteToFile());
}
else
{
writer.Write(line + "\n");
}
}
else
{
continue;
}
}
}
}
catch (FileNotFoundException e)
{
Console.WriteLine($"The file was not found: '{e}'");
}
catch (DirectoryNotFoundException e)
{
Console.WriteLine($"The directory was not found: '{e}'");
}
catch (IOException e)
{
Console.WriteLine($"The file could not be opened: '{e}'");
}
}
public static string GetTxtPath(string fileName)
{
var startDirectory =
Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName;
var absPath = startDirectory + #"\data\" + fileName;
return absPath;
}
private static int getIdFromString(string line)
{
return Int32.Parse(line.Split('|')[0]);
}
Version 2:
public static void Edit(Transformable o, string fileName)
{
try
{
if (!File.Exists(FileUtils.GetTxtPath("temp.txt")))
{
File.Create(FileUtils.GetTxtPath("temp.txt"));
}
using (StreamReader reader = FileUtils.GetTxtReader(fileName))
using (StreamWriter writer = FileUtils.GetTxtWriter("temp.txt"))
{
String line;
while ((line = reader.ReadLine()) != null)
{
if (!line.Equals(""))
{
if (o.GetId() == getIdFromString(line))
{
writer.Write(o.WriteToFile());
}
else
{
writer.Write(line + "\n");
}
}
else
{
continue;
}
}
}
File.Move(FileUtils.GetTxtPath("temp.txt"), FileUtils.GetTxtPath(fileName));
File.Delete(FileUtils.GetTxtPath("temp.txt"));
//Here I tied many differenet options but nonthing worked
//Here is Java code which did the job of renaming and deleting
//------------------------------------------------------------
// File original = FileUtils.getFileForName(fileName);
// File backUpFile = new File("backUp");
// Files.move(original.toPath(), backUpFile.toPath(),
// StandardCopyOption.REPLACE_EXISTING);
// File temporary = FileUtils.getFileForName(temporaryFilePath);
// temporary.renameTo(original);
// backUpFile.delete();
// File original = FileUtils.getFileForName(path);
//--------------------------------------------------------
//public static File getFileForName(String name)
//{
// String dir = System.getProperty("user.dir");
// String sP = System.getProperty("file.separator");
// File dirData = new File(dir + sP + "src" + sP + "data");
// File file = new File(dirData.getAbsolutePath() + sP + name);
// return file;
//}
//---------------------------------------------------------------------
}
catch (FileNotFoundException e)
{
Console.WriteLine($"The file was not found: '{e}'");
}
catch (DirectoryNotFoundException e)
{
Console.WriteLine($"The directory was not found: '{e}'");
}
catch (IOException e)
{
Console.WriteLine($"The file could not be opened: '{e}'");
}
public static StreamReader GetTxtReader(string fileName)
{
var fileStream = new FileStream(GetTxtPath(fileName), FileMode.Open, FileAccess.Read);
return new StreamReader(fileStream, Encoding.UTF8);
}
public static StreamWriter GetTxtWriter(string fileName)
{
FileStream fileStream = new FileStream(GetTxtPath(fileName), FileMode.Append);
return new StreamWriter(fileStream, Encoding.UTF8);
}
public static void Edit(Transformable o, string fileName)
{
try
{
string tempName = "temp.txt"; // create here correct path
using (var readStream = File.OpenRead(fileName))
using (var writeStream = File.OpenWrite(tempName))
using (var reader = new StreamReader(readStream))
using (var writer = new StreamWriter(writeStream))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (!line.Equals(""))
{
if (o.GetId() == GetId(line))
{
writer.WriteLine(o.ToWriteableString());
}
else
{
writer.WriteLine(line);
}
}
}
}
File.Delete(fileName);
File.Move(tempName, fileName);
}
catch ...
}
File.OpenWrite method opens an existing or creates a new file for writing. So there is no need to manually check and create the file.
You have wrapped FileStreams in a using statement quite correctly. However, StreamReader and StreamWriter also must to be released after use.
I renamed some methods, giving them names that conform to the naming rules in C#: Edit, GetId, ToWriteableString.
The else branch with the continue statement is not needed.
In the end, just use the File.Delete and File.Move methods.
Note: the int.Parse method can throw exceptions that also need to be handled.

How to ignore first two columns of CSV file

I'm trying to read a .csv file, that contains students names, students IDs, and many columns of grades and use that information to write lines in a listbox that look like this John --> 12345 --> 89.50, where the first value is student name, the second value is student id, and the third value is an average of the test scores.
I'm able to read the file and assign token[0] to name and token1 to ID, I just can't figure out how to get the remain values (grades) from a string to a double, so that I can do the math to get the averages.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace McKensey
{
//struct for students name, ID, grades
struct Student
{
public string name;
public string ID;
public string grade;
}
public partial class Form1 : Form
{
//feild to hold a list of GradeEntry
private List<Student> gradeList = new List<Student>();
public Form1()
{
InitializeComponent();
}
//the ReadFile method reads thecontents of the .csv test and stores
//it as Student objects in gradeList
private void ReadFile()
{
StreamReader inputFile; //to read the file
string line; //to hold a line from the file
double grade;
double total = 0;
//creat a instance of the Student structure
Student entry = new Student();
//create a delimiter array
char[] delim = { ',' };
//open the .csv file
if (openFile.ShowDialog() == DialogResult.OK)
{
//open the selected file
inputFile = File.OpenText(openFile.FileName);
//read the files data
while (!inputFile.EndOfStream)
{
//read the lines from the file
while (!inputFile.EndOfStream)
{
line = inputFile.ReadLine();
//tokenize the line
string[] tokens = line.Split(delim);
entry.name = tokens[0];
entry.ID = tokens[1];
gradeList.Add(entry);
}
}
//close file
inputFile.Close();
}
else
{
MessageBox.Show("Opertaion Canceled.");
}
}
private void DisplayInfo()
{
foreach (Student entry in gradeList)
{
listBox1.Items.Add(entry.name + "-->" + entry.ID + "-->" + entry.grade);
}
}
private void processButton_Click(object sender, EventArgs e)
{
ReadFile();
DisplayInfo();
}
}
}
You can simply do this:
IEnumerable<string> strCSV =
File.ReadLines(#"C:\\Users\\xxx\\Desktop\\Book1.csv");
var results = from str in strCSV
let tmp = str.Split(',')
.Skip(2) // skip the first two columns
.Select(q => Convert.ToInt32(q))
select new
{
Max = tmp.Max(),
Min = tmp.Min(),
Total = tmp.Sum(),
Avg = tmp.Average()
};
var query = results.ToList();
foreach (var q in query)
{
Console.WriteLine(
string.Format("Maximum: {0}, " +
"Minimum: {1}, " +
"Total: {2}, " +
"Average: {3}",
q.Max, q.Min, q.Total, q.Avg));
}
If the third column is your grade column, it is needed to be like this
entry.name = tokens[0];
entry.ID = tokens[1];
entry.grade = Convert.ToDouble(tokens[2]);
edit: I fixed the string to double conversion
when we trace your code piece which reads file,
Reading line with line = inputFile.ReadLine();
Splitting line to the pieces
here you are transforming line string to array of strings with the delimiter ,
arrays start from position 0 goes until Length - 1 (your csv file has 7 colums so your array starts from 0 and ends at 6)
then reads everyline with tokens[column_number]
ATTENTION
your code has two while conditions while (!inputFile.EndOfStream) which does not make sense. only 1 while condition is enough for reading single file. remove the outer while condition.
EDIT
you need to either change your Student.grade property to double and use entry.grade = Convert.ToDouble(tokens[2]); or keep it string and use entry.grade = tokens[2]
struct Student
{
public string name;
public string ID;
public double grade; //this line has modification
}
If you want the rest from Double into String then you can do it something like:
entry.grade = double.Parse(tokens[2]).ToString() + ',' + double.Parse(tokens[3]).ToString() + ',' + double.Parse(tokens[4]).ToString() + ',' + double.Parse(tokens[5]).ToString() + ',' + double.Parse(tokens[6]).ToString();
You can wrap it with try catch if you want to handle the error.

How to override a specific line in a text file in c#

I have the following situation. I am creating a quiz game in c# visual studio and want to create a Register and Login forms. When a user registers a new account the text file will store their username and password and will set the high score to 0. Each line in the text file looks like that: username;password;highscore. ';' is the delimiter. I have created a new project to create a practice login/ register form. Here is my code for the register form:
private void btnRegister_Click(object sender, EventArgs e)
{
if (txtPassword.Text == txtConfirmPassword.Text)
{
string newAccount = txtName.Text + ";" + txtConfirmPassword.Text + ";" + "0";
TextWriter account = new StreamWriter("../../TextFile/LogonDetails.txt", true);
account.WriteLine(newAccount);
account.Close();
MessageBox.Show("Account created");
}
and here is my code for the login form
string line = "";
StreamReader myReader = new StreamReader("../../TextFile/LogonDetails.txt");
string[] accounts = new string[900000]; int value = 0;
while ((line=myReader.ReadLine()) != null)
{
string[] data = line.Split(';');
if ((data[0] == txtLoginName.Text) && (data[1] == txtLoginPassword.Text) && (int.Parse(data[2]) > int.Parse(txtScore.Text)))
{
value = 1;
break;
}
if ((data[0] == txtLoginName.Text) && (data[1] == txtLoginPassword.Text) && (int.Parse(data[2]) < int.Parse(txtScore.Text)))
{
value = 2;
break;
}
else
{
value = 3;
}
}
if (value == 1)
{
MessageBox.Show("Your score remains the same");
}
else if (value == 2)
{
string updatedAccount = txtLoginName.Text + ";" + txtLoginPassword.Text + ";" + txtScore;
TextWriter textAccounts = new StreamWriter("../../TextFile/LogonDetails.txt");
textAccounts.WriteLine(updatedAccount);
textAccounts.Close();
}
else if (value == 3)
{
MessageBox.Show("Account not found");
}
}
So my question is how can I override the line stored in the text file if in this case 'txtScore' is greater than data[2]? I have tried creating a new line each time the score is greater but that seems inefficient. Is there a way that i can override the line to change the score value? Any help is greatly appreciated
If the file is not that long you can do something like this:
String fileName = #"C:\LogonDetails.txt";
var data = File
.ReadLines(fileName)
.Select(line => line.Split(';'))
.Select(items => {
if ((items[0] == txtLoginName.Text) &&
(items[1] == txtLoginName.Text) &&
(int.Parse(items[2]) < int.Parse(txtScore.Text)))
items[2] = int.Parse(txtScore.Text);
return items;
})
.ToList(); // materialize in oreder to prevent file read/write collision
File.WriteAllLines(fileName, data);
There is no straightforward way to target a specific line in a text file to update the contents on that line. I would suggest storing your information in an XML (structured data) format; .NET already has the capabilities built in for reading and writing to specific nodes in an XML file.
If you don't want to do that, then my suggestion would be that you load all the lines from the text file into memory as instances of, e.g. a User class that has as properties your username, password, and score, and then write them all back out to your data file all at once with any updates to the scores.
By the way, it's generally not a good idea to store passwords in plain text, so I would hope you're at least employing a hashing algorithm.
Well, based on your question you know the line number, so do something like this:
var lines = File.ReadAllLines(#"path to file");
if (lines.Contains("1234"))
{
lines[Array.IndexOf(lines, "1234")] = "new york";
}
File.WriteAllLines(#"path to file", lines);
try like this.

"The process cannot access the file because it is being used by another process"

The full error I am receiving is:
"The process cannot access the file 'e:\Batch\NW\data_Test\IM_0232\input\RN318301.WM' because it is being used by another process.>>> at IM_0232.BatchModules.BundleSort(String bundleFileName)
at IM_0232.BatchModules.ExecuteBatchProcess()"
The involved code can be seen below. The RN318301.WM file being processed is a text file that contains information which will eventually be placed in PDF documents. There are many documents referenced in the RN318301.WM text file with each one being represented by a collection of rows. As can be seen in the code, the RN318301.WM text file is first parsed to determine the number of documents represented in it as well as the maximum number of lines in a documents. This information is then used to create two-dimensional array that will contain all of the document information. The RN318301.WM text file is parsed again to populate the two-dimensional array and at the same time information is collected into a dictionary that will be sorted later in the routine.
The failure occurs at the last line below:
File.Delete(_bundlePath + Path.GetFileName(bundleFileName));
This is a sporadic problem that occurs only rarely. It has even been seen to occur with a particular text file with which it had not previously occurred. That is, a particular text file will process fine but then on reprocessing the error will be triggered.
Can anyone help us to diagnose the cause of this error? Thank you very much...
public void BundleSort(string bundleFileName)
{
Dictionary<int, string> memberDict = new Dictionary<int, string>();
Dictionary<int, string> sortedMemberDict = new Dictionary<int, string>();
//int EOBPosition = 0;
int EOBPosition = -1;
int lineInEOB = 0;
int eobCount = 0;
int lineCount = 0;
int maxLineCount = 0;
string compareString;
string EOBLine;
//#string[][] EOBLineArray;
string[,] EOBLineArray;
try
{
_batch.TranLog_Write("\tBeginning sort of bundle " + _bundleInfo.BundleName + " to facilitate householding");
//Read the bundle and create a dictionary of comparison strings with EOB position in the bundle being the key
StreamReader file = new StreamReader(#_bundlePath + _bundleInfo.BundleName);
//The next section of code counts CH records as well as the maximum number of CD records in an EOB. This information is needed for initialization of the 2-dimensional EOBLineArray array.
while ((EOBLine = file.ReadLine()) != null)
{
if (EOBLine.Substring(0, 2) == "CH" || EOBLine.Substring(0, 2) == "CT")
{
if (lineCount == 0)
lineCount++;
if (lineCount > maxLineCount)
{
maxLineCount = lineCount;
}
eobCount++;
if (lineCount != 1)
lineCount = 0;
}
if (EOBLine.Substring(0, 2) == "CD")
{
lineCount++;
}
}
EOBLineArray = new string[eobCount, maxLineCount + 2];
file = new StreamReader(#_bundlePath + _bundleInfo.BundleName);
try
{
while ((EOBLine = file.ReadLine()) != null)
{
if (EOBLine.Substring(0, 2) == "CH")
{
EOBPosition++;
lineInEOB = 0;
compareString = EOBLine.Substring(8, 40).Trim() + EOBLine.Substring(49, 49).TrimEnd().TrimStart() + EOBLine.Substring(120, 5).TrimEnd().TrimStart();
memberDict.Add(EOBPosition, compareString);
EOBLineArray[EOBPosition, lineInEOB] = EOBLine;
}
else
{
if (EOBLine.Substring(0, 2) == "CT")
{
EOBPosition++;
EOBLineArray[EOBPosition, lineInEOB] = EOBLine;
}
else
{
lineInEOB++;
EOBLineArray[EOBPosition, lineInEOB] = EOBLine;
}
}
}
}
catch (Exception ex)
{
throw ex;
}
_batch.TranLog_Write("\tSending original unsorted bundle to archive");
if(!(File.Exists(_archiveDir + "\\" +DateTime.Now.ToString("yyyyMMdd")+ Path.GetFileName(bundleFileName) + "_original")))
{
File.Copy(_bundlePath + Path.GetFileName(bundleFileName), _archiveDir + "\\" +DateTime.Now.ToString("yyyyMMdd")+ Path.GetFileName(bundleFileName) + "_original");
}
file.Close();
file.Dispose();
GC.Collect();
File.Delete(_bundlePath + Path.GetFileName(bundleFileName));
You didn't close/dispose your StreamReader first time round so the file handle is still open
Consider using the using construct - this will automatically dispose of the object when it goes out of scope:
using(var file = new StreamReader(args))
{
// Do stuff
}
// file has now been disposed/closed etc
You need to close your StreamReaders for one thing.
StreamReader file = new StreamReader(#_bundlePath + _bundleInfo.BundleName);
You need to close the StreamReader object, and you could do this in a finally block:
finally {
file.Close();
}
A better way is to use a using block:
using (StreamReader file = new StreamReader(#_bundlePath + _bundleInfo.BundleName)) {
...
}
It looks to me like you are calling GC.Collect to try to force the closing of these StreamReaders, but that doesn't guarantee that they will be closed immediately as per the MSDN doc:
http://msdn.microsoft.com/en-us/library/xe0c2357.aspx
From that doc:
"All objects, regardless of how long they have been in memory, are considered for collection;"

Reading File Records and Assigning to an Array

I'm creating a poker stats WinForm program to write player info and 8 weeks' worth of winnnings and a total winnings amount to a file and read that info to display in a form. I'm having issues reading the 8 weekly winnings amounts textboxes into my array. I receive an "Object reference not set to an instance of an object." error. I've noted in the code below where I think the error is coming from. I've included both the form code and my class code. Any ideas what I'm doing wrong? I hope I've provided enough background of the issue. Thanks in advance!!
My form code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Text;
using System.Windows.Forms;
namespace PokerStats
{
public partial class FormPokerStats : Form // FormPokerStats inheriting from class Form
{
// declaring and assigning of variables needed for file read/write
const char DELIM = ',';
const string FILEPATH = #"C:\C# Project Output\";
const string FILENAME = "PokerPlayers.txt";
// declaring instances of Person, Location, and Winnings classes
Person myplayer = new Person();
Location mycasino = new Location();
Winnings mywinnings = new Winnings();
// constructing in/out FileStream/StreamReader/StreamWriter objects
static FileStream inFile = new FileStream(FILEPATH + FILENAME, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite);
StreamWriter writer = new StreamWriter(outFile);
static FileStream outFile = new FileStream(FILEPATH + FILENAME, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
StreamReader reader = new StreamReader(inFile);
public FormPokerStats()
{
InitializeComponent();
}
// "Enter/Update Player" tab Enter Player button: read/assign user input, write to file, close file stream
private void buttonEnterPlayer_Click(object sender, EventArgs e)
{
// if directory does not exist, create it
if (!(Directory.Exists(FILEPATH)))
{
// create directory
Directory.CreateDirectory(FILEPATH);
}
try
{
// read user input and assign to variables; test for empty player inputs and reprompt for input, if necessary
// Player Information fields
// if any or all textboxes are left blank
if ((textBoxSSN.Text == String.Empty || textBoxFirstName.Text == String.Empty || textBoxLastName.Text == String.Empty
|| textBoxCasinoName.Text == String.Empty || textBoxCasinoState.Text == String.Empty) ||
(textBoxSSN.Text == String.Empty && textBoxFirstName.Text == String.Empty && textBoxLastName.Text == String.Empty
&& textBoxCasinoName.Text == String.Empty && textBoxCasinoState.Text == String.Empty))
{
MessageBox.Show("Please complete all player information fields.", "Input Error!");
}
else
{
// if all textboxes are completed, assign to variables
myplayer.SocialSecurityNumber = textBoxSSN.Text;
myplayer.FirstName = textBoxFirstName.Text;
myplayer.LastName = textBoxLastName.Text;
mycasino.CasinoName = textBoxCasinoName.Text;
mycasino.CasinoState = textBoxCasinoState.Text;
// writing record to text file
writer.WriteLine(myplayer.ToString() + mycasino.ToString());
// if record is successfully written, display messagebox
MessageBox.Show("Wrote " + myplayer.FirstName.ToString() + ' ' + myplayer.LastName.ToString() + " to file with winnings totaling " + mywinnings.TotalWinnings.ToString("C2") + ".", "File Written");
}
***************************ERROR HERE***************************
// read weekly winnings input and assign to appropriate array position; test for empty inputs and assign default value of 0 if empty
// Week1
if (textBoxWeek1Winnings.Text == String.Empty)
{
mywinnings.ReadWinningsIntoArray("0", 0);
}
else mywinnings.ReadWinningsIntoArray(textBoxWeek1Winnings.Text, 0);
//// Week2
//if (textBoxWeek2Winnings.Text == String.Empty)
//{
// mywinnings.ReadWinningsIntoArray("0", 1);
//}
//else mywinnings.ReadWinningsIntoArray(textBoxWeek2Winnings.Text, 1);
//// Week3
//if (textBoxWeek3Winnings.Text == String.Empty)
//{
// mywinnings.ReadWinningsIntoArray("0", 2);
//}
//else mywinnings.ReadWinningsIntoArray(textBoxWeek3Winnings.Text, 2);
//// Week4
//if (textBoxWeek2Winnings.Text == String.Empty)
//{
// mywinnings.ReadWinningsIntoArray("0", 3);
//}
//else mywinnings.ReadWinningsIntoArray(textBoxWeek1Winnings.Text, 3);
//// Week5
//if (textBoxWeek2Winnings.Text == String.Empty)
//{
// mywinnings.ReadWinningsIntoArray("0", 4);
//}
//else mywinnings.ReadWinningsIntoArray(textBoxWeek1Winnings.Text, 4);
//// Week6
//if (textBoxWeek2Winnings.Text == String.Empty)
//{
// mywinnings.ReadWinningsIntoArray("0", 5);
//}
//else mywinnings.ReadWinningsIntoArray(textBoxWeek1Winnings.Text, 5);
//// Week7
//if (textBoxWeek2Winnings.Text == String.Empty)
//{
// mywinnings.ReadWinningsIntoArray("0", 6);
//}
//else mywinnings.ReadWinningsIntoArray(textBoxWeek1Winnings.Text, 6);
//// Week8
//if (textBoxWeek2Winnings.Text == String.Empty)
//{
// mywinnings.ReadWinningsIntoArray("0", 7);
//}
//else mywinnings.ReadWinningsIntoArray(textBoxWeek1Winnings.Text, 7);
//// calculate total winnings by summing WeeklyWinnings array values and assigning to TotalWinnings
//mywinnings.TotalWinnings = mywinnings.WeeklyWinnings.Sum();
}
catch (FormatException)
{
// if format exception is thrown in try, display messagebox with message
MessageBox.Show("Winnings must be entered at xx.xx (e.g. 34.56).", "Input Error!");
}
catch (Exception f)
{
// if exception is thrown in try, display messagebox with message
MessageBox.Show(f.Message, "Error!");
}
// clear form textboxes
ClearTextBoxes();
writer.Close();
}
// "Enter/Update Player" tab Exit button: closes file streams and quits the application
private void buttonExit_Click(object sender, EventArgs e)
{
// closing file streams
reader.Close();
inFile.Close();
writer.Close();
outFile.Close();
// close application
Application.Exit();
}
// "Player List" tab View Player Winnings button: read file records, display records sorted by total winnings descending
private void buttonRead_Click(object sender, EventArgs e)
{
// if file exists
if (!(File.Exists(FILEPATH + FILENAME)))
{
// if file does not exist, display messagebox
MessageBox.Show("File does not exist.", "File Does Not Exist!");
}
else
{
string[] fields;
// read first record in file
string recordIn = reader.ReadLine();
listBoxOutputRecords.Items.Add("First Name\tLast Name\tCasino Name\tCasino State\tTotal Winnings\t");
while (recordIn != null)
{
// split record into array and assign
fields = recordIn.Split(DELIM);
myplayer.SocialSecurityNumber = fields[0];
myplayer.FirstName = fields[1];
myplayer.LastName = fields[2];
mycasino.CasinoName = fields[3];
mycasino.CasinoState = fields[4];
// output record to listbox
listBoxOutputRecords.Items.Add(myplayer.FirstName + "\t\t" + myplayer.LastName + "\t\t" + mycasino.CasinoName + "\t\t" + mycasino.CasinoState + "\t\t");
// read next record in file
recordIn = reader.ReadLine();
}
}
// return file position to 0
inFile.Seek(0, SeekOrigin.Begin);
}
// "Player List" tab Exit button: call buttonExit_Click method
private void buttonExit2_Click(object sender, EventArgs e)
{
// call buttonExit_Click method
buttonExit_Click(sender, e);
}
// method to clear listbox items when "Player List" tab is left
private void tabPagePlayerList_Leave(object sender, EventArgs e)
{
// clear listbox items
listBoxOutputRecords.Items.Clear();
}
// method to clear textbox controls
private void ClearTextBoxes()
{
Action<Control.ControlCollection> func = null;
func = (controls) =>
{
foreach (Control control in controls)
if (control is TextBox)
(control as TextBox).Clear();
else
func(control.Controls);
};
func(Controls);
}
}
}
My class code:
class Person
{
// SocialSecurityNumber, FirstName, LastName properties
public string SocialSecurityNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
// overridden ToString() method to return string output
public override string ToString()
{
return (SocialSecurityNumber + ',' + FirstName + ',' + LastName + ',');
}
}
// Location class
class Location
{
// CasinoName and CasinoState properties
public string CasinoName { get; set; }
public string CasinoState { get; set; }
// overridden ToString() method to return string output
public override string ToString()
{
return (CasinoName + ',' + CasinoState + ',');
}
}
// Winnings class
class Winnings
{
double[] weeklyWinnings = new double[8];
// WeeklyWinnings and TotalWinnings properties
public double[] WeeklyWinnings { get; set; }
public double TotalWinnings { get; set; }
// overridden ToString() method to return string output
public override string ToString()
{
return ( WeeklyWinnings[0].ToString("C2") + ','
+ WeeklyWinnings[1].ToString("C2") + ','
+ WeeklyWinnings[2].ToString("C2") + ','
+ WeeklyWinnings[3].ToString("C2") + ','
+ WeeklyWinnings[4].ToString("C2") + ','
+ WeeklyWinnings[5].ToString("C2") + ','
+ WeeklyWinnings[6].ToString("C2") + ','
+ WeeklyWinnings[7].ToString("C2") + ','
+ TotalWinnings.ToString("C2"));
}
// method to read textbox winnings inputs into the array
public void ReadWinningsIntoArray(string textBoxText, int position)
{
double value;
if (double.TryParse(textBoxText, out value))
WeeklyWinnings[position] = Convert.ToDouble(value);
}
}
Is textBoxWeek1Winnings properly defined in a designer file? If not, the null is because this variable isn't defined anywhere and that is the problem.
I would think in the design view of the form you should be able to see the name of the textboxes for the winnings and this is what you haven't set correctly. In declaring a new textbox
Dotnetperls has an example that may be useful to consider for how you are coding this as I think you're missing something relatively simple here.
You can greatly simplify your code by making use of the File.ReadAllLines() and File.WriteAllLines() methods.

Categories

Resources