Reading file to array - c#

I am reading and counting the number of lines in a file, then initializing an array with the same number of spaces as the number of lines. The file is then read again and each line is assigned to that position of the array. For example, the first line would be stored in the index position of 0. I have the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace testProg
{
class program
{
static void main(){
Console.WriteLine("enter your filename for reading!");
fileName = Console.ReadLine();
using (StreamReader rs = new StreamReader(fileName))
{
string line2;
while ((line2 = rs.ReadLine()) != null)
{
arraysize = arraysize+1;//this goes through and gets the number of lines
}
}
Console.WriteLine(arraysize);
string[] unenc = new string[arraysize]; //this creates the array dynamically
int i = -1;//starts at position -1 then +1 so starts at 0
using (StreamReader fr = new StreamReader(fileName))
{
string linefinal;
while ((linefinal = fr.ReadLine()) != null)
{
Console.WriteLine(linefinal);//this will write the current line
unenc[i + 1] = linefinal;// this should store the string above in the current position
Console.WriteLine(unenc[i]);//this should output the same line it does not the index is just empty ? but it should be stored yet it is not
}
}
}
}
}

The problem is that you're not saving the incremented value of i anywhere.
You could modify you code like so:
while ((linefinal = fr.ReadLine()) != null)
{
Console.WriteLine(linefinal);
unenc[i + 1] = linefinal;
Console.WriteLine(unenc[i]);
i++;
}
So your query in comments is
would the array not update the value of i in the section where unenc[i+1]?
What i + 1 does is return the value of "i plus 1".
If you want to increment the value, you have two options:
Increment after returning value:
var oldValue = i++;
var newValue = i;
Increment before returning value:
var oldValue = i;
var newValue = ++i;
Code optimisation
You're having to read your file twice in order to get the number of lines so you can find out how big your array is. .NET provides a lovely class which will help you in this instance: List<>.
List<int> is a wrapper for int[] which manages the length of its internal array on the fly, which means while with an array you have to do this:
var array = int[3];
array[0] = 1;
array[1] = 2;
array[3] = 3:
with a List<int> you can simply do the following
var list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
With an array you'd have to copy to a larger array if you wanted to add another element, with list, this is all done for you internally.
Of course you can still access a list by var item = list[3];.
So utilising this, you can do away with the first read of the file and just keep adding to a list.

Instead of an array, consider using a List object. You can use the Add() method to continuously add items as you read them. Once complete, you can simply call the ToArray() method on the List object to get the array you need. You'll have all of the index values matching each line.

The line
unenc[i + 1] = linefinal;
isn't quite right. I belive you mean
unenc[i++] = linefinal;
Your line does not change the value of i as it goes through the loop.

Simple way is to use ArrayList. Please see the below code snippet
ArrayList lines = new ArrayList();
using (StreamReader rs = new StreamReader(#"C:\Users\vimal\Desktop\test.txt"))
{
string line = null;
while ((line = rs.ReadLine()) != null)
{
lines.Add(line);
}
}

Related

C# Populate An Array with Values in a Loop

I have a C# console application where an external text file is read. Each line of the file has values separated by spaces, such as:
1 -88 30.1
2 -89 30.1
So line one should be split into '1', '-88', and '30.1'.
What I need to do is to populate an array (or any other better object) so that it duplicate each line; the array should have 3 elements per row. I must be having a brain-lock to not figure it out today. Here's my code:
string line;
int[] intArray;
intArray = new int[3];
int i = 0;
//Read Input file
using (StreamReader file = new StreamReader("Score_4.dat"))
{
while ((line = file.ReadLine()) != null && line.Length > 10)
{
line.Trim();
string[] parts;
parts = line.Split(' ');
intArray[0][i] = parts[0];//error: cannot apply indexing
i++;
}
}
Down the road in my code, I intend to make some API calls to a server by constructing a Json object while looping through the array (or alternate object).
Any idea?
Thanks
If you only need the data to be transferred to JSON then you don't need to process the values of the data, just reformat it to JSON arrays.
As you don't know the number of lines in the input file, it is easier to use a List<>, whose capacity expands automatically, to hold the data rather than an array, whose size you would need to know in advance.
I took your sample data and repeated it a few times into a text file and used this program:
static void Main(string[] args)
{
string src = #"C:\temp\Score_4.dat";
List<string> dataFromFile = new List<string>();
using (var sr = new StreamReader(src))
{
while (!sr.EndOfStream)
{
string thisLine = sr.ReadLine();
string[] parts = thisLine.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 3)
{
string jsonArray = "[" + string.Join(",", parts) + "]";
dataFromFile.Add(jsonArray);
}
else
{
/* the line did not have three entries */
/* Maybe keep a count of the lines processed to give an error message to the user */
}
}
}
/* Do something with the data... */
int totalEntries = dataFromFile.Count();
int maxBatchSize = 50;
int nBatches = (int)Math.Ceiling((double)totalEntries / maxBatchSize);
for(int i=0;i<nBatches;i+=1)
{
string thisBatchJsonArray = "{\"myData\":[" + string.Join(",", dataFromFile.Skip(i * maxBatchSize).Take(maxBatchSize)) + "]}";
Console.WriteLine(thisBatchJsonArray);
}
Console.ReadLine();
}
to get this output:
{"myData":[[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1]]}
{"myData":[[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1],[1,-88,30.1],[2,-89,30.1]]}
It should be easy to adjust the format as required.
I would create a custom Item class and then populate a list, for easy access and sorting, with self contained items. something like:
public Class MyItem
{
public int first { get; set; }
public int second { get; set; }
public float third { get; set; }
public MyItem(int one, int two, float three)
{
this.first = one;
this.second = two;
this.third = three;
}
}
then you could do:
List<MyItem> mylist = new List<MyItem>();
and then in your loop:
using (StreamReader file = new StreamReader("Score_4.dat"))
{
while ((line = file.ReadLine()) != null && line.Length > 10)
{
line.Trim();
string[] parts;
parts = line.Split(' ');
MyItem item = new Item(Int32.Parse(parts[0]),Int32.Parse(parts[1]),Float.Parse(parts[2]));
mylist.Add(item);
i++;
}
}
As there are numbers like 30.1 so int is not suitable for this, and also it must not be a double[] but double[][]:
string[] lines = File.ReadAllLines("file.txt");
double[][] array = lines.Select(x => s.Split(' ').Select(a => double.Parse(a)).ToArray()).ToArray();
Issue is that int array is single dimensional.
My suggestion is that you can put a class with 3 properties and populate a list of class there. It's better to have class with same property names that you require to build JSON. So that you can easily serialize this class to JSON using some nugets like Newtonsoft and make api calls easily.
Your int array is a single dimensional array yet you're trying to index it like a multidemensional array. It should be something like this:
intArray[i] = parts[0]
(However you'll need to handle converting to int for parts that are fractional)
Alternatively, if you want to use a multidimensional array, you have to declare one.
int[][] intArray = new int[*whatever your expected number of records are*][3]
Arrays have a static size. Since you're reading from a file and may not know how many records there are until your file finishes reading, I recommend using something like a List of Tuples or a Dictionary depending on your needs.
A dictionary will allow you to have quick lookup of your records without iterating over them by using a key value pair, so if you wanted your records to match up with their line numbers, you could do something like this:
Dictionary<int, int[]> test = new Dictionary<int, int[]>();
int lineCount = 1;
while ((line = file.ReadLine()) != null && line.Length > 10)
{
int[] intArray = new int[3];
line.Trim();
string[] parts = line.Split(' ');
for (int i = 0; i < 3; i++)
{
intArray[i] = int.Parse(parts[i]);
}
test[lineCount] = intArray;
lineCount++;
}
This will let you access your values by line count like so:
test[3] = *third line of file*

c# can't access list elements - Argument is out of range

I am trying to use list for the first time :-)
I have the list defined in a class:
using UnityEngine;
using System.Collections;
using System.IO;
using UnityEditor;
using System; //This allows the IComparable Interface
using System.Collections.Generic;
public class Words : MonoBehaviour {
public List<string> wordslist = new List<string>();
static void WriteString()
{
string path = "Assets/Resources/words.txt";
//Write some text to the test.txt file
StreamWriter writer = new StreamWriter(path, true);
writer.WriteLine("Test");
writer.Close();
//Re-import the file to update the reference in the editor
AssetDatabase.ImportAsset(path);
TextAsset asset = (TextAsset)Resources.Load("words");
//Print the text from the file
Debug.Log(asset.text);
}
static void ReadString()
{
string text = " ";
string path = "Assets/Resources/words.txt";
//List<WordsList> wordslist = new List<WordsList>();
int ix = 1;
//Read the text from directly from the test.txt file
StreamReader reader = new StreamReader(path);
while(text != null){
text = reader.ReadLine();
if (text != null) {
wordslist.Add (text);
ix++;
Debug.Log (wordslist[ix].ToString());
}
}
//Debug.Log (reader.ReadToEnd ().Length);
//Debug.Log(reader.ReadToEnd());
reader.Close();
}
public void GetWord(){
ReadString ();
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
I am trying to add words from a text file in to the list and display the list in the console.
the reading fails:
ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index
I am trying to access the list because I want to add code to select a random word from the list after this works
I am having trouble defining it correctly and reading the values after the Add function. I didn't try the WriteString yet, in case you see something wrong there too
All indexes start with 0 not 1, so replace
int ix = 1;
with
int ix = 0;
and move the ix++; to the very last line in the while-loop, so after:
Debug.Log (wordslist[ix]);
ix++;
Do you really want you ReadString and WriteString methods to be static? Having static methods means they are not tied to an instance of your Words class meaning you cannot use the field wordslist as this belongs to an instance of your Words class.
You could pass the instance of wordslist as a parameter to the ReadString instead.

Add an element/item to a multidimentional list

I am trying to create a multidimensional list filled with an employee and their information.
Ex: "Jane Smith" "Manager" "75,000" "Dallas"
the code I have right now is giving me an out of range exception.
This bigROW[i].Add(ownName); and bigROW[i][j+1] = newElement; gives me errors.
//Begin making rows
for (int i = 0; i < fileRowCount; i++ )
{
string findOwners = "";
findOwners = file5Data.Rows[i][0].ToString();
if(DISTINCTOppOwners.Contains(findOwners))
{
//Find index of where owner is
int useIndex = 0;
useIndex = DISTINCTOppOwners.IndexOf(findOwners);
//Add their name to Multidimensional list
string ownName = DISTINCTOppOwners[useIndex].ToString();
//This line give me the ERROR
bigROW[i].Add(ownName);
for (int j = 0; j < fileColCount; j++)
{
Add Employee information to Multidimensional list
string newElement = file5Data.Rows[i][j].ToString();
if(ownName != newElement)
{
if(j ==0)
{
//Avoid adding their names to the list twice
bigROW[i][j+1] = newElement;
}
bigROW[i][j] = newElement;
}
}
}
}
I tried adding the info to a list called "sublist" then adding it to the BigRow(multidimensional list),but when I cleared the sublist to add a new row it deleted the values from the BigRow.
I tried adding the info to a list called "sublist" then adding it to the BigRow(multidimensional list),but when I cleared the sublist to add a new row it deleted the values from the BigRow.
When you add an object to a list what is stored is a reference, not the contents of the object. Instead of clearing sublist you should create a new List each time. Otherwise you have an outer list that contains multiple copies of the same list inside.
Refer to jdweng's answer above for an example of this. In his code the ToList call creates an new numbers list for each line, so that each row has its own List of numbers.
Here is a simple example
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication64
{
class Program
{
static void Main(string[] args)
{
string input =
"0,1,2,3,4,5,6,7,8,9\n" +
"10,11,12,13,14,15,16,17,18,19\n" +
"20,21,22,23,24,25,26,27,28,29\n" +
"30,31,32,33,34,35,36,37,38,39\n" +
"40,41,42,43,44,45,46,47,48,49\n";
List<List<int>> output = new List<List<int>>();
StringReader reader = new StringReader(input);
string inputline = "";
while ((inputline = reader.ReadLine()) != null)
{
List<int> numbers = inputline.Split(new char[] { ',' }).Select(x => int.Parse(x)).ToList();
output.Add(numbers);
}
}
}
}

reading a .txt file and displaying numbers from the file

I am trying to read a .txt file using c# and displaying its contents but I am getting error as IndexOutOfRangeException with error code as 0xc000013a.
Here's my code:
static void Main(string[] args)
{
StreamReader sStreamReader = new StreamReader("d:\\TEST.txt");
while (!sStreamReader.EndOfStream)
{
string sLine = "";
if (sLine != null)
{
sLine = sStreamReader.ReadLine();
if (sLine != null)
{
string[] rows = sLine.Split(",".ToCharArray());
double a = Convert.ToDouble(rows[1]);
Console.Write(a);
int b = Convert.ToInt32(rows[3]);
Console.WriteLine(b);
Console.WriteLine();
}
}
}
}
my text file is as follows:
1,2,3,4,5,6,7
1,2,3,4,5,6,7
5,6,2,7,3,8,4
3,4,3,4,3
5,3,23,12
12,30000,12,99
I would change it to the following:
static void Main(string[] args)
{
// StreamReader is IDisposable which should be wrapped in a using statement
using (StreamReader reader = new StreamReader(#"d:\TEST.txt"))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
// make sure we have something to work with
if (String.IsNullOrEmpty(line)) continue;
string[] cols = line.Split(',');
// make sure we have the minimum number of columns to process
if (cols.Length < 4) continue;
double a = Convert.ToDouble(cols[1]);
Console.Write(a);
int b = Convert.ToInt32(cols[3]);
Console.WriteLine(b);
Console.WriteLine();
}
}
}
Some notes here:
StreamReader implements IDisposable, so you should wrap it in a using clause so that it is properly disposed of.
Don't name things like "sLine". That form of Hungarian is commonly recognized as seriously bad practice. Even Microsoft says don't do it.
You're dealing with columns, not rows. So that variable should be named appropriately.
Always test to make sure you have all of the columns you need before blindly accessing them.
Normally, I wouldn't use Convert.ToDouble or Convert.ToInt32. It's much safer to use TryParse to make sure it was able to convert. The code you have will blow if cols[1] and cols[3] had non-numeric data.
You can use the # symbol in front of a string to tell the compiler that it doesn't need to be escaped.
It's much cleaner to simply "continue" a loop instead of wrapping it in a if statement.
Setting a String variable to a blank string then immediately setting it to some other value causes the blank to stay in memory for the entire scope. In other words, it's wasting memory. Granted, in this case it's a micro-optimization, but it never hurts to use best practices all of the time.
Have you considered checking for row.Length before accessing row[1] and row[3]
I suspect your empty lines are the problem
Here is how you can do it simpler:
string[] lines = File.ReadAllLines("d:\\TEST.txt");
foreach (var line in lines.Where(line => line.Length > 0))
{
string[] numbers = line.Split(',');
// It checks whether numbers.Length is greater than
// 3 because if maximum index used is 3 (numbers[3])
// than the array has to contain at least 4 elements
if (numbers.Length > 3)
{
double a = Convert.ToDouble(numbers[1]);
Console.Write(a);
int b = Convert.ToInt32(numbers[3]);
Console.Write(b);
Console.WriteLine();
}
}
You should consider to use :
if (!string.IsNullOrEmpty(sLine))
instead of
if (sLine != null)
You have this exceptions because some lines are empty.
However, here is a way you should write your code when using a StreamReader :
using(var reader = new StreamReader(#"d:\\TEST.txt"))
{
string line;
while ((line= reader.ReadLine()) != null)
{
if (string.IsNullOrEmpty(line)) continue;
var rows = line.Split(",".ToCharArray());
var a = Convert.ToDouble(rows[1]);
Console.Write(a);
var b = Convert.ToInt32(rows[3]);
Console.WriteLine(b);
Console.WriteLine();
}
}
Regards,
Kévin

Reading each row from text file into an array of doubles or integer using C#

Suppose I have a text file with data like below, I want to read first row and store the elements in one array. Read the second row and store in second array and so on. I will be making some manipulations on the array later on. Can you help me to do this in C#?
Input text file:
5,7,3,6,9,8,3,5,7
5,6,8,3,4,5
6,4,3,2,65,8,6,3,3,5,7,4
4,5,6,78,9,4,2,5,6
The Code I am trying out is:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace ReadFile
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
static void Main(string[] args)
{
TextReader tr = new StreamReader("Data.txt");
// write a line of text to the file
string word = tr.ReadLine();
//now split this line into words
string[] val = word.Split(new Char[] { ',' });
}
}
}
If I use the above technique, I can get the first line in array val. Is there a way to loop it for all the rows?
File.ReadAllLines will help you read all lines from file as string array.
String.Split will help you split line in pieces.
Int.Parse will help you transform string to int (double has similar method).
Ok, since you are a beginner my suggestions on what to focalize your attention.
First of all, are your consumer always needing all the lines or can it stop at some point? If so, use a yield strategy to return the results one by one. You can use a StreamReader to read line one by one in any case, and use double.TryParse(...) or int.TryParse() after splitting the string by the separator. Keep an eye to the fact that separator can change, so use it with some kind of configurability, and in the case of double, ensure your code works even in machines with a different decimal point configured. If you are sure your csv alwais uses '.' as a decimal point separator, specify
double.TryParse("",System.Globalization.CultureInfo.InvariantCulture);
Something roughly like this would work:
StreamReader reader = new (File.OpenRead(#"YourFile.txt"));
List<string> LstIntegers = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
//values is actually a string array.
var values = line.Split(',');
//add the entire array fetched into string List
LstIntegers.AddRange(values);
}
// important to close the reader. You can also use using statement for reader. It
// will close the reader automatically when reading finishes.
reader.Close();
// You can then further manipulate it like below, you can also use int.Parse or int.TryParse:
foreach (var v in LstIntegers)
{
// use int.TryParse if there is a chance that a non-int is read.
int someNum = Convert.ToInt32(v);
}
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.IO;
using System.Xml.Linq;
using System.Diagnostics;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
List<int[]> arrays = new List<int[]>();
int counter = 0;
string line;
// Read the file
System.IO.StreamReader file =
new System.IO.StreamReader("c:\\temp\\test.txt");
while ((line = file.ReadLine()) != null)
{
// split the line into a string array on , separator
string[] splitLine = line.ToString().Split(',');
// if our split isnt null and has a positive length
if (splitLine != null && splitLine.Length > 0)
{
// create a lineArray the same size as our new string[]
int[] lineArray = new int[splitLine.Length];
int posCounter = 0;
foreach (string splitValue in splitLine)
{
// loop through each value in the split, try and convert
// it into an int and push it into the array
try
{
lineArray[posCounter] = Int32.Parse(splitValue);
}
catch { }
posCounter++;
}
// if our lineArray has a positive length then at it to our
// list of arrays for processing later.
if (lineArray.Length > 0)
{
arrays.Add(lineArray);
}
}
counter++;
}
file.Close();
// go through the List<int[]> and print to screen
foreach (int[] row in arrays)
{
foreach (int rowCol in row)
{
Console.Write(rowCol + ",");
}
Console.WriteLine();
}
// Suspend the screen.
Console.ReadLine();
}
}
}
See this lines of code:
List<List<int>> numbers = new List<List<int>>();
foreach (string line in File.ReadAllLines(""))
{
var list = new List<int>();
foreach (string s in line.Split(new[]{',', ' '},
StringSplitOptions.RemoveEmptyEntries))
{
int i;
if(int.TryParse(s, out i))
{
list.Add(i);
}
}
numbers.Add(list);
}
var specialNumber = numbers[3][4]; // gives line 3 number 4
var specialLine = numbers[2].ToArray(); // gives an array of numbers of line 2
description:
I used this useful Generic:
List: Represents a strongly typed list of objects that can be accessed by index
and these useful Classes:
File.ReadAllLines: Opens a text file, reads all lines of the file into a string array
String.Split : Returns a string array that contains the substrings in this instance that are delimited by elements of a specified string or Unicode character array.
Int.TryParse: Converts the string representation of a number to its 32-bit signed integer equivalent.
I have presented the following code in two sections, just to show you in steps.
SECTION 1
This code is just to show that you just needed to loop through all lines and store string numbers from each line in a List.
SECTION 1
static void Main(string[] args)
{
List<string[]> allLines = new List<string[]>();
TextReader tr = new StreamReader("Data.txt");
string word = tr.ReadLine();
// write a line of text to the file
while ( word != null ) {
//now split this line into words
string[] vals = word.Split(new Char[] { ',' });
//Add this line into allLines
allLines.Add(vals);
//Now read the next line
word = tr.ReadLine();
}
}
SECTION 2
This section will get you the results as int.
static void Main(string[] args)
{
//A list of arrays of integers
//A single array will have numbers from a single line
List<int[]> allNumbers = new List<int[]>();
TextReader tr = new StreamReader("Data.txt");
string word = tr.ReadLine();
// write a line of text to the file
while ( word != null ) {
//now split this line into words
string[] vals = word.Split(new Char[] { ',' });
int[] intVals = new int[vals.Length];
for ( int i = 0; i < vals.Length; i++) {
Int32.TryParse(vals[i], out intVals[i]);
}
//Add this array of integers into allNumbers
allNumbers.Add(intVals);
//Now read the next line
word = tr.ReadLine();
}
}
NOTE: I have not compiled or tested the code above.
I figured it out. Thanks all for your time!
private void ReadFile()
{
var lines = File.ReadLines("Data.csv");
var numbers = new List<List<double>>();
var separators = new[] { ',', ' ' };
/*System.Threading.Tasks.*/
Parallel.ForEach(lines, line =>
{
var list = new List<double>();
foreach (var s in line.Split(separators, StringSplitOptions.RemoveEmptyEntries))
{
double i;
if (double.TryParse(s, out i))
{
list.Add(i);
}
}
lock (numbers)
{
numbers.Add(list);
}
});

Categories