Streamreader Line with commas into a dictionary - c#

I have a text file that contains lines and each line is seperated with a comma.
I want to put the data on the dictionary that will get the key and value based on the text file's values that are seperated in comma on each line.
txt row example:
{
key, value
}
I first get the data in a loop. If it was simply a string then i would know how to do it but the fact that i am firstly reading it from a streamReader it gives me problems. In a normal list it also worked but in this method it just doesn't work on the dictionary. Here is the code:
StreamReader sr = new StreamReader("Text.txt");
string line;
int i = 0;
while ((line = sr.ReadLine()) != null)
{
string[] arr = line.Split(',');
dict.Add(arr[i], arr[i + 1]);
i= i+2;
}
I got stuck in the dict.Add . I know it shouldn't be the arr as i wrote.
Thanks for any help!

Your question is almost impossibly unclear. But from what I could decipher, you either need another while loop:
StreamReader sr = new StreamReader("Text.txt");
string line;
while ((line = sr.ReadLine()) != null)
{
string[] arr = line.Split(',');
int i = 0;
while (i < arr.Length)
{
dict.Add(arr[i], arr[i + 1]);
i+=2;
}
}
Or your need forget about your i variable entirely:
StreamReader sr = new StreamReader("Text.txt");
string line;
while ((line = sr.ReadLine()) != null)
{
string[] arr = line.Split(',');
dict.Add(arr[0], arr[1]);
}
One of those should be right. Which one depends on whether you have multiple sets of values per line or not. The text of your question makes this impossible to guess.
And fwiw, string.Split() is usually a really horrible way to handle comma-separated data.

Related

asp.net MVC Seed a database from a .TXT file with code first (over 10000 words) [duplicate]

I am using a list to limit the file size since the target is limited in disk and ram.
This is what I am doing now but is there a more efficient way?
readonly List<string> LogList = new List<string>();
...
var logFile = File.ReadAllLines(LOG_PATH);
foreach (var s in logFile) LogList.Add(s);
var logFile = File.ReadAllLines(LOG_PATH);
var logList = new List<string>(logFile);
Since logFile is an array, you can pass it to the List<T> constructor. This eliminates unnecessary overhead when iterating over the array, or using other IO classes.
Actual constructor implementation:
public List(IEnumerable<T> collection)
{
...
ICollection<T> c = collection as ICollection<T>;
if( c != null) {
int count = c.Count;
if (count == 0)
{
_items = _emptyArray;
}
else {
_items = new T[count];
c.CopyTo(_items, 0);
_size = count;
}
}
...
}
A little update to Evan Mulawski answer to make it shorter
List<string> allLinesText = File.ReadAllLines(fileName).ToList()
Why not use a generator instead?
private IEnumerable<string> ReadLogLines(string logPath) {
using(StreamReader reader = File.OpenText(logPath)) {
string line = "";
while((line = reader.ReadLine()) != null) {
yield return line;
}
}
}
Then you can use it like you would use the list:
var logFile = ReadLogLines(LOG_PATH);
foreach(var s in logFile) {
// Do whatever you need
}
Of course, if you need to have a List<string>, then you will need to keep the entire file contents in memory. There's really no way around that.
You can simple read this way .
List<string> lines = System.IO.File.ReadLines(completePath).ToList();
[Edit]
If you are doing this to trim the beginning of a log file, you can avoid loading the entire file by doing something like this:
// count the number of lines in the file
int count = 0;
using (var sr = new StreamReader("file.txt"))
{
while (sr.ReadLine() != null)
count++;
}
// skip first (LOG_MAX - count) lines
count = LOG_MAX - count;
using (var sr = new StreamReader("file.txt"))
using (var sw = new StreamWriter("output.txt"))
{
// skip several lines
while (count > 0 && sr.ReadLine() != null)
count--;
// continue copying
string line = "";
while ((line = sr.ReadLine()) != null)
sw.WriteLine(line);
}
First of all, since File.ReadAllLines loads the entire file into a string array (string[]), copying to a list is redundant.
Second, you must understand that a List is implemented using a dynamic array under the hood. This means that CLR will need to allocate and copy several arrays until it can accommodate the entire file. Since the file is already on disk, you might consider trading speed for memory and working on disk data directly, or processing it in smaller chunks.
If you need to load it entirely in memory, at least try to leave in an array:
string[] lines = File.ReadAllLines("file.txt");
If it really needs to be a List, load lines one by one:
List<string> lines = new List<string>();
using (var sr = new StreamReader("file.txt"))
{
while (sr.Peek() >= 0)
lines.Add(sr.ReadLine());
}
Note: List<T> has a constructor which accepts a capacity parameter. If you know the number of lines in advance, you can prevent multiple allocations by preallocating the array in advance:
List<string> lines = new List<string>(NUMBER_OF_LINES);
Even better, avoid storing the entire file in memory and process it "on the fly":
using (var sr = new StreamReader("file.txt"))
{
string line;
while ((line = sr.ReadLine()) != null)
{
// process the file line by line
}
}
Don't store it if possible. Just read through it if you are memory constrained. You can use a StreamReader:
using (var reader = new StreamReader("file.txt"))
{
var line = reader.ReadLine();
// process line here
}
This can be wrapped in a method which yields strings per line read if you want to use LINQ.
//this is only good in .NET 4
//read your file:
List<string> ReadFile = File.ReadAllLines(#"C:\TEMP\FILE.TXT").ToList();
//manipulate data here
foreach(string line in ReadFile)
{
//do something here
}
//write back to your file:
File.WriteAllLines(#"C:\TEMP\FILE2.TXT", ReadFile);
List<string> lines = new List<string>();
using (var sr = new StreamReader("file.txt"))
{
while (sr.Peek() >= 0)
lines.Add(sr.ReadLine());
}
i would suggest this... of Groo's answer.
string inLine = reader.ReadToEnd();
myList = inLine.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList();
I also use the Environment.NewLine.toCharArray as well, but found that didn't work on a couple files that did end in \r\n. Try either one and I hope it works well for you.
string inLine = reader.ReadToEnd();
myList = inLine.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList();
This answer misses the original point, which was that they were getting an OutOfMemory error. If you proceed with the above version, you are sure to hit it if your system does not have the appropriate CONTIGUOUS available ram to load the file.
You simply must break it into parts, and either store as List or String[] either way.

MemoryStream to string[]

I read the content of a CSV file from a zip file in memory(the requirment is not to write to disk) into the MemoryStream. and use to following code to get the human readable string
string result = Encoding.ASCII.GetString(memoryStream.ToArray());
However, we would like the result to be a string[] to map each row in the CSV file.
Is there a way to handle this automatically?
Thanks
Firstly, there's no need to call ToArray on the memory stream. Just use a StreamReader, and call ReadLine() repeatedly:
memoryStream.Position = 0; // Rewind!
List<string> rows = new List<string>();
// Are you *sure* you want ASCII?
using (var reader = new StreamReader(memoryStream, Encoding.ASCII))
{
string line;
while ((line = reader.ReadLine()) != null)
{
rows.Add(line);
}
}
You can use Split method to split string by newlines:
string[] result = Encoding.
ASCII.
GetString(memoryStream.ToArray()).
Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
Depending on the contents of your CSV file, this can be a much harder problem than you're giving it credit for.
assume this is your csv:
id, data1, data2
1, some data, more data
2, "This element has a new line
right in the middle of the field", and that can create problems if you're reading line by line
If you simply read this in line by line with reader.ReadLine(), you're not going to get what you want if you happen to have quoted fields with new lines in the middle (which is generally allowed in CSVs). you need something more like this
List<String> results = new List<string>();
StringBuilder nextRow = new StringBuilder();
bool inQuote = false;
char nextChar;
while(reader.ReadChar(out nextChar)){ // pretend ReadChar reads a char into nextChar and returns false when it hits EOF
if(nextChar == '"'){
inQuote = !inQuote;
} else if(!inQuote && nextChar == '\n'){
results.Add(nextRow.ToString());
nextRow.Length = 0;
} else{ nextString.Append(nextChar); }
}
note that this handles double quotes. Missing quotes will be a problem, but they always are in .csv files.

How to add lines of a text file into individual items on a ListBox (C#)

How would it be possible to read a text file with several lines, and then to put each line in the text file on a separate row in a ListBox?
The code I have so far:
richTextBox5.Text = File.ReadAllText("ignore.txt");
String text = File.ReadAllText("ignore.txt");
var result = Regex.Split(text, "\r\n|\r|\n");
foreach(string s in result)
{
lstBox.Items.Add(s);
}
string[] lines = System.IO.File.ReadAllLines(#"ignore.txt");
foreach (string line in lines)
{
listBox.Items.Add(line);
}
Write a helper method that return the collection of lines
static IEnumerable<string> ReadFromFile(string file)
{// check if file exist, null or empty string
string line;
using(var reader = File.OpenText(file))
{
while((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
use it
var lines = ReadFromFile(myfile);
myListBox.ItemsSource = lines.ToList(); // or change it to ObservableCollection. also you can add to the end line by line with myListBox.Items.Add()
You should use a streamreader to read the file one line at a time.
using (StreamReader sr = new StreamReader("ignore.txt"))
{
string line;
while ((line = sr.ReadLine()) != null)
listBox1.Items.Add(line);
}
StreamReader info -> http://msdn.microsoft.com/en-us/library/system.io.streamreader.aspx
ListBox info -> http://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.aspx

C#: Searching for a keyword in a txt file

I have a problem reading a comma-delimited TXT file. This is what I am trying to do. I'm searching a text file for a keyword and then, when I've found the line containing that keyword, getting the whole line of comma-delimited keywords into a string array. How can I do this?
Thanks
System.IO.StreamReader file = new System.IO.StreamReader("c:\\test.txt");
String line;
String[] array;
while((line = file.ReadLine()) != null)
{
if (line.Contains("myString"))
{
array = line.Split(',');
}
}
file.Close();
In the if part yo can save your comma separated strings to an array
Basically, you're going to want to read the file line by line and check each of those lines for your string. When you find it, you'll take that line and split it into an array.
string temp = "";
string[] list;
IO.FileStream file = new IO.FileStream("MyFile.txt", IO.FileMode.Open);
IO.StreamReader reader = new IO.StreamReader(file);
While (!reader.EndOfStream)
{
temp = reader.ReadLine();
if (temp.Contains("myString")
{
list = temp.split(",");
break;
}
}
reader.close();

How to skip first line and start reading file from second line in C#

How to start reading file from 2nd line skipping 1st line. This seems to work but is it best way to do so?
using (StreamReader sr = new StreamReader(varFile, Encoding.GetEncoding(1250))) {
string[] stringSeparator = new string[] { "\",\"" };
int i = 0;
while (!sr.EndOfStream) {
string line = sr.ReadLine(); //.Trim('"');
if (i > 0) {
string[] values = line.Split(stringSeparator, StringSplitOptions.None);
for (int index = 0; index < values.Length; index++) {
MessageBox.Show(values[index].Trim('"'));
}
}
i++;
}
}
If the file is not very large and can fit in memory:
foreach (var line in File.ReadAllLines(varFile, Encoding.GetEncoding(1250)).Skip(1))
{
string[] values = line.Split(',');
...
}
If not write an iterator:
public IEnumerable<string> ReadAllLines(string filename, Encoding encoding)
{
using (var reader = new StreamReader(filename, encoding))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
and then consume it:
foreach (var line in ReadAllLines(varFile, Encoding.GetEncoding(1250)).Skip(1))
{
string[] values = line.Split(',');
...
}
Could you not just read the first line outside of the loop without assigning it to a variable?
using (StreamReader sr = new StreamReader(varFile, Encoding.GetEncoding(1250))) {
string[] stringSeparator = new string[] { "\",\"" };
if (!sr.EndOfStream)
sr.ReadLine();
while (!sr.EndOfStream) {
string line = sr.ReadLine(); //.Trim('"');
string[] values = line.Split(stringSeparator, StringSplitOptions.None);
for (int index = 0; index < values.Length; index++) {
MessageBox.Show(values[index].Trim('"'));
}
}
}
I'm sorry but I see no problem with the way you are doing it though. I couldn't add comment.
So just for the sake of answering, you probably could have try to call ReadLine() once before the loop. Might not be the best way as I don't know whats the behavior of running ReadLine() if its already end of stream, but it nothing is gonna happen then thats gonna save you some checks.
Updated:
To give a more complete answer, calling ReadLine() when the stream is at its end will return a null.
Reference: http://msdn.microsoft.com/en-us/library/system.io.streamreader.readline.aspx
Remember to check the return for null value.

Categories