C# - From Text File to Array (Index out of bounds - StreamReader) - c#

I am very new to programming and learning C# and I have encountered a problem with using array:
(Not using list)
I have a text file with three rows (Adam Evert Jonson) named names.txt, and I want to add these to an array that can hold three elements. When creating the array I am told the index is out of bounds. I guess I am missing something obvious, a loop or such?
This is for me learning StreamReader.
thank you for your time.
using System;
using System.IO;
class Program {
public static void Main(string\[\] args) {
Names.Load();
}
}
class Names {
string firstName;
string middleName;
string lastName;
public static void Load() {
StreamReader file = new StreamReader("names.txt");
string r;
while ((r = file.ReadLine()) != null) {
string[] field = r.Split('\t');
string firstName = field[0];
string middleName = field[1];
string lastName = field[2];
Names m = new Names();
m.firstName = firstName;
m.middleName = middleName;
m.lastName = lastName;
}
file.Close();
}
}

As suggested by Johnny Mopp, make sure there are three elements in the "field" array:
string[] field = r.Split('\t');
if (field.Length == 3) {
string firstName = field[0];
string middleName = field[1];
string lastName = field[2];
Names m = new Names();
m.firstName = firstName;
m.middleName = middleName;
m.lastName = lastName;
// "m" is local, so it won't be avaialble outside
// the while loop, do something with it?
// ... do something with "m" ...
}
You could also use if (field.Length >= 3), to make sure there are AT LEAST THREE values in the array, and you would just be ignoring the rest.
If you only want to read that very first line, then exit the loop after getting your data.

To read plain files such as .txt or .csv files I would recommend to use FileHelpers library.
You need to first install it through 'Manage NuGet Packages'
Hit the 'Browse' tab
Type 'FileHelpers'
Install the latest version your solution supports.
Then you would need to create a model class with the properties.
using FileHelpers;
[DelimitedRecord(",")]
public class Names
{
public string firstName;
public string middleName;
public string lastName;
}
Your names.txt file should look something like:
Albus, Percival, Dumbledore
Albus, Severus, Potter
Where each line would be a 'Person' but will be parsed as your 'Names' class.
In your program class you need the next code:
var engine = new FileHelperEngine<Names>();
// To Read Use:
var result = engine.ReadFile("names.txt"); //You should put the route to your file here
// result is now an array of Names
You can see the result:
foreach (Names name in result)
{
Console.WriteLine("Names:");
Console.WriteLine(name.firstName + " - " + name.middleName+ " - " + name.lastName);
}
You can check more of this library in: FileHelpers QuickStart

Related

how to take specific column from text file(.txt) with delimiters with C#

I have example data like this , the data is in the text file(.txt) sry i got this type of file, if its excel or csv maybe it will be easier
Edit : i make a console app with C#
FamilyID;name;gender;DOB;Place of birth;status
1;nicky;male;01-01-1998;greenland;married
1;sonia;female;02-02-1995;greenland;married
2;dicky;male;04-01-1995;bali;single
3;redding;male;01-05-1996;USA;single
3;sisca;female;05-03-1994;australia;married
i want to take the specific column from that data, for example i want to take FamilyID,Name and status.
I already tried some code to read data and take all the data and list it to new text file.
The goal is to create a new text file based on family ID, and only take specific columns.
The problem is : i cant take a specific column that i want from text file (don't know how to select many column in the code that i write)
DateTime date = DateTime.Now;
string tgl = date.Date.ToString("dd");
string bln = date.Month.ToString("d2");
string thn = date.Year.ToString();
string tglskrg = thn + "/" + bln + "/" + tgl;
string filename = ("C:\\Users\\Documents\\My Received Files\\exampledata.txt");
string[] liness = File.ReadAllLines(filename);
string[] col;
var lines = File.ReadAllLines(filename);
var groups = lines.Skip(1)
.Select(x => x.Split(';'))
.GroupBy(x => x[0]).ToArray();
foreach (var group in groups)
{
Console.WriteLine(group);
File.WriteAllLines(#"C:\\Users\\Documents\\My Received Files\\exampledata_"+group.Key+".txt", group.Select(x => string.Join(";", x)));
}
maybe someone can help? thankyou
One way to approach this would be capture the details to a data structure and later write the required details to file. For example,
public class Detail
{
public int FamilyID{get;set;}
public string Name{get;set;}
public string Gender{get;set;}
public DateTime DOB{get;set;}
public string PlaceOfBirth{get;set;}
public string Status{get;set;}
}
Now you can write a method that parses the string based on delimiter and returns an IEnumerable.
public IEnumerable<Detail> Parse(string source,char delimiter)
{
return source.Split(new []{Environment.NewLine},StringSplitOptions.RemoveEmptyEntries)
.Skip(1)
.Select(x=>
{
var detail = x.Split(new []{delimiter});
return new Detail
{
FamilyID = Int32.Parse(detail[0]),
Name = detail[1],
Gender = detail[2],
DOB = DateTime.Parse(detail[3]),
PlaceOfBirth = detail[4],
Status = detail[5]
};
}
);
}
Client Call
Parse(stringFromFile,';');
Output
Now you can pick and write the details you want to write to output file from the collection.
try this.
var list = new List<String>();
list.Add("FamilyID;name;gender;DOB;Place of birth;status");
list.Add("1;nicky;male;01-01-1998;greenland;married");
list.Add("1;sonia;female;02-02-1995;greenland;married");
list.Add("2;dicky;male;04-01-1995;bali;single");
list.Add("3;redding;male;01-05-1996;USA;single");
list.Add("3;sisca;female;05-03-1994;australia;married");
var group = from item in list.Skip(1)
let splitItem = item.Split(';', StringSplitOptions.RemoveEmptyEntries)
select new
{
FamilyID = splitItem[0],
Name = splitItem[1],
Status = splitItem[5],
};
foreach(var item in group.ToList())
{
Console.WriteLine($"Family ID: {item.FamilyID}, Name: {item.Name}, Status: {item.Status}");
}

How to add a string to a specific line in a text file using C#

i need your help,
i'm trying to add a string "MyString" to a specific line in a text file but couldn't yet.
for exmple
this is the content of my Text file :
First Name.
Last Name.
Date of Birth.
Counrty.
now what i'm looking for is add "MyString" will be "City" just in the next line after the word "Date of Birth". so the result can be like this :
First Name.
Last Name.
Date of Birth.
City.
Counrty.
I've tried:
File.AppendAllText(#"C:\\Users\\Volki\\Desktop\\TextFile.txt",
string.Format("{0}{1}", "Date of Birth.", "City"));
try Something like this:
string PathFile=#"c:\temp\testxx.TXT";
List<string> Listvalue = File.ReadAllLines(PathFile).ToList();
int IndexSearch = Listvalue.IndexOf("Date of Birth.");
if (IndexSearch>=0)
{
Listvalue.Insert(IndexSearch+1, "City.");
File.WriteAllLines(PathFile, Listvalue.ToArray());
}
Create string[] currFile and read from your file into it (you will get array with 4 elements in it)
Create another string[] newFile but with size of currFile.Length + 1
Copy currFile to newFile but forth line set to fifth (into new file you have first 3 lines, one empty and fifth line.
Store city into newFile's forth line
Save that to text file
If i made some mistake post in comment, i set this up in hurry
EDIT:
What you probably do is use Newtonsoft.Json so you have class:
public User
{
public string FirstName;
public string LastName;
public DateTime dateOfBirth;
public string Country;
}
And then you use it like this:
public MyClass
{
public MyClass()
{
User user = new User();
user.FirstName = "User1";
...
WriteUser(user);
User user1 = ReadUser();
string username = user1.FirstName;
}
void WriteUser(User user)
{
string stringToWriteToFile = JsonConvert.SerializeObject(user);
//Write this string to file
}
User ReadUser()
{
string stringFromFile = ...
return JsonConvert.DeserializeObject<User>(stringFromFile);
}
}

List, strings and vs Template

I'm having a list of strings whit some values and I want to make some kind of variable for keeping code that I will be using in template file.
For example lets say I have list with this 3 string values: configService, scaleCoefConfigService, sessionService. Name of the list is chItemName.
And I need to generate this kind of code that I will parse later into template:
[Dependency("configService")]
[Dependency("scaleCoefConfigService")]
[Dependency("sessionService")]
So my question is can make some variable and mechanism for iterating thou list of strings that adds every single item from list to variable?
I've tried this:
foreach (var tp in controllerChecked)
{
var genCode = "[Dependency](" '"' + chItemName + '"'")] \n"
}
controllerChecked is collection of objects and one of the objects value is Name that I'm getting like this:
var chItemName = controllerChecked.Select(c => c.Name).ToList();
This is how the list chItemName is getting those strings.
But of course it is impossible to use + with lists and this kind of stuff will never work. Someone has better idea?
In your example, you are not using the tp variable, which contains will contain each of the values within controllerChecked, one at a time.
You could just iterate through the chItemName list and add the result to a StringBuilder:
StringBuilder codeBuilder = new StringBuilder();
foreach (string tp in chItemName)
{
codeBuilder.AppendLine("[Dependency(\"" + tp + "\")]");
}
string code = codeBuilder.ToString();
If controllerChecked contains more information, you could also directly access it:
StringBuilder codeBuilder = new StringBuilder();
foreach (var item in controllerChecked)
{
string propertyName = item.Name.SubString(1);
codeBuilder.AppendLine("[Dependency(\"" + item.Name + "\")]");
codeBuilder.AppendLine("public " + item.Type + " " + propertyName + " { get; set; }");
codeBuilder.AppendLine();
}
string code = codeBuilder.ToString();
PS. I would definitely change the name of chItemName to chItemNames as it is a list, but that is up to you of course.
This worked perfectly good. I have little bit harder version of this, if you can figure out how to do this:
Lets say that instead of one chItemName list I have 2 more: fName and chItemType, both are string lists.
And I have to generate this kind of code:
[Dependency("alarmsService")]
public IAlarmsService AlarmsService { get; set; }
[Dependency("jsonFactory")]
public IJSONFactoryService JsonFactory { get; set; }
[Dependency("dataBean")]
public IDataBean DataBean { get; set; }
alarmsServise, jsonFactory and dataBean are items of chItemName.
IAlarmsService, IJSONFactoryService and IDataBean are items of chItemType.
AlarmsService, Json Factory and DataBean are items of fName list.
fName is list that I got from chItemType by trimming the first letter from each string in list:
List<string> fName = new List<string>();
foreach(var i in chItemType)
{
var newName = i.Remove(0,1);
fName.Add(newName);
}
So only that list is not a part of controllerChecked list. The othere two are defined like this:
var chItemType = controllerChecked.Select(c => c.Type).ToList();
var chItemName = controllerChecked.Select(c => c.Name).ToList();
Can I edit foreach somehow or maybe I can make parts of code with StringBulider and after that merged them together?

Load data from txt file to comboBox

Hi i have this structure of txt file:
Lukas 1
Zdenek 3
Martin 2
Kate 1
And i need load this data...the name i need load to comboBox...and when i choose from ComboBox for example Lukas, i need to save Name Lukas to variable Name and number 1 to variable Number...
It is possible?
I have this code now...
using (StreamReader reader = new StreamReader(#"C:\Us...nka\example.txt"))
{
string data = "";
data = reader.ReadToEnd().Trim();
}
But i need read separately Name and separately Number...Have you any ideas? Thanks..
You can use File.ReadLines and String.Split:
var lines = File.ReadLines(#"C:\Us...nka\example.txt");
var data = lines.Select(l => l.Split());
I would use a class to store both properties:
public class Person
{
public int PersonID { get; set; }
public string PersonName { get; set; }
}
Now you can load the persons in a loop or with LINQ:
List<Person> allPersons = data
.Where(arr => arr.Length >= 2 && arr[1].Trim().All(Char.IsDigit))
.Select(arr => new Person
{
PersonName = arr[0].Trim(),
PersonID = int.Parse(arr[1].Trim())
})
.ToList();
Edit:
Yes thanks...but i cant load PersonsName to combobox
You can use a BindingSource for the ComboBox. Then set the DisplayMember and ValueMember properties accordingly:
var bindingSourcePersons = new BindingSource();
bindingSourcePersons.DataSource = allPersons;
personComboBox.DataSource = bindingSourcePersons.DataSource;
personComboBox.ValueMember = "PersonID";
personComboBox.DisplayMember = "PersonName";
First create a class like this:
public class Person {
public string Name {get;set;}
public int Number {get;set;}
}
then you can use Linq to convert the string you read like this:
var people = data
.Split(new {'\r','\n'}, StringSplitOptions.RemoveEmptyEntries)
.Select(d => new Person { Name = d.Split(' ')[0], Value = int.Parse(d.Split(' ')[1])})
.ToList();
Or better you could read your data line by line, like this:
var people = from l in File.ReadLines(#"C:\Us...nka\example.txt")
let parts = l.Split(' ')
select new Person {
Name = parts[0].Trim(),
Value = int.Parse(parts[1].Trim())
};
here is a pseudo:
while the reader is not EndOfStream
read current line
split the line that was just read into a string[] array, the separator being a space
first item in the array would be the name and the second item in the array would be the number.
then you add the item in the combo box. The combobox has an Items collection and an add method, which just takes a System.Object.
http://msdn.microsoft.com/en-us/library/aa983551(v=vs.71).aspx

Column headers in CSV using fileHelpers library?

Is there a built-in field attribute in the FileHelper library which will add a header row in the final generated CSV?
I have Googled and didn't find much info on it. Currently I have this:
DelimitedFileEngine _engine = new DelimitedFileEngine(T);
_engine.WriteStream
(HttpContext.Current.Response.Output, dataSource, int.MaxValue);
It works, but without a header.
I'm thinking of having an attribute like FieldTitleAttribute and using this as a column header.
So, my question is at which point do I check the attribute and insert header columns? Has anyone done something similar before?
I would like to get the headers inserted and use custom text different from the actual field name just by having an attribute on each member of the object:
[FieldTitleAttribute("Custom Title")]
private string Name
and maybe an option to tell the engine to insert the header when it's generated.
So when WriteStream or WriteString is called, the header row will be inserted with custom titles.
I have found a couple of Events for DelimitedFileEngine, but not what's the best way to detect if the current record is the first row and how to insert a row before this.
I know this is an old question, but here is an answer that works for v2.9.9
FileHelperEngine<Person> engine = new FileHelperEngine<Person>();
engine.HeaderText = engine.GetFileHeader();
Here's some code that'll do it: https://gist.github.com/1391429
To use it, you must decorate your fields with [FieldOrder] (a good FileHelpers practice anyway). Usage:
[DelimitedRecord(","), IgnoreFirst(1)]
public class Person
{
// Must specify FieldOrder too
[FieldOrder(1), FieldTitle("Name")]
string name;
[FieldOrder(2), FieldTitle("Age")]
int age;
}
...
var engine = new FileHelperEngine<Person>
{
HeaderText = typeof(Person).GetCsvHeader()
};
...
engine.WriteFile(#"C:\people.csv", people);
But support for this really needs to be added within FileHelpers itself. I can think of a few design questions off the top of my head that would need answering before it could be implemented:
What happens when reading a file? Afaik FileHelpers is currently all based on ordinal column position and ignores column names... but if we now have [FieldHeader] attributes everywhere then should we also try matching properties with column names in the file? Should you throw an exception if they don't match? What happens if the ordinal position doesn't agree with the column name?
When reading as a data table, should you use A) the field name (current design), or B) the source file column name, or C) the FieldTitle attribute?
I don't know if you still need this, but here is the way FileHelper is working :
To include headers of columns, you need to define a string with headers delimited the same way as your file.
For example with '|' as delimiter :
public const string HeaderLine = #"COLUMN1|COLUMN2|COLUMN3|...";
Then, when calling your engine :
DelimitedFileEngine _engine = new DelimitedFileEngine<T> { HeaderText = HeaderLine };
If you don't want to write the headers, just don't set the HeaderText attribute on the engine.
List<MyClass> myList = new List<MyClass>();
FileHelperEngine engine = new FileHelperEngine(typeof(MyClass));
String[] fieldNames = Array.ConvertAll<FieldInfo, String>(typeof(MyClass).GetFields(), delegate(FieldInfo fo) { return fo.Name; });
engine.HeaderText = String.Join(";", fieldNames);
engine.WriteFile(MapPath("MyClass.csv"), myList);
Just to include a more complete example, which would have saved me some time, for version 3.4.1 of the FileHelpers NuGet package....
Given
[DelimitedRecord(",")]
public class Person
{
[FieldCaption("First")]
public string FirstName { get; set; }
[FieldCaption("Last")]
public string LastName { get; set; }
public int Age { get; set; }
}
and this code to create it
static void Main(string[] args)
{
var people = new List<Person>();
people.Add(new Person() { FirstName = "James", LastName = "Bond", Age = 38 });
people.Add(new Person() { FirstName = "George", LastName = "Washington", Age = 43 });
people.Add(new Person() { FirstName = "Robert", LastName = "Redford", Age = 28 });
CreatePeopleFile(people);
}
private static void CreatePeopleFile(List<Person> people)
{
var engine = new FileHelperEngine<Person>();
using (var fs = File.Create(#"c:\temp\people.csv"))
using (var sw = new StreamWriter(fs))
{
engine.HeaderText = engine.GetFileHeader();
engine.WriteStream(sw, people);
sw.Flush();
}
}
You get this
First,Last,Age
James,Bond,38
George,Washington,43
Robert,Redford,28
I found that you can use the FileHelperAsyncEngine to accomplish this. Assuming your data is a list called "output" of type "outputData", then you can write code that looks like this:
FileHelperAsyncEngine outEngine = new FileHelperAsyncEngine(typeof(outputData));
outEngine.HeaderText = "Header1, Header2, Header3";
outEngine.BeginWriteFile(outputfile);
foreach (outputData line in output){
outEngine.WriteNext(line);
}
outEngine.Close();
You can simply use FileHelper's GetFileHeader function from base class
var engine = new FileHelperEngine<ExportType>();
engine.HeaderText = engine.GetFileHeader();
engine.WriteFile(exportFile, exportData);

Categories

Resources