I've got a textfile which contains the following data:
name = Very well sir
age = 23
profile = none
birthday= germany
manufacturer = Me
And I want to get the profile, birthday and manufacturer value but can't seem to get it right. I succeded including the file into my program but there it stops. I just can't figure out how I will clean the textfile up.
Here's my current code: http://sv.paidpaste.com/HrQXbg
using System;
using System.IO;
using System.Linq;
class Program
{
static void Main()
{
var data = File
.ReadAllLines("test.txt")
.Select(x => x.Split('='))
.Where(x => x.Length > 1)
.ToDictionary(x => x[0].Trim(), x => x[1]);
Console.WriteLine("profile: {0}", data["profile"]);
Console.WriteLine("birthday: {0}", data["birthday"]);
Console.WriteLine("manufacturer: {0}", data["manufacturer"]);
}
}
I would suggest instead of using ReadToEnd, reading each line and doing a string.Split('=') and then a string.Trim() on each line text. You should be left with 2 values per line, the first being the key and the second, the value.
For example, in your reading loop:
List<string[]> myList = new List<string[]>();
string[] splits = nextLine.Split('=');
if (splits.Length == 2)
myList.Add(splits);
You need to split into lines first and then split the lines:
StreamReader reader = new StreamReader(filePath);
string line;
while(null != (line=reader.Read())
{
string[] splitLine = strLines.Split('=');
//Code to find specific items based on splitLine[0] - Example
//TODO: Need a check for splitLine length
case(splitLine[0].ToLower().Trim())
{
case "age": { age = int.Parse(splitLine[1]);
}
}
reader.Dispose();
This should make a good start for you.
Related
Hi there I have a requirement where i need to read content from a text file. The sample text content is as below.
Name=Check_Amt
Public=Yes
DateName=pp
Name=DBO
I need to read the text and only extract the value which comes after Name='What ever text'.
So I am expecting the output as Check_Amt, DBO
I need to do this in C#
When querying data (e.g. file lines) Linq is often a convenient tool; if the file has lines in
name=value
format, you can query it like this
Read file lines
Split each line into name, value pair
Filter pairs by their names
Extract value from each pair
Materialize values into a collection
Code:
using System.Linq;
...
// string[] {"Check_Amt", "DBO"}
var values = File
.ReadLines(#"c:\MyFile.txt")
.Select(line => line.Split(new char[] { '=' }, 2)) // split into name, value pairs
.Where(items => items.Length == 2) // to be on the safe side
.Where(items => items[0] == "Name") // name == "Name" only
.Select(items => items[1]) // value from name=value
.ToArray(); // let's have an array
finally, if you want comma separated string, Join the values:
// "Check_Amt,DBO"
string result = string.Join(",", values);
Another way:
var str = #"Name=Check_Amt
Public=Yes
DateName=pp
Name=DBO";
var find = "Name=";
var result = new List<string>();
using (var reader = new StringReader(str)) //Change to StreamReader to read from file
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (line.StartsWith(find))
result.Add(line.Substring(find.Length));
}
}
You can use LINQ to select what you need:
var names=File. ReadLines("my file.txt" ).Select(l=>l.Split('=')).Where(t=>t.Length==2).Where(t=>t[0]=="Name").Select(t=>t[1])
I think that the best case would be a regex.
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = #"(?<=Name=).*?(?=Public)";
string input = #"Name=Check_Amt Public=Yes DateName=pp Name=DBO";
RegexOptions options = RegexOptions.Multiline;
foreach (Match m in Regex.Matches(input, pattern, options))
{
Console.WriteLine("'{0}' found at index {1}.", m.Value, m.Index);
}
}
}
EDIT: My answer was written before your question were corrected, while it's still working the LINQ answer would be better IMHO.
I have an assignment to read text in from a text file. The text is an inventory with department names followed by the quantity of items in the department and then items underneath the separate departments with the item name, quantity, and price. A part of the text file is shown here:
Stationary, 4
Notebook, 20, .99
Pens, 50, .50
Pencils, 25, 0.09
Post It Notes, 30, 4.99
Tools, 6
Band Saw, 3, 299.99
Cresent Wrench, 12, 8.49
Circular Saw, 5, 89.99
Tile Cutter, 2, 149.99
Screwdriver, 70, 2.99
Measuring Tape, 34, 10.99
I'm able to load the text file in just fine. My task is to take in user input for them decide which department they want to shop on. How am I able to display just the departments and then just the items of the desired department from the user? I have a method to output all of the departments and items shown below. This is my first time working with text files with C# so I have no idea what I am doing.
static void ReadDepartments(out List<Dept> s)
{
string line; // detail line read from file
string[] tokens; // break line up into tokens
string deptName; // name of department
int deptQuan; // quan of different items in dept
s = new List<Dept>();
try
{
using (StreamReader sr = new StreamReader(#"..\..\inventory.txt"))
{
while (sr.Peek() >=0)
{
List<Item> myItemList = new List<Item>(); // new instance of tmp List
line = sr.ReadLine();
tokens = line.Split(',');
deptName = tokens[0];
deptQuan = Convert.ToInt32(tokens[1]);
for (int i=0; i< deptQuan; i++)
{
// read each line of dept and build a list of items
line = sr.ReadLine();
tokens = line.Split(',');
Item myItem = new Item(tokens[0], Convert.ToInt32(tokens[1]), Convert.ToDouble(tokens[2]));
myItemList.Add(myItem);
}
s.Add(new Dept(deptName,deptQuan, myItemList));
}
}
}
catch (Exception e)
{
Console.WriteLine("Can't open file because {0}", e.Message);
}
}
static void PrintInventory(List<Dept> s)
{
foreach (Dept d in s)
{
Console.WriteLine("Dept: {0,-20} [{1} items]", d.Name, d.NumItems);
for (int i = 0; i < d.NumItems; i++)
Console.WriteLine(" {0,-15} {1,4} {2,7:$,##0.00}", d.GetItem(i).Name,
d.GetItem(i).Quan, d.GetItem(i).PriceEach);
}
}
I started a method to check if the desired department is a valid department shown below. Is there an easier way to implement the valid[] variable instead of including all of the department names? I will have to error check for valid items and that seems like it would be very tedious.
static string GetDepartment(string prompt)
{
string[] valid = {"BOOKS", "FOOD", "VIDEO", "SPORTS", "STATIONARY", "TOOLS"};
string ans = GetString(prompt, valid, "Inavlid response. Please choose a department.");
return ans;
}
static string GetString(string prompt, string[] valid, string error)
{
string response;
bool OK = false;
do
{
Console.Write(prompt);
response = Console.ReadLine().ToUpper();
foreach (string s in valid) if (response == s) OK = true;
if (!OK) Console.WriteLine(error);
}
while (!OK);
return response;
}
Your method that reads from the text file results in you having a List<Dept>. So you can generate a list of valid department names by going through the list of departments that you have read from the text file.
LINQ is great for searching through data and checking if items exists and what not.
Since you have all of your departments in a List you can query it via some different methods. Either search your raw data directly
using System.Linq;
...
List<Dept> departments;
...
departments.Any(dept => dept.Name == response);
Or if you want to send the names to your GetString method:
GetString(prompt, departments.Select(dept => dept.Name), ...);
...
string GetString(string prompt, IEnumerable<string> valids, string error)
...
valids.Any(valid => valid == response);
If you want to use the Department instead you can use FirstOrDefault instead (which also takes a predicate) and check for null if the item does not exist
Department found = departments.FirstOrDefault(dept => dept.Name == response);
if (found == null) //department name does not exist
If everything is ok on your code then you can add a if statement to check whether if it is your desired department info to print. I didn't check the whole code. You also can solve this problem with Linq (it will be more smart coding then) but your code seems to me as a starter code, so may be it will be a little inefficient but I hope it will solve your problem.
static void PrintInventory(List<Dept> s,string userInputDepartmentName)
{
if(s == null && s.Count <= 0)
return;
foreach (Dept d in s)
{
if(d.Name.Equals(userInputDepartmentName))
{
Console.WriteLine("Dept: {0,-20} [{1} items]", d.Name, d.NumItems);
for (int i = 0; i < d.NumItems; i++)
Console.WriteLine("{0,-15} {1,4} {2,7:$,##0.00}", d.GetItem(i).Name,d.GetItem(i).Quan, d.GetItem(i).PriceEach);
}
}
}
So I am trying to sort a file out in a descending order.
The text file looks something like this:
%[TIMESTAMP=1441737006376][EVENT=agentStateEvent][queue=79651][agentID=61871][extension=22801][state=2][reason=0]%
%[TIMESTAMP=1441737006102][EVENT=agentStateEvent][queue=79654][agentID=62278][extension=22828][state=2][reason=0]%
%[TIMESTAMP=1441737006105][EVENT=CallControlTerminalConnectionTalking][callID=2619][ucid=10000026191441907765][deviceType=1][deviceName=21775][Queue=][Trunk=384:82][TrunkType=1][TrunkState=1][Cause=100][CalledDeviceID=07956679058][CallingDeviceID=21775][extension=21775]%
and basically I want the end result to only output unique values of the timestamp. I have used substring to get rid of the excess text, and it outputs fine as shown below:
[TIMESTAMP=1441737006376]
[TIMESTAMP=1441737006102]
[TIMESTAMP=1441737006105]
however i want it to order in the following order (basically numeric descending to ascending):
[TIMESTAMP=1441737006102]
[TIMESTAMP=1441737006105]
[TIMESTAMP=1441737006376]
I have tried the .sort and .orderBy but not having any joy. I wouldve using this prior to doing any substring formatting wouldve sufficed but clearly not.
Code is as follows:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FedSorter
{
class Program
{
static void Main(string[] args)
{
int counter = 0;
string line;
string readIn = "C:\\Users\\xxx\\Desktop\\Files\\ex1.txt";
System.IO.TextWriter writeOut = new StreamWriter("C:\\Users\\xxx\\Desktop\\Files\\ex1_new.txt");
List<String> list = new List<String>();
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(readIn);
string contents = "";
string checkValues = "";
while ((line = file.ReadLine()) != null)
{
string text = line;
text = text.Substring(1, 25);
if (!checkValues.Contains(text))
{
list.Add(text);
Console.WriteLine(text);
writeOut.WriteLine(text);
counter++;
}
contents = text;
checkValues += contents + ",";
}
list = list.OrderBy(x => x).ToList();
writeOut.Close();
file.Close();
orderingFile();
}
public static void orderingFile()
{
string line = "";
string readIn = "C:\\Users\\xxx\\Desktop\\Files\\ex1_new.txt";
System.IO.TextWriter writeOut = new StreamWriter("C:\\Users\\xxx\\Desktop\\Files\\ex1_new2.txt");
List<String> ordering = new List<String>();
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(readIn);
while ((line = file.ReadLine()) != null)
{
ordering.OrderBy(x => x).ToList();
ordering.Add(line);
writeOut.WriteLine(line);
}
writeOut.Close();
file.Close();
}
}
}
You are creating a new list and you need to assign it to the variable
list = list.OrderBy(x => x).ToList();
However it doesn't look like you even use list after you create and sort it. Additionally you have the same issue in the orderingFile method with
ordering.OrderBy(x => x).ToList();
However instead of sorting and creating a new list on each line it would be better to use a SortedList<TKey, TValue> that will keep the contents sorted as you add to it.
But again you are not actually using the ordering list after you finish adding to it in the foreach. If you are looking to read the values in a file, sort them and then output them to another file, then you need to do it in that order.
Aside from #juharr's correct answer, you would do well to take advantage of LINQ to simplify your code greatly.
string readIn = "C:\\Users\\xxx\\Desktop\\Files\\ex1.txt";
var timestamps = File.ReadAllLines(readIn)
.Select(l => l.Substring(1, 25))
.Distinct()
.OrderBy(t => t)
.ToArray();
To write out the values, you can either use a foreach on timestamps and write out each line to your TextWriter, or you can use the File class again:
string readOut = "C:\\Users\\xxx\\Desktop\\Files\\ex1_new.txt";
File.WriteAllLines(readOut, timestamps);
//notice I've changed it to ToArray in the first part instead of ToList.
it prints all the names from last name to fist in the text file but i am stuck trying to print it in alphabetical order by last name
here is the code i have so far:
namespace cse1302_Lecture18_FileIO_Prez
{
class Program
{
static void Main(string[] args)
{
StreamReader sr = new StreamReader("NameInput.txt"); //if file in bin/debug
char[] delims = {','};
//string[] names = {"",""};
while(!sr.EndOfStream)
{
string data_line = sr.ReadLine();
//names = data_line.Split(delims);
Console.WriteLine(data_line);
}
sr.Close();
}
}
}
Try using LINQ. I've assumed here that you file contains two fields per line delimited with a comma, where the first is the First Name and the second the Surname.
var lines = System.IO.File.ReadLines("NameInput.txt");
var linesOrderedBySurname = lines.OrderBy((p) => p.Split(',')[1]).ToList();
First store the names into a list, then sort them based on last name like:
var names = new List<string>();
while(!sr.EndOfStream)
{
names.Add(sr.ReadLine());
}
names.Sort((x, y) => x.Split(',')[1].CompareTo(y.Split(',')[1]));
Then just display list items in the console.
foreach(var name in names)
Console.WriteLine(name);
This assumes that last name comes after first name and they are delimited with a comma.
Try to use File.ReadAllLines instead of StreamReader you need to load all lines of the file and then use LINQ to order them
static void Main(string[] args)
{
var lastNames = File.ReadAllLines("yourtxtfile.txt").OrderBy(line => line.Split(',')[1]);
}
I have seen several posts giving examples of how to read from text files, and examples on how to make a string 'public' (static or const), but I haven't been able to combine the two inside a 'function' in a way that is making sense to me.
I have a text file called 'MyConfig.txt'.
In that, I have 2 lines.
MyPathOne=C:\TestOne
MyPathTwo=C:\TestTwo
I want to be able to read that file when I start the form, making both MyPathOne and MyPathTwo accessible from anywhere inside the form, using something like this :
ReadConfig("MyConfig.txt");
the way I am trying to do that now, which is not working, is this :
public voice ReadConfig(string txtFile)
{
using (StreamReader sr = new StreamResder(txtFile))
{
string line;
while ((line = sr.ReadLine()) !=null)
{
var dict = File.ReadAllLines(txtFile)
.Select(l => l.Split(new[] { '=' }))
.ToDictionary( s => s[0].Trim(), s => s[1].Trim());
}
public const string MyPath1 = dic["MyPathOne"];
public const string MyPath2 = dic["MyPathTwo"];
}
}
The txt file will probably never grow over 5 or 6 lines, and I am not stuck on using StreamReader or dictionary.
As long as I can access the path variables by name from anywhere, and it doesn't add like 400 lines of code or something , then I am OK with doing whatever would be best, safest, fastest, easiest.
I have read many posts where people say the data should stored in XML, but I figure that part really doesn't matter so much because reading the file and getting the variables part would be almost the same either way. That aside, I would rather be able to use a plain txt file that somebody (end user) could edit without having to understand XML. (which means of course lots of checks for blank lines, does the path exist, etc...I am OK with doing that part, just wanna get this part working first).
I have read about different ways using ReadAllLines into an array, and some say to create a new separate 'class' file (which I don't really understand yet..but working on it). Mainly I want to find a 'stable' way to do this.
(project is using .Net4 and Linq by the way)
Thanks!!
The code you've provided doesn't even compile. Instead, you could try this:
public string MyPath1;
public string MyPath2;
public void ReadConfig(string txtFile)
{
using (StreamReader sr = new StreamReader(txtFile))
{
// Declare the dictionary outside the loop:
var dict = new Dictionary<string, string>();
// (This loop reads every line until EOF or the first blank line.)
string line;
while (!string.IsNullOrEmpty((line = sr.ReadLine())))
{
// Split each line around '=':
var tmp = line.Split(new[] { '=' },
StringSplitOptions.RemoveEmptyEntries);
// Add the key-value pair to the dictionary:
dict[tmp[0]] = dict[tmp[1]];
}
// Assign the values that you need:
MyPath1 = dict["MyPathOne"];
MyPath2 = dict["MyPathTwo"];
}
}
To take into account:
You can't declare public fields into methods.
You can't initialize const fields at run-time. Instead you provide a constant value for them at compilation time.
Got it. Thanks!
public static string Path1;
public static string Path2;
public static string Path3;
public void ReadConfig(string txtFile)
{
using (StreamReader sr = new StreamReader(txtFile))
{
var dict = new Dictionary<string, string>();
string line;
while (!string.IsNullOrEmpty((line = sr.ReadLine())))
{
dict = File.ReadAllLines(txtFile)
.Select(l => l.Split(new[] { '=' }))
.ToDictionary( s => s[0].Trim(), s => s[1].Trim());
}
Path1 = dict["PathOne"];
Path2 = dict["PathTwo"];
Path3 = Path1 + #"\Test";
}
}
You need to define the variables outside the function to make them accessible to other functions.
public string MyPath1; // (Put these at the top of the class.)
public string MyPath2;
public voice ReadConfig(string txtFile)
{
var dict = File.ReadAllLines(txtFile)
.Select(l => l.Split(new[] { '=' }))
.ToDictionary( s => s[0].Trim(), s => s[1].Trim()); // read the entire file into a dictionary.
MyPath1 = dict["MyPathOne"];
MyPath2 = dict["MyPathTwo"];
}
This question is similar to Get parameters out of text file
(I put an answer there. I "can't" paste it here.)
(Unsure whether I should "flag" this question as duplicate. "Flagging" "closes".)
(Do duplicate questions ever get consolidated? Each can have virtues in the wording of the [often lame] question or the [underreaching and overreaching] answers. A consolidated version could have the best of all, but consolidation is rarely trivial.)