Comparing string to text file - c#

I am currently working on a code where I add a student to a text file of students and make other calculations. The problem I'm having is I have to sort the new student into the text file so he is in the correct place.
StreamWriter changeFile = new StreamWriter("Students.txt", true);
if (pos > 0)
{
changeFile.Close();
}
else
{
changeFile.WriteLine(newStudent);
changeFile.Close();
}
using (StreamReader streamReader = new StreamReader("Students.txt"))
{
string text = streamReader.ReadToEnd();
}
So far I have managed to change the text file into a string to compare the 2, but it is in the wrong place. What code would I use to make the StreamWriter compare the newStudent string to the text file so it can put it in the correct order?
P.S. The text file has over 10,000 students in it.
These are the first 5 lines of the text file:
students (LIST
(LIST (LIST 'Abbott 'A_____ 'J ) 'NONE 'xxxxx#mail.usi.edu 2.3073320999676614 )
(LIST (LIST 'Abbott 'B_____ 'Y ) 'NONE 'xxxxx#mail.usi.edu 3.1915725161177115 )
(LIST (LIST 'Abbott 'R_____ 'Y ) 'NONE 'xxxxx#mail.usi.edu 3.448215586562192 )
(LIST (LIST 'Abel 'H_____ 'Y ) 'NONE 'xxxxx#mail.usi.edu 3.2517764202656974 )
) ) <- this is at the end

Simple method is:
Split the string at the line breaks
Create a List containing the source lines
Add the new student to the list
Sort the list
Write the list to the file
Alternately:
Split the string at the line breaks
Create a List containing the source lines
Write lines back to the file util you find the position for the new record
Write the new record
Write the rest of the records.
Or, even better for large files:
Read the source file line-by-line
Write lines to a temporary destination file
When you find the correct place to insert the new record, write it to the dest file.
Continue copying lines from source to destination
Delete the source file and rename the destination file to take its place.

something like
var Students = File.ReadAllText("Students.txt").Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList().Union(new string[] { newStudent }).ToList().Sort();
File.WriteAllLines("Students.txt", Students);
might work for you

Assuming the text file contains one student per line, you could read the text file into a list of strings, then add the new student then sort it and write it back to the file.
var allStudents = new List<string>(File.ReadAllLines("Students.txt"));
allStudents.Add(newStudent);
allStudents.Sort(allStudents);
File.WriteLines("Students.txt", allStudents);
This is inefficient because every time it reads and writes the whole file. If you have a choice, consider using a database like others have suggested.
EDIT:
Since the first line of your file is not a student, you should remove it before sorting and re-add it later.
You can remove that line like this:
var line = allStudents[0];
allStudents.RemoveAt(0);
And re-add it like this:
allStudents.Insert(0, line);

Related

Saving listbox items into a csv file

I have a list box which contains student information, it has a studentID and a student mark, when I write to the file I want the studentID and studentMark to be in separate columns (for example the first students ID will be in A1 and their mark will be in B1. and so on until all the students have been written into the file)
I have this code, but this code only adds the studentinformation into the one column, how would I go about making it split the data and putting them in 2 columns
if(lstMarks.Items.Count > 0)
{
using(TextWriter outputfile = new StreamWriter("StudentRecords.csv"))
{
foreach(string data in lstMarks.Items)
{
outputfile.WriteLine(data);
}
MessageBox.Show("Student Information inserted successfully");
}
}
This will do what you need...
outputfile.WriteLine(string.Join(",", data.Split(':')));
What this does it firstly split the string data where it finds the colon, and this returns an array. The string.Join() then joins that array back together as a string, using a comma as a separator.
You could alternatively use data.Replace(":", ",").
You can create a string and WriteLine inside your foreach loop
You will have to split your string so you have studentId and studentMark in an array. Then you can build a string with comma separated.
Finally use flush to clear all buffers
using(TextWriter outputfile = new StreamWriter("StudentRecords.csv"))
{
foreach(string data in lstMarks.Items)
{
var dataArray = data.split(':');
var line = string.Format("{0},{1}", data[0] , data[1]);
outputfile.WriteLine(line);
outputfile.Flush();
}
MessageBox.Show("Student Information inserted successfully");
}

Proof Reading .CSV per line

CSVHelper and FileHelper is not an option
I have a .csv export that I need to check for consistency structured like the below
Reference,Date,EntryID
ABC123,08/09/2015,123
ABD234,08/09/2015,124
XYZ987,07/09/2015,125
QWE456,08/09/2016,126
I can use ReadLine or RealAllLines and .Split which give me entire rows/columns BUT I have need to select each row and then go through each attribute (separated by ',') for format checking
I am running into problems here. I can not single out each value in a row for this check.
It is probably either something simple onto
class Program
{
static void Main(string[] args)
{
string csvFile = #"proof.csv";
string[] lines = File.ReadAllLines(csvFile);
var values = lines.Skip(1).Select(l => new { FirstRow = l.Split('\n').First(), Values = l.Split('\n').Select(v => int.Parse(v)) });
foreach (var value in values)
{
Console.WriteLine(string.Format("{0}", value.FirstRow));
}
}
}
Or I am going down the wrong path, my searches relate to pulling specific rows or columns (as opposed to checking the individual values associated)
The sample of the data above has a highlighted example: The date is next year and I would like to be able to proof that value (just an example as it could be in either column where errors appear)
I can not single out each value in a row
That's because you split on \n twice. The values within a row are separated by comma (,).
I'm not sure what all that LINQ is supposed to do, but it's as simple as this:
string[] lines = File.ReadAllLines(csvFile);
foreach (var line in lines.Skip(1))
{
var values = line.Split(',');
// access values[0], values[1] ...
}
Instead of reading it as text read it by OLEDB object, so data of CSV file will come in datatable and you do not need to spit it.
To Read the csv file you can use these objects of OLEDB
System.Data.OleDb.OleDbCommand
System.Data.OleDb.OleDbDataAdapter
System.Data.OleDb.OleDbConnection
and
System.Data.DataTable

Joining different text file to 1 text file c#

im try to combine text file to filename. For example my path
C:\Users\o.k\Desktop\Record\
record file has many .txt file. they names is
20.07.2015-1.txt
20.07.2015-2.txt
20.07.2015-3LAST_try.txt
20.07.2015-4.txt
20.07.2015-5.txt
20.07.2015-6LAST_a1.txt
20.07.2015-7FIRST_a2.txt
20.07.2015-8FIRST_a4.txt
this is first example write in 20.07.2015-1.txt file for example
the other one in text file 20.07.2015-2.txt this is second example.
i want to combine this 2 sentence like
this is first example
this is second example
create new text file then write in this 2 sentences.but this should for filename group.
20.07.2015-1.txt
20.07.2015-2.txt
20.07.2015-4.txt
20.07.2015-5.txt
this name format save together to main.txt
20.07.2015-3LAST_try.txt
20.07.2015-6LAST_a1.txt
this name format save together to LAST.txt
20.07.2015-7FIRST_a2.txt
20.07.2015-8FIRST_a4.txt
this name format save together to First.text
when click button it creates 3 type text file. Main,first and last. Main.txt file has contents of this files 20.07.2015-1.txt 20.07.2015-2.txt 20.07.2015-4.txt 20.07.2015-5.txt First.txt file has contents of this files 20.07.2015-7FIRST_a2.txt
20.07.2015-8FIRST_a4.txt etc.
Try this:
using (var output = File.Create("output"))
{
foreach (var file in new[] { "file1", "file2" })
{
using (var input = File.OpenRead(file))
{
input.CopyTo(output);
}
}
}

How to remove contents of one csv file from another in C#

I have 2 csv files, file1.csv and file2.csv. Some lines in each file will be identical. I wish to create a 3rd csv file, based upon file2.csv but with any lines that are present in file1.csv removed from it. Effectively I wish to subtract file1.csv from file2.csv ignoring any lines present in file1 that are not in file2.
I know that I could use streamreader to read each line in file2.csv and search for it in file1.csv. If it does not exist in file1.csv I can write it to file3.csv. However, the files are very large (over 30000 lines) and I believe this would take a lot of processing time.
I suspect there may be a better method of loading each csv to an array and then performing a simple subtraction function on them to obtain the desired result. I would appreciate either some help with the code or on method that I should approach this problem with.
Example content of files:
file1.csv
dt97861.jpg,149954,c1714ee1,\folder1\folderA\,
dt97862.jpg,149955,c1714ee0,\folder1\folderA\,
dt97863.jpg,59368,cd23f223,\folder2\folderA\,
dt97864.jpg,57881,0835be4a,\folder2\folderB\,
dt97865.jpg,57882,0835be4b,\folder2\folderB\,
file2.csv
dt97862.jpg,149955,c1714ee0,\folder1\folderA\,
dt97863.jpg,59368,cd23f223,\folder2\folderA\,
dt97864.jpg,57881,0835be4a,\folder2\folderB\,
dt97865.jpg,57882,0835be4b,\folder2\folderB\,
dt97866.jpg,57883,0835be4c,\folder2\folderB\,
dt97867.jpg,57884,0835be4d,\folder3\folderA\,
dt97868.jpg,57885,0835be4e,\folder3\folderA\,
The results I require is:
file3.csv
dt97866.jpg,57883,0835be4c,\folder2\folderB\,
dt97867.jpg,57884,0835be4d,\folder3\folderA\,
dt97868.jpg,57885,0835be4e,\folder3\folderA\,
EDIT:
With the help below I came to the following solution which I believe to be nice and elegant:
public static IEnumerable<string> ReadFile(string path)
{
string line;
using (var reader = File.OpenText(path))
while ((line = reader.ReadLine()) != null)
yield return line;
}
then:
var file2 = ReadFile(file2FilePath);
var file1 = ReadFile(file1FilePath);
var file3 = file2.Except(file1);
File.WriteAllLines(file3FilePath, file3);
Assume the line is perfectly identical, you can read both file into two IEnumerable<string> and extract with IEnumerable.Except<T>. This will produce the same result regardless of the ordering~
Example :
var file1 = new List<string>{
#"dt97861.jpg,149954,c1714ee1,\folder1\folderA\,",
#"dt97862.jpg,149955,c1714ee0,\folder1\folderA\,",
#"dt97863.jpg,59368,cd23f223,\folder2\folderA\,",
#"dt97864.jpg,57881,0835be4a,\folder2\folderB\,",
#"dt97865.jpg,57882,0835be4b,\folder2\folderB\,",
};
var file2 = new List<string>{
#"dt97862.jpg,149955,c1714ee0,\folder1\folderA\,",
#"dt97863.jpg,59368,cd23f223,\folder2\folderA\,",
#"dt97864.jpg,57881,0835be4a,\folder2\folderB\,",
#"dt97865.jpg,57882,0835be4b,\folder2\folderB\,",
#"dt97866.jpg,57883,0835be4c,\folder2\folderB\,",
#"dt97867.jpg,57884,0835be4d,\folder3\folderA\,",
#"dt97868.jpg,57885,0835be4e,\folder3\folderA\,",
};
file2.Except(file1).Dump();
Output :
dt97866.jpg,57883,0835be4c,\folder2\folderB\,
dt97867.jpg,57884,0835be4d,\folder3\folderA\,
dt97868.jpg,57885,0835be4e,\folder3\folderA\,
Here is the function to load any file into IEnumerable<string>. Just dont forget to using System.IO;.
public static IEnumerable<string> ReadFile(string path)
{
string line;
using(var reader = File.OpenText(path))
while((line = reader.ReadLine()) != null)
yield return line;
}
To write the result to a file :
//using System.IO; is required
File.WriteAllLines("file3.csv", file2.Except(file1))
Remarks : File.WriteAllLines will create or overwrite the file.
While this may not be the best approach, it's the one I've used in the past. It's a bit of a dirty hack, but...
Import both CSV files into a datatable (so you will have two datatables -I personally prefer closed xml if you plan to use an excel type format, otherwise just use a normal file read/write - My example uses regular read/write)
Move data from datatable into a list (my example assumes comma separated values, one per line.)
Find unique values between lists and merge
Export the merged lists to a csv file
*[Edited steps after actually working on the code]
Per request from Bit, I've added an example using sample data from Some Random Website - This was written in VS2008 against .NET 3.5, but it should work on 3.5+. I copied us-500 into 2 versions, the original and modified 1 row to create a unique value to test. This project is targeting x86 platform. I've used a new windows form for testing
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace TestSandbox
{
public partial class Form1 : Form
{
public Form1()
{
var file1 = new DataTable();
var file2 = new DataTable();
InitializeComponent();
//Gets data from csv file, select allows for filtering
using (var conn = new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\;Extended Properties=""text;HDR=Yes;FMT=Delimited"";"))
{
conn.Open();
using (var adapter = new OleDbDataAdapter(#"select * from [us-500.csv]", conn))
{
adapter.Fill(file1);
}
}
using (var conn = new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\;Extended Properties=""text;HDR=Yes;FMT=Delimited"";"))
{
conn.Open();
using (var adapter = new OleDbDataAdapter(#"select * from [us-500-2.csv]", conn))
{
adapter.Fill(file2);
}
}
//Moves datatable information to lists for comparison
var file1List = (from DataRow row in file1.Rows select row.ItemArray.Select(field => field.ToString()).ToArray() into fields select string.Join(",", fields)).ToList();
var file2List = (from DataRow row in file2.Rows select row.ItemArray.Select(field => field.ToString()).ToArray() into fields select string.Join(",", fields)).ToList();
//Adds all data from file2 into file1 list, except for data that already exists in file1
file1List.AddRange(file2List.Except(file1List));
//Exports all results to c:\results.csv
File.WriteAllLines(#"C:\Results.csv", file1List.ToArray());
}
}
}
*Note: After looking at the code, importing straight to a list looks like it would be more efficient, but I'll leave this as is for now since it's not overly complicated.
Step 1. Using System.IO, we'll read two files using FileStream and create a third file using StreamWriter.
Step 2. Use FileStream to read file #1. e.g.
using (var FS = new System.IO.FileStream(file1, System.IO.FileMode.Open, System.IO.FileAccess.Read)) { ...<insert next steps in here>...}
Step 3. Nest another FileStream to read file #2. This stream will be read multiple times, so it's best if you can put the smaller file in this part of the nest. You can do this by checking the size of the file prior to jumping into these loops.
Step 4. Read in a single line from our biggest file, File#1, then we compare it against ALL lines from File#2 sequentially. If a match is found, set a boolean to TRUE indicating that there is a matching line found in File #2.
Step 5. Once we're at the end of File #2, check for a true/false condition of the boolean. If its false, SAVE the string we read from File #1 into File #3. This is your output file.
Step 6. Reset the stream pointer for File #2 to the beginning of the file e.g. FS.Seek(0, System.IO.SeekOrigin.Begin)
Step 7. Repeat from Step 4 until we've reached the end of File #1. File #3's contents should represent only unique entries from File #1 that are not members of File #2

Streamwriter if statement not working

I am currently working on a school project involving a large number of students where I have to insert a new student alphabetically and do a few other calculations. I am having trouble getting it so that it only adds the new student once. I have an if statement but it doesn't appear to be working properly.
`//this adds the new student
StreamWriter changeFile = new StreamWriter("Students.txt", true);
string newStudent = "(LIST (LIST 'Malachi 'Constant 'A ) '8128675309 'iwishihadjessesgirl#mail.usi.edu 4.0 )";
// this is where I am getting stumped
if (File.Exists(newStudent))
{
changeFile.Close();
}
else
{
changeFile.WriteLine(newStudent);
changeFile.Close();
}`
Whenever I run the code like this it will just add the new student every time I debug the program. How can I make it only add him one time?
File.Exists determines if the file at the given path exists (which, for the record, you should still be doing before trying to read/write to the file). You're trying to find out if the given line of text exists within a given file. That's a very different task.
You'll need to read through the lines in the file and compare them to your given text.
if(!File.ReadLines(filepath).Contains(newStudent))
{
//TODO: Append student to the file
}
File.Exists(string path) returns a bool that determines if a file exists at the specified path.
http://msdn.microsoft.com/en-us/library/system.io.file.exists(v=vs.110).aspx
string newStudent is not a file path, so it will always return false.
I think what you want is something like this: (this is by memory so it likely won't compile as is)
var file = File.Open("students.txt");
var fileContents = file.ReadToEnd();
if (!fileContents.Contains(newStudent))
{
file.WriteLine(newStudent);
}
file.Close();
First read the Existing file data into String variable and then check the given student data is available or not in the received file.if the given student data is not found then write the new student data into file otherwise,if already present then close the opened steream.
String StudentInfo = System.IO.File.ReadAllText("Students.txt");
StreamWriter changeFile = new StreamWriter("Students.txt", true);
string newStudent = "(LIST (LIST 'Malachi 'Constant 'A ) '8128675309 'iwishihadjessesgirl#mail.usi.edu 4.0 )";
// this is where I am getting stumped
if (StudentInfo.Contains(newStudent))
{
changeFile.Close();
}
else
{
changeFile.WriteLine(newStudent);
changeFile.Close();
}

Categories

Resources