I'm creating a program in my free time to store info about my trading card collection. I was wondering is there any way to prevent duplicate entries into excel using the File.AppendAllText method. My current code is:
private void btnAdd_Click(object sender, EventArgs e)
{
Global.card.Add(new Card(lblCardNoFinal.Text, lblCardNameFinal.Text, lblCardRarityFinal.Text, lblCardTypeFinal.Text));
string file = ("..\\Debug\\LOB.csv");
string delimiter = ",";
StringBuilder sb = new StringBuilder();
foreach (Card card in Global.card)
{
sb.AppendLine(card.CardNo + delimiter + card.CardName + delimiter + card.CardRarity + delimiter + card.CardType);
}
File.AppendAllText(file, sb.ToString());
MessageBox.Show("Card Added");
}
When I try to add more than one card, the data of the previous one is entered into the excel file so it appears twice when I don't want it to. Thanks
Try File.WriteAllText instead. File.AppendAllText will add the text to the bottom of the file.
Alternatively, you could do File.AppendAllLines for the card you are adding, like this:
private void btnAdd_Click(object sender, EventArgs e)
{
string file = ("..\\Debug\\LOB.csv");
string delimiter = ",";
var card = new Card(lblCardNoFinal.Text, lblCardNameFinal.Text, lblCardRarityFinal.Text, lblCardTypeFinal.Text)
Global.card.Add(card);
File.AppendAllLines(file, new[] {card.CardNo + delimiter + card.CardName + delimiter + card.CardRarity + delimiter + card.CardType});
MessageBox.Show("Card Added");
}
It looks that whenever you add single card you're appending all cards from Global.card, so I would get rid of foreach loop. You can just append this single card.
Try something like:
Card newCard = new Card(lblCardNoFinal.Text, lblCardNameFinal.Text, lblCardRarityFinal.Text, lblCardTypeFinal.Text)
Global.card.Add(newCard)
File.AppendAllText(file, newCard.CardNo + delimiter + newCard.CardName + delimiter + newCard.CardRarity + delimiter + newCard.CardType);
You also don't need StringBuilder, but I would work on ToString method for your Card class.
Related
I'm sure this is really simple to do but i'm struggling.
private void button1_Click(object sender, EventArgs e)
{
SaveBtn();
void SaveBtn()
{
string savetext = textBox1.Text;
string savetext2 = textBox2.Text;
File.AppendAllText(#"C:\Riot Games\AccountSwitcher.txt", savetext + Environment.NewLine + savetext2 + Environment.NewLine + Environment.NewLine);
MessageBox.Show("Your ID: " + savetext + " and you PWD: " + savetext2 + " has been saved.");
}
}
As you can see i have 2 textbox and when i'm clicking the button "save" both input are saved into a file.txt. This code works like a charm but i'd rather save these 2 inputs into an array so i could use them individually.
Thanks your help, i'm pretty noob as you can see so please keep it simple :D <3
Use:
string[] savetexts = new string[]{ savetext , savetext2 };
Alternatively, you could convert the entire string and save it in a char array.
char[] savetext = savetext.ToCharArray();
char[] savetext2 = savetext2.ToCharArray();
Hope this helps.!
P.S It is much easier to use a List instead of hard-coded arrays like above.
List<String> myStrings = new List<String>();
myStrings.add(savetext);
myStrings.add(saveText2);
.....etc
then to get them back you iterate over myStrings
foreach(String s in myStrings){
Console.writeline(s);
}
Or you can access them directly
String text1 = myStrings[0];
String text2 = myString[1];
This is a bit more than what you are asking, but using List becomes much easier in the long run. Best of luck.
I'm currently having some issues with my CSV to SQL Converter. With this being my third week of learning C# I'm starting to grasp some stuff but this is going over my head a bit.
What I'm trying to do is have the Top row/Titles taken down split into each individual title and then for the SQL code through that rather than entering it manually like I've done. Below you can see some of my code that I've built so far.
private void Form1_Load(object sender, EventArgs e)
{
try
{
// your code here
string CSVFilePathName = #"C:\\CSV\\reg.csv";
string[] Lines = File.ReadAllLines(CSVFilePathName);
string[] Fields;
//1st row must be column names; force lower case to ensure matching later on.
// get regs from filename
// get fieldnames from Lines[0] (first line of file)
// create a loop for fields array
string hdr = Lines[0];
for (int i = 1; i < Lines.Length; i++)
{
Fields = Lines[i].Split(new char[] { ',' });
CSVTextBox.AppendText(Fields[0] + "," + Fields[1] + "," + Fields[2] + "," + Fields[3] + Environment.NewLine);
// need a for loop for each field
// for (
SQLTextBox.AppendText("INSERT INTO[dbo].[REGS]([SESTYPE],[REG],[LFL],[SUBVER]) VALUES('" + Fields[3] + "'" + Fields[0] + "'" + Fields[1] + "'" + Fields[2] + ")" + Environment.NewLine);
// }
}
}
catch (Exception ex)
{
MessageBox.Show("Error is " + ex.ToString());
throw;
}
}
This all runs at the moment, I'm just struggling to get the titles to become part of the code. Any help would be appreciated.
Cheers,
First: Remove the try catch. If you get an Exception, you should read, understand and clear off.
For your SQLTextBox: I recommend to use the String.Format function. This allows you to create strings with different values, but is much, much easier to read.
For the titles: Use your variable hdr This should contain the title. Then you can split it via string.Split(',') or string.Split(';'), depending on your delimiter
How can we read a text file column by column.
Check my new code: I can read the data row-wise using text.split (' ')
But how can be the file read as column wise? Lets assume that a file contains number of rows and columns but I was able to read the data/value horizontally. The code you see that below that's what I could execute!
SEE THE CODE BELOW:-
private void Form1_Load(object sender, EventArgs e)
{
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
string text = "";
text = textBox1.Text;
string[] arr = text.Split(' ');
textBox2.Text = arr[5];
textBox3.Text = arr[8];
}
private void button3_Click(object sender, EventArgs e)
{
string file_name = "c:\\Excel\\count.txt";
string txtline = "";
System.IO.StreamReader objreader;
objreader = new System.IO.StreamReader(file_name);
do
{
txtline = txtline + objreader.ReadLine() + "\r\n";
txtline = txtline + objreader.ReadToEnd() + "";
this.textBox1.Text = "subzihut";
}
while (objreader.Peek() != -1);
textBox1.Text = txtline;
objreader.Close();
}
private void button2_Click(object sender, EventArgs e)
{
textBox4.Text = textBox2.Text + " " + textBox3.Text;
}
}
}
A textfile contains a sequence of characters, delimited by newline characters and probably other characters which are used as delimiters (usually a comma or a semiciolon).
When you read a file you simply read this stream of characters. There are helper functions which read such a file line-by-line (using the newline character as a delimiter).
In plain .Net there are no methods which read column-by-column.
So you should:
read the file line by line
split each line into fields/columns using string.Split() at the separator character(s)
access only the columns of interest
You can simply read the file line by line, splitt the lines and do whatever you want.
var lines = File.ReadLines(#"c:\yourfile.txt");
foreach(var line in lines)
{
var values = line.Split(' ');
}
public string getColumnString(int columnNumber){
string[] lines = System.IO.ReadAllLines(#"C:\inputfile.txt");
string stringTobeDisplayed = string.Empty;
foreach(string line in lines) {
if(columnNumber == -1){ //when column number is sent as -1 then read full line
stringTobeDisplayed += line +"\n"
}
else{ //else read only the column required
string [] words = line.Split();
stringTobeDisplayed += word[columnNumber] +"\n"
}
}
return stringTobeDisplayed;
}
Maybe this will help you:
public static void ReadFile(string path)
{
List<string> Col1 = new List<string>();
List<string> Col2 = new List<string>();
List<string> Col3 = new List<string>();
using (StreamReader sr = new StreamReader(path))
{
while (sr.EndOfStream)
{
string header = sr.ReadLine();
var values = header.Split(' ');
Col1.Add(values[0]);
Col2.Add(values[1]);
Col3.Add(values[2]);
}
}
}
It's true that sometimes you just don't know where to start. Here are some pointers.
You'll have to read the whole file in, probably using something like a StreamReader.
You can parse the first row into column names. Use StreamReader.ReadLine() to get the first line and then do some simple string parsing on it.
You'll want to create some kind of class/object to store and access your data.
Once you have column names, continue to parse the following lines into the proper arrays.
Some here's a rough idea
using(StreamReader sr = new StreamReadeR("C:\\my\\file\\location\\text.csv"))
{
string header = sr.ReadLine();
List<string> HeaderColumns = new List<string>(header.split(" ", StringSplitOptions.RemoveEmptyEntires));
myModelClass.Header = HeaderColumns;
etc...
You might also consider making some kind of dictionary to access columns by header name and index.
Struggling with a C# Component. What I am trying to do is take a column that is ntext in my input source which is delimited with pipes, and then write the array to a text file. When I run my component my output looks like this:
DealerID,StockNumber,Option
161552,P1427,Microsoft.SqlServer.Dts.Pipeline.BlobColumn
Ive been working with the GetBlobData method and im struggling with it. Any help with be greatly appreciated! Here is the full script:
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
string vehicleoptionsdelimited = Row.Options.ToString();
//string OptionBlob = Row.Options.GetBlobData(int ;
//string vehicleoptionsdelimited = System.Text.Encoding.GetEncoding(Row.Options.ColumnInfo.CodePage).GetChars(OptionBlob);
string[] option = vehicleoptionsdelimited.Split('|');
string path = #"C:\Users\User\Desktop\Local_DS_CSVs\";
string[] headerline =
{
"DealerID" + "," + "StockNumber" + "," + "Option"
};
System.IO.File.WriteAllLines(path + "OptionInput.txt", headerline);
using (System.IO.StreamWriter file = new System.IO.StreamWriter(path + "OptionInput.txt", true))
{
foreach (string s in option)
{
file.WriteLine(Row.DealerID.ToString() + "," + Row.StockNumber.ToString() + "," + s);
}
}
Try using
BlobToString(Row.Options)
using this function:
private string BlobToString(BlobColumn blob)
{
string result = "";
try
{
if (blob != null)
{
result = System.Text.Encoding.Unicode.GetString(blob.GetBlobData(0, Convert.ToInt32(blob.Length)));
}
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
Adapted from:
http://mscrmtech.com/201001257/converting-microsoftsqlserverdtspipelineblobcolumn-to-string-in-ssis-using-c
Another very easy solution to this problem, because it is a total PITA, is to route the error output to a derived column component and cast your blob data to a to a STR or WSTR as a new column.
Route the output of that to your script component and the data will come in as an additional column on the pipeline ready for you to parse.
This will probably only work if your data is less than 8000 characters long.
I have this code:
public void FileCleanup(List<string> paths)
{
string regPattern = (#"[~#&!%+{}]+");
string replacement = "";
string replacement_unique = "_";
Regex regExPattern = new Regex(regPattern);
List<string> existingNames = new List<string>();
StreamWriter errors = new StreamWriter(#"C:\Documents and Settings\jane.doe\Desktop\SharePointTesting\Errors.txt");
StreamWriter resultsofRename = new StreamWriter(#"C:\Documents and Settings\jane.doe\Desktop\SharePointTesting\Results of File Rename.txt");
foreach (string files2 in paths)
try
{
string filenameOnly = Path.GetFileName(files2);
string pathOnly = Path.GetDirectoryName(files2);
string sanitizedFileName = regExPattern.Replace(filenameOnly, replacement);
string sanitized = Path.Combine(pathOnly, sanitizedFileName);
if (!System.IO.File.Exists(sanitized))
{
existingNames.Add(sanitized);
try
{
foreach (string names in existingNames)
{
string filename = Path.GetFileName(names);
string filepath = Path.GetDirectoryName(names);
string cleanName = regExPattern.Replace(filename, replacement_unique);
string scrubbed = Path.Combine(filepath, cleanName);
System.IO.File.Move(names, scrubbed);
//resultsofRename.Write("Path: " + pathOnly + " / " + "Old File Name: " + filenameOnly + "New File Name: " + sanitized + "\r\n" + "\r\n");
resultsofRename = File.AppendText("Path: " + filepath + " / " + "Old File Name: " + filename + "New File Name: " + scrubbed + "\r\n" + "\r\n");
}
}
catch (Exception e)
{
errors.Write(e);
}
}
else
{
System.IO.File.Move(files2, sanitized);
resultsofRename.Write("Path: " + pathOnly + " / " + "Old File Name: " + filenameOnly + "New File Name: " + sanitized + "\r\n" + "\r\n");
}
}
catch (Exception e)
{
//write to streamwriter
}
}
}
}
What i'm trying to do here is rename "dirty" filenames by removing invalid chars (defined in the Regex), replace them with "". However, i noticed if i have duplicate file names, the app does not rename them. I.e. if i have ##test.txt and ~~test.txt in the same folder, they'd be renamed to test.txt. So, i created another foreach loop that instead replaces the invalid char with a "_" versus a blank space.
Problem is, whenever i try to run this, nothing ends up happening! None of the files are renamed!
Can someone tell me if my code is incorrect and how to fix it?
ALSO-- does anybody know how i could replace the invalid char in the 2nd foreach loop with a different char everytime? That way if there are multiple instances of i.e. %Test.txt, ~Test.txt and #test.txt (all to be renamed to test.txt), they can somehow be uniquely named with a different char?
However, would you know how to replace the invalid char with a different unique character every time so that each filename remains unique?
This is one way:
char[] uniques = ",'%".ToCharArray(); // whatever chars you want
foreach (string file in files)
{
foreach (char c in uniques)
{
string replaced = regexPattern.Replace(file, c.ToString());
if (File.Exists(replaced)) continue;
// create file
}
}
You may of course want to refactor this into its own method. Take note also that the maximum number of files only differing by unique character is limited to the number of characters in your uniques array, so if you have a lot of files with the same name only differing by the special characters you listed, it might be wise to use a different method, such as appending a digit to the end of the file name.
how would i append a digit to the end of the file name (with a different # everytime?)
A slightly modified version of Josh's suggestion would work that keeps track of the modified file names mapped to the number of times the same file name has been generated after the replacement:
var filesCount = new Dictionary<string, int>();
string replaceSpecialCharsWith = "_"; // or "", whatever
foreach (string file in files)
{
string sanitizedPath = regexPattern.Replace(file, replaceSpecialCharsWith);
if (filesCount.ContainsKey(sanitizedPath))
{
filesCount[file]++;
}
else
{
filesCount.Add(sanitizedPath, 0);
}
string newFileName = String.Format("{0}{1}{2}",
Path.GetFileNameWithoutExtension(sanitizedPath),
filesCount[sanitizedPath] != 0
? filesCount[sanitizedPath].ToString()
: "",
Path.GetExtension(sanitizedPath));
string newFilePath = Path.Combine(Path.GetDirectoryName(sanitizedPath),
newFileName);
// create file...
}
just a suggestion
after removing/replacing the special characters append timestamp to the file name. timestamps are unique so appending them to filenames will give you a unique filename.
How about maintaining a dictionary of all renamed files, checking each file against it, and if already existing add a number to the end of it?
In response to the answer #Josh Smeaton's gave here's some sample code using a dictionary to keep track of the file names :-
class Program
{
private static readonly Dictionary<string,int> _fileNames = new Dictionary<string, int>();
static void Main(string[] args)
{
var fileName = GetUniqueFileName("filename.txt");
Console.WriteLine(fileName);
fileName = GetUniqueFileName("someotherfilename.txt");
Console.WriteLine(fileName);
fileName = GetUniqueFileName("filename.txt");
Console.WriteLine(fileName);
fileName = GetUniqueFileName("adifferentfilename.txt");
Console.WriteLine(fileName);
fileName = GetUniqueFileName("filename.txt");
Console.WriteLine(fileName);
fileName = GetUniqueFileName("adifferentfilename.txt");
Console.WriteLine(fileName);
Console.ReadLine();
}
private static string GetUniqueFileName(string fileName)
{
// If not already in the dictionary add it otherwise increment the counter
if (!_fileNames.ContainsKey(fileName))
_fileNames.Add(fileName, 0);
else
_fileNames[fileName] += 1;
// Now return the new name using the counter if required (0 means it's just been added)
return _fileNames[fileName].ToString().Replace("0", string.Empty) + fileName;
}
}