I trying to load 4 lines from text files:
email:pass
email1:pass1
email2:pass2
email3:pass3
I used string.split, however when I try to Add to the my List it doesn't load well.
Here what I tried:
List<string> AccountList = new List<string>();
Console.Write("File Location: ");
string FileLocation = Console.ReadLine();
string[] temp = File.ReadAllLines(FileLocation);
string[] tempNew = new string[1000];
int count = 0;
foreach(var s in temp)
{
AccountList.Add(s.Split(':').ToString());
count++;
}
I checked how it the strings look inside the lists and they were like this:
System.String[]
I want it to be like this:
AccountList[0] = email
AccountList[1] = pass
AccountList[2] = email1
AccountList[3] = pass1
String.Split yields a string array
foreach(var s in temp)
{
string[] parts = s.Split(':');
string email = parts[0];
string pass = parts[1];
...
}
To store these two pieces of information, create an account class:
public class Account
{
public string EMail { get; set; }
public string Password { get; set; }
}
Then declare your account list as List<Account>:
var accountList = new List<Account>();
foreach(var s in File.ReadLines(FileLocation))
{
string[] parts = s.Split(':');
var account = new Account { EMail = parts[0], Password = parts[1] };
accountList.Add(account);
}
Note that you don't need the temp variable. File.ReadLines reads the file as the loop progresses, so that the whole file needs not to be stored in memory. See: File.ReadLines Method (Microsoft Docs).
No need to count. You can get the count with
int count = accountList.Count;
This list will be easier to handle than a list interleaved with emails and passwords.
You can access an account by index
string email = accountList[i].EMail;
string pass = accountList[i].Password;
or
Account account = accountList[i];
Console.WriteLine($"Account = {account.EMail}, Pwd = {account.Password}");
From your expected result you can try this, string.Split will return a string array string[], which spite by your expect character.
then use the index to get string part.
foreach(var s in temp)
{
var arr = s.Split(':');
AccountList.Add(arr[0]);
AccountList.Add(arr[1]);
}
The problem is that Split returns a string array consisting of the parts of the string found between the split character(s), and you're treating it as a string.
Instead, your code can be simplified by taking the result of File.ReadAllLines (a string array) and using .SelectMany to select the resulting array from splitting each line on the : character (so you're selecting an array for each item in the array), and then calling ToList on the result (since you're storing it in a list).
For example:
Console.Write("Enter file location: ");
string fileLocation = Console.ReadLine();
// Ensure the file exists
while (!File.Exists(fileLocation))
{
Console.Write("File not found, please try again: ");
fileLocation = Console.ReadLine();
}
// Read all the lines, split on the ':' character, into a list
List<string> accountList = File.ReadAllLines(fileLocation)
.SelectMany(line => line.Split(':'))
.ToList();
Related
I have a data file
Name; LastName; EurosCents;
Name2; LastName2; EurosCents2;
(for example:
John; Smith; 4,20;
Josh; Peck; 6,50;
)
I need to read the data and then do some further work with it... Is there any way to read the lines and save them? As the only way to read from a text file is to read the entire line at once.
var lst = File.ReadAllLines(yourFilePath).Select(x => new
{
FirstName = x.Split(';')[0]
LastName = x.Split(';')[1]
Value = decimal.Parse(x.Split(';')[2])
}).ToList();
use
lst[7].FirstName = "xxx";
Console.WriteLine(lst[2].Value);
etc...
The File API provide multiple options for reading files. Below is a possible way to proceed:
foreach(var line in File.ReadAllLines(path))
{
var splitted = line.Split(';');
var name = splitted.ElementAtOrDefault(0);
var lastName = splitted.ElementAtOrDefault(1);
var cents = Decimal.Parse(splitted.ElementAtOrDefault(2));
}
Parsing will be very easy if you are comfortable using LINQ.
Below line can get you the file in a hierarchical structure.
var theselines = File.ReadLines(#"C:\Test.txt").Select(l => l.Split(','));
You can see the result of above line by debugging.
Later you can have any logic to get the required data from each line without using foreach loop.
var Data = theselines.Select(l => new
{
id = l.Where(t => t.Contains("01")).FirstOrDefault(),
Price = l.Where(t => t.Contains(",")).FirstOrDefault(),
Firstname= l[0],
lastname = l[1]
});
Providing that data itself (both names and cents) can't contain ; in order to get
items from the comma separated values you can just split:
var data = File
.ReadLines(#"C:\MyData.csv")
// .Skip(1) // <- in case you have caption to skip
.Select(line => line.Split(';'))
.Select(items => new {
Name = items[0],
LastName = items[1],
EuroCents = decimal.Parse(items[2]) //TODO: check type and its format
});
//.ToArray(); // <- if you want to materialize as, say, an array
Then you can use it
foreach (var item in data) {
if (item.EuroCents > 10) {
...
}
}
the simple code to read whole file is as follows
string[] test(string path)
{
System.IO.StreamReader sr = new System.IO.StreamReader(path);
string[] str = sr.ReadToEnd().Split(';');
sr.Close();
return str;
}
I have a list of strings which holds file paths.
List<string> allFilesWithPathList = new List<string>();
allFilesWithPathList.Add(#"G:\Test\A.sql");
allFilesWithPathList.Add(#"G:\Test\B.sql");
allFilesWithPathList.Add(#"G:\Test\C.sql");
return allFilesWithPathList;
I have another list which holds a subset of files – but it has only the file name; not the path.
List<string> excludeList = new List<string>();
excludeList.Add("B.sql");
Now I need to get files from allFilesWithPathList that is not present in excludeList. Currently I am doing the following, using EXCEPT, after creating another list with file names only.
List<string> allFileNamesOnlyList = new List<string>();
foreach (string fileNameWithPath in allFilesWithPathList)
{
//Remove path and get only file name
int pos = fileNameWithPath.LastIndexOf(#"\") + 1;
string value = fileNameWithPath.Substring(pos, fileNameWithPath.Length - pos);
allFileNamesOnlyList.Add(value);
}
//EXCEPT logic
List<string> eligibleListToProcess = allFileNamesOnlyList.Except(excludeList).ToList();
What is the best way in LINQ to get this logic working without introducing another list like the above?
Note: I am using .Net 4.5
Complete code
class Program
{
static void Main(string[] args)
{
List<string> allFilesWithPathList = GetAllFilesWithPath();
List<string> excludeList = new List<string>();
excludeList.Add("B.sql");
List<string> allFileNamesOnlyList = new List<string>();
foreach (string fileNameWithPath in allFilesWithPathList)
{
//Remove path and get only file name
int pos = fileNameWithPath.LastIndexOf(#"\") + 1;
string value = fileNameWithPath.Substring(pos, fileNameWithPath.Length - pos);
allFileNamesOnlyList.Add(value);
}
//EXCEPT logic
List<string> eligibleListToProcess = allFileNamesOnlyList.Except(excludeList).ToList();
//Print all eligible files
foreach (string s in eligibleListToProcess)
{
Console.WriteLine(s);
}
Console.ReadLine();
}
public static List<string> GetAllFilesWithPath()
{
List<string> allFilesWithPathList = new List<string>();
allFilesWithPathList.Add(#"G:\Test\A.sql");
allFilesWithPathList.Add(#"G:\Test\B.sql");
allFilesWithPathList.Add(#"G:\Test\C.sql");
return allFilesWithPathList;
}
}
allFilesWithPathList.Where(path => !allFileNamesOnlyList.Contains(Path.GetFileName(path));
There are two improvements here.
Path.GetFileName is much better than splitting the path yourself.
IEnumerable.Where in conjunction with ICollection.Contains to actually query the list in a succinct and easy to read way.
This should work
allFilesWithPathList.Where(x => !excludeList.Any(y => x.EndsWith(y)))
I have a two arrays i have taken from a csv file, i want to check my current output for the first array and output the second array, eg
"Hello, LOL" would output "Hello, Laugh out loud"
i have used
var reader = new StreamReader(File.OpenRead(#filelocation"));
List<string> listA = new List<string>();
List<string> listB = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(',');
listA.Add(values[0]);
listB.Add(values[1]);
}
The arrays are stored and have the correct information in them, i just don't know how to check a string from the first list and change it to the second.
You should use a Dictionary for this operation instead of List. In addition, you could use File.ReadAllLines to read all lines in a file instead of looping.
// I replace your code with linq
Dictionary<string, string> dictionary =
File.ReadAllLines("#filelocation").Select(l => l.Split(',')).ToDictionary(k =>
k[0], v => v[1]);
string input = "Hello, LOL" ;
var thekey = dictionary.Keys.FirstOrDefault(k => input.Contains(k));
if (thekey != null) // Replacement was found
{
input = input.Replace(thekey, dictionary[thekey]);
}
// Should print Hello, Laugh out loud
Console.WriteLine(input) ;
I have a text file that looks like this:
DeltaV User List - 17 Jun 2013
SUPPLY_CHAIN
UserID Full Name
BAINC C M B
BEEMANH H B
CERIOJI J M C
LADUCK K L
MAYC C M
NEWTONC C N
DeltaV User List - 17 Jun 2013
FERM_OPER
UserID Full Name
POULIOTM M P
TURNERM7 M T
I need to get the individual users for each of these sections in C# and I'm not sure how to do it. I was using the StreamReader class and it worked for getting the Area name (the word in all caps) but I cannot seem to get all of the users. I have a user class that has 2 strings Name & Area and I'm trying to make a list of user objects.
This is what I've tried so far: (I've declared a list of User objects earlier in the code)
// read user list text file
var userReader = new StreamReader(File.OpenRead(UserListPath));
while(!userReader.EndOfStream)
{
var line = userReader.ReadLine();
var newUser = new User();
if(line.Contains("DeltaV User List"))
{
var Area = userReader.ReadLine();
newUser.Area = Area;
userReader.ReadLine();
userReader.ReadLine();
userReader.ReadLine();
var userid = userReader.ReadLine();
Console.WriteLine(userid);
var name = userid.Split(' ');
Console.WriteLine(name[0]);
newUser.UserId = name[0];
}
Users.Add(newUser);
}
Oh, I only need to get the UserId, not the Full Name as well.
Edited
Here is a little piece of code that should achieve what you need :
using (var fileStream = File.OpenRead(UserListPath))
using (var userReader = new StreamReader(fileStream))
{
string currentArea = string.Empty;
string currentToken = string.Empty;
while (!userReader.EndOfStream)
{
var line = userReader.ReadLine();
if (!string.IsNullOrEmpty(line))
{
var tokenFound = Tokens.FirstOrDefault(x => line.StartsWith(x));
if (string.IsNullOrEmpty(tokenFound))
{
switch (currentToken)
{
case AreaToken:
currentArea = line.Trim();
break;
case UserToken:
var array = line.Split(' ');
if (array.Length > 0)
{
Users.Add(new User()
{
Name = array[0],
Area = currentArea
});
}
break;
default:
break;
}
}
else
{
currentToken = tokenFound;
}
}
}
}
This program assumes that your input file ends with a line return. It uses these constants that you will have to declare in your class or anywhere your want by modifying their accessors (private into public for instance) :
private const string AreaToken = "DeltaV";
private const string UserToken = "UserID";
private List<string> Tokens = new List<string>() { AreaToken, UserToken };
Of course, i've done it my way, there's probably lots of better way of doing it. Improve it the way you want, it's just a kind of draft that should compile and work.
Among other things, you'll notice :
the use of using keyword, which is very useful to make sure your memory/ressource/file handles are properly free.
i tried to avoid the use of hard coded values (that's the reason why i use constants and a reference list)
i tried to make it so you just have to add new constants into the Token reference list (called Tokens) and to extend switch cases to handle new file tokens/scenarios
Finally, do not forget to instanciate your User list :
List<User> Users = new List<User>();
// read user list text file
var userReader = new StreamReader(File.OpenRead(UserListPath));
var Area = "";
while(!userReader.EndOfStream)
{
var line = userReader.ReadLine();
if(line.Contains("DeltaV User List"))
{
Area = userReader.ReadLine(); // Area applies to group of users below.
userReader.ReadLine(); // blank line
userReader.ReadLine(); // blank line
userReader.ReadLine(); // User ID header line
}
else
{
if (line.trim() != "") // Could be blank line before "DeltaV..."
{
var userid = line;
var newUser = new User();
newUser.Area = Area;
// I left the following lines in place so that you can test the results.
Console.WriteLine(userid);
var name = userid.Split(' ');
Console.WriteLine(name[0]);
newUser.UserId = name[0];
Users.Add(newUser);
}
}
}
Here is what I got working:
void Main()
{
var filePath = #"..."; //insert your file path here
var lines = File.ReadLines(filePath); //lazily read and can be started before file is fully read if giant file
IList<User> users = new List<User>();
var Area = string.Empty;
foreach(var line in lines)
{
if(string.IsNullOrWhiteSpace(line) ||
line.Contains("DeltaV User List") ||
line.Contains("UserID")
)
{
continue;
}
var values = line.Split(' ');
if(values.Length == 1)
{
Area = values[0];
continue;
}
var currentUser = new User
{
Name = values[0],
Area = Area
};
users.Add(currentUser);
}
users.Dump("User List"); //Dump is a Linqpad method to display result see screen shot
}
// Define other methods and classes here
public class User
{
public string Name { get; set; }
public string Area { get; set; }
}
Result from the file you posted:
File.ReadLines
LinqPad for testing small snippets of code.
You can copy and paste this into LinqPad to modify for your needs just provide it a file.
Background on this project. It started as a simple homework assignment that required me to store 5 zip codes and their corresponding cities. When a user puts a Zip code in a textbox, a corresponding city is returned, and likewise the opposite can be done. I wrote the code to return these values, but then I decided I wanted to store ALL zip codes and their corresponding Cities in an external .csv, and store those values in arrays and run the code off that because if its worth doing, its worth overdoing! To clarify, this is no longer for homework, just to learn more about using external files in C#.
In the following code, I have called to open the file successfully, now I just need help in figuring out how to pull the data that is stored in two separate columns (one for city, one for zip code) and store them in two arrays to be acted upon by the for loop. Here is the code I have now. You can see how I have previously stored the other values in arrays and pulled them out:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnConvert2City_Click(object sender, EventArgs e)
{
try
{
string dir = System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location);
string path = dir + #"\zip_code_database_edited.csv";
var open = new StreamReader(File.OpenRead(path));
int EnteredZipcode = Convert.ToInt32(txtZipcode.Text.Trim());
string result = "No Cities Found";
string[] Cities = new String[5] { "FLINTSTONE", "JAMAICA", "SCHENECTADY", "COTTONDALE", "CINCINNATI" };
int[] Zipcode = new int[5] { 30725, 11432, 12345, 35453, 45263 };
for (int i = 0; i <= Zipcode.Length - 1; i++)
{
if (Zipcode[i] == EnteredZipcode)
{
result = Cities[i];
break;
}
}
string DisplayState = result;
txtCity.Text = DisplayState;
}
catch (FormatException)
{
MessageBox.Show("Input must be numeric value.");
}
catch (OverflowException)
{
MessageBox.Show("Zipcode to long. Please Re-enter");
}
}
private void btnConvert2Zipcode_Click(object sender, EventArgs e)
{
string dir = System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location);
string path = dir + #"\zip_code_database_edited.csv";
var open = new StreamReader(File.OpenRead(path));
String EnteredCity = txtCity.Text.ToUpper();
string result = "No Zipcode Found";
string[] Cities = new String[5] { "FLINTSTONE", "JAMAICA", "SCHENECTADY", "COTTONDALE", "CINCINNATI" };
int[] Zipcode = new int[5] { 30725, 11432, 12345, 35453, 45263 };
for (int i = 0; i <= Cities.Length - 1; i++)
{
if (Cities[i] == EnteredCity)
{
result = Convert.ToString(Zipcode[i]);
break;
}
}
string DisplayZip = result;
txtZipcode.Text = DisplayZip;
}
}
The following data is a snippet of what the data in my excel .csv looks like:
zip,primary_city
44273,Seville
44274,Sharon Center
44275,Spencer
44276,Sterling
44278,Tallmadge
44280,Valley City
44281,Wadsworth
44282,Wadsworth
44285,Wayland
And so on for about 46,000 rows.
How can I pull the zip and the primary_city into two separate arrays (I'm guessing with some ".Split "," "line) that my for-loop can operate on?
Also, if there are better ways to go about this, please let me know (but be sure to leave an explanation as I want to understand where you are coming from).
Don't create two separate array.Create a separate class for city
class City
{
public string Name{get;set;}
public int ZipCode{get;set;}
}
Now to read the data from that csv file
List<City> cities=File.ReadAllLines(path)
.Select(x=>new City
{
ZipCode=int.Parse(x.Split(',')[0]),
Name=x.Split(',')[1]
}).ToList<City>();
Or you can do this
List<City> cities=new List<City>();
foreach(String s in File.ReadAllLines(path))
{
City temp=new City();
temp.ZipCode=int.Parse(s.Split(',')[0]);
temp.Name=s.Split(',')[1];
cities.Add(temp);
}
You can try this:
string dir = System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location);
string path = dir + #"\zip_code_database_edited.csv";
var open = new StreamReader(File.OpenRead(path));
var cities = new HashList<string>();
var zipCodes = new HashList<int>();
var zipAndCity = new string[2];
string line = string.Empty;
using (open)
{
while ((line = reader.ReadLine()) != null)
{
zipAndCity = line.Split(",");
zipCodes.Add(int.Parse(zipAndCity[0]));
cities.Add(zipAndCity[1]);
}
}
I am posting this answer having learned much more about C# since I posted this question. When reading a CSV, there are better options than String.Split().
The .NET Framework already has a built-in dedicated CSV parser called TextFieldParser.
It's located in the Microsoft.VisualBasic.FileIO namespace.
Not only are there many edge cases that String.Split() is not properly equipped to handle, but it's also much slower to use StreamReader.