Reading csv without specific type - c#

I want to read csv file and save to list or array or anything, but CsvHelper demands to save it as collection of specific type. Problem is my csv has so many columns, that mapping it to custom class will take a few weeks.
How can I just read it without saving as specific type? Accessing specific values with thing like row[1][2] is more than enough for me.

Add it to a datatable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
namespace ConsoleApplication23
{
class Program
{
const string FILENAME = #"c:\temp\test.csv";
static void Main(string[] args)
{
StreamReader reader = new StreamReader(FILENAME);
string line = "";
DataTable dt = new DataTable();
int rowCount = 0;
while((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length > 0)
{
string[] splitArray = line.Split(new char[] { ',' });
if (rowCount == 0)
{
foreach (string col in splitArray)
{
dt.Columns.Add(col, typeof(string));
}
}
else
{
dt.Rows.Add(splitArray);
}
}
}
}
}
}

Related

How to iterate through a column in a csv file using CSVhelper library? using: dynamic object

CSV file
CSV file in notepad editor
using CsvHelper;
public class csvread
{
public dynamic APSSValue ;
public async Task GetMode()
{
try
{
FileOpenPicker openpicker = new FileOpenPicker();
openpicker.FileTypeFilter.Add(".csv");
IRandomAccessStreamWithContentType stream = await file.OpenReadAsync();
StreamReader reader = new StreamReader(stream.AsStream());
string UserCultureInfo = Thread.CurrentThread.CurrentCulture.Name;
CsvReader csv = new CsvReader(reader, culture: CultureInfo.CreateSpecificCulture(UserCultureInfo));
csv.Configuration.HasHeaderRecord = false;
csv.Configuration.Delimiter = ";";
while (csv.Read())
{
APSSValue = Enumerable.ToList(csv.GetRecord<dynamic>());
}
}
}
}
I tried this way shown above but with this I only get the number of columns.
I also tried
csv.Read();
APSSValue = Enumerable.ToList(csv.GetRecords<dynamic>());
but this gives me the entire data of csv file.
Questions:
I want to look for the value under the column (I_APSS_Modus) Please see the images shared above, It can be 0 or 1 so how can I look for that value if it is 0 or 1 ?
NOTE:
I don't want the values of entire column because all the values in the column would be either 0 or 1. So i just want one value from any row under that column.
CSV file is not same every time, so the column number for (I_APSS_Modus) will vary if the CSV file is different
Try following code which put data into a DataTable so you can easily filter with linq. Below will work with posted csv
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Globalization;
using System.Data;
namespace ConsoleApplication8
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Timestamp", typeof(DateTime));
dt.Columns.Add("B_Kurze_Seite", typeof(Boolean));
dt.Columns.Add("I_Partikeleinfall Reinluft", typeof(int));
dt.Columns.Add("I_Partikeleinfall Rohluft", typeof(int));
dt.Columns.Add("I_APSS_Modus", typeof(int));
StreamReader reader = new StreamReader(FILENAME);
string line = "";
int row = 0;
string format = "yyyy MM dd HH:mm:ss:fff";
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length > 0 && !line.StartsWith("sep"))
{
if (++row > 1)
{
string[] splitRow = line.Split(new char[] { ';' });
dt.Rows.Add(new object[] {
DateTime.ParseExact(splitRow[0],format,CultureInfo.InvariantCulture),
(splitRow[1] == "FALSE")? false : true,
int.Parse(splitRow[2]),
int.Parse(splitRow[3]),
int.Parse(splitRow[4])
});
}
}
}
List<int> data = dt.AsEnumerable().Select(x => x.Field<int>("I_APSS_Modus")).ToList();
}
}
}
Here is code that will work with generic columns
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Globalization;
using System.Data;
namespace ConsoleApplication8
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
DataTable dt = new DataTable();
StreamReader reader = new StreamReader(FILENAME);
string line = "";
int row = 0;
string format = "yyyy MM dd HH:mm:ss:fff";
string[] columnNames = null;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if ((line.Length > 0) && !line.StartsWith("sep"))
{
string[] splitRow = line.Split(new char[] { ';' });
if (++row == 1)
{
columnNames = splitRow;
foreach (string col in splitRow)
{
switch(col)
{
case "Timestamp":
dt.Columns.Add(col, typeof(DateTime));
break;
case "I_APSS_Modus":
dt.Columns.Add(col, typeof(int));
break;
default:
dt.Columns.Add(col, typeof(string));
break;
}
}
}
else
{
DataRow newRow = dt.Rows.Add();
for (int i = 0; i < columnNames.Length; i++)
{
switch (columnNames[i])
{
case "Timestamp":
newRow["Timestamp"] = DateTime.ParseExact(splitRow[i], format, CultureInfo.InvariantCulture);
break;
case "I_APSS_Modus":
newRow["I_APSS_Modus"] = int.Parse(splitRow[i]);
break;
default:
newRow[i] = splitRow[i];
break;
}
}
}
}
}
List<int> data = dt.AsEnumerable().Select(x => x.Field<int>("I_APSS_Modus")).ToList();
}
}
}
If you want to stay with CsvHelper, a simple mapping should do the trick:
// Data model of a row (only I_APSS_Modul is of interest)
public class DataSet
{
public int ApssModus { get; set; }
}
// Mapping
public class ApssMap : ClassMap<DataSet>
{
public ApssMap()
{
Map(m => m.ApssModus).Name("I_APSS_Modus");
}
}
// Reading records
public void GetMode()
{
string UserCultureInfo = Thread.CurrentThread.CurrentCulture.Name;
using (var tr = new StreamReader(new FileStream("any.csv", FileMode.Open)))
{
using (var csv = new CsvReader(tr, new CsvConfiguration(CultureInfo.CreateSpecificCulture(UserCultureInfo))
{
Delimiter = ";"
}))
{
csv.Configuration.RegisterClassMap<ApssMap>();
var records = csv.GetRecords<DataSet>().ToList();
}
}
}
Edit: Check the official docs for all the mapping options: https://joshclose.github.io/CsvHelper/examples/configuration/class-maps
If you just want to read the first row of data, you have to read the header first and then you can read the first data row.
static void Main(string[] args)
{
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))
using (var reader = new StreamReader(stream))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
writer.WriteLine("Timestamp;B_Kurze_Seite;I_Parikeleinfall Reinluft;I_Partikeleinfall Rohluft;I_APSS_Modus");
writer.WriteLine("2020 06 27 08:49:20:335;FALSE;15;0;0");
writer.WriteLine("2020 06 27 08:49:20:391;FALSE;0;0;0");
writer.Flush();
stream.Position = 0;
csv.Configuration.Delimiter = ";";
csv.Read();
csv.ReadHeader();
csv.Read();
var record = csv.GetRecord<dynamic>();
var APSSModus = record.I_APSS_Modus;
}
}
Edit: This should give you the same answer as #jdweng
static void Main(string[] args)
{
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))
using (var reader = new StreamReader(stream))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
writer.WriteLine("sep=;");
writer.WriteLine("");
writer.WriteLine("");
writer.WriteLine("");
writer.WriteLine("Timestamp;B_Kurze_Seite;I_Parikeleinfall Reinluft;I_Partikeleinfall Rohluft;I_APSS_Modus");
writer.WriteLine("2020 06 27 08:49:20:335;FALSE;15;0;0");
writer.WriteLine("2020 06 27 08:49:20:391;FALSE;0;0;0");
writer.Flush();
stream.Position = 0;
csv.Configuration.Delimiter = ";";
csv.Configuration.ShouldSkipRecord = row => row[0].StartsWith("sep=") || row.All(string.IsNullOrEmpty);
var records = csv.GetRecords<dynamic>();
List<int> data = records.Select(x => (int)int.Parse(x.I_APSS_Modus)).ToList();
}
}

C# Delete line from .txt extension with a changing filename

I am currently trying to make an .exe in c# that I can drag and drop a .txt file onto to remove lines of text that contain the keywords "CM" and/or "Filling". It must be able to overwrite the existing data so there are no new files created. The filename is different every time except for the extension. The data is tab delimited if that has any bearing. I'm aware that there are similar questions to this but I haven't managed to adapt them to suit my needs. Also, I'm very new to this and I've been trying for about a week with no luck.
if (args.Length == 0)
return; // return if no file was dragged onto exe
string text = File.ReadAllText("*.txt");
text = text.Replace("cm", "");
string path = Path.GetDirectoryName(args[0])
+ Path.DirectorySeparatorChar
+ Path.GetFileNameWithoutExtension(args[0])
+ "_unwrapped" + Path.GetExtension(args[0]);
File.WriteAllText("*.txt", text);
\\attempt 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Text.RegularExpressions;
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
string concrete = "CM";
string line;
using (StreamReader reader = new StreamReader(#"C:\\Users\drocc_000\Desktop\1611AN24T99-041805221704.txt"))
{
using (StreamWriter writer = new StreamWriter(#"C:\\Users\drocc_000\Desktop\1611AN24T99-041805221704NEW.txt"))
{
while ((line = reader.ReadLine()) != null)
{
// if (String.Compare(line, yourName) == 0)
// continue;
writer.WriteLine(line.Replace(concrete, ""));
}
}
}
\\attempt 2
Thanks for your time.
Regards,
Danny
You can create a console application with the code below and then drag and drop your text file into the .exe file without opening it.
class Program
{
static void Main(string[] args)
{
if (args.Length > 0 && File.Exists(args[0]))
{
string path = args[0];
EditFile(new List<string>() { "CM", "Filling" }, path);
}
Console.Read();
}
public static void EditFile(List<string> keyWords, string filename)
{
List<string> lines = new List<string>();
using (StreamReader sr = new StreamReader(filename))
{
while (sr.Peek() >= 0)
{
lines.Add(sr.ReadLine());
}
sr.Close();
}
int removedLinesCount = 0;
bool writeline;
using (StreamWriter sw = new StreamWriter(filename))
{
foreach (var line in lines)
{
writeline = true;
foreach (var str in keyWords)
{
if (line.Contains(str))
{
writeline = false;
removedLinesCount++;
break;
}
}
if (writeline)
sw.WriteLine(line);
}
Console.WriteLine(removedLinesCount + " lines removed from the file " + filename);
sw.Close();
}
}
}
Something like this?
using System;
using System.IO;
using System.Linq;
namespace ConsoleApp1
{
internal static class Program
{
private static void Main(string[] args)
{
try
{
// Get the filename from the applications arguments
string filename = args[0];
// Read in all lines in the file.
var linesInFile = File.ReadLines(filename);
// Filter out the lines we don't need.
var linesToKeep = linesInFile.Where(line => !line.Contains("CM") && !line.Contains("Filling")).ToArray();
// Overwrite the file.
File.WriteAllLines(filename, linesToKeep);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}

Extracting CSV Header data type

In my current project, I am trying to derive the data type of CSV file. For instance, the following is the .CSV file.
sepallength,sepalwidth,petallength,petalwidth,class
6.2,2.8,4.8,1.8,Iris-virginica
6.3,2.9,5.6,1.8,Iris-virginica
5.1,3.5,1.4,0.3,Iris-setosa
5.2,3.5,1.5,0.2,Iris-setosa
5.9,3,4.2,1.5,Iris-versicolor
5.7,3,4.2,1.2,Iris-versicolor
5.5,2.6,4.4,1.2,Iris-versicolor
6.4,2.8,5.6,2.2,Iris-virginica
My requirement is that a program should give me the following output.
"sepallength" is of "float" datatype
"sepalwidth" is of "float" datatype
"petallength" is of "float" datatype
"petalwidth" is of "float" datatype
"class" is of "String" datatype
I have written the following program. However the "columnName.GetType()" function always return string data type.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using Microsoft.VisualBasic.FileIO;
using System.IO;
namespace ReadCSVFile
{
class Program
{
static void Main(string[] args)
{
// This is a file Path that a user has to input.
string csv_file_path = #"C:\TestCSV\iris.csv";
string columnName;
DataTable csvData = GetDataTabletFromCSVFile(csv_file_path);
Console.WriteLine("Column Value of the CSV file are as follows:");
Console.WriteLine("=========================================");
// This will retrieve columnNames from the table.
foreach (DataColumn column in csvData.Columns)
{
columnName = column.ColumnName;
Console.WriteLine(columnName);
Console.WriteLine("Column type " + columnName.GetType());
}
}
/*
* This function takes the file Path as an input and returns a Datatable.
*/
private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
{
DataTable csvData = new DataTable();
try
{
// Connect to the .CSV file Path
using (TextFieldParser csvReader = new TextFieldParser(csv_file_path))
{
csvReader.SetDelimiters(new string[] { "," });
csvReader.HasFieldsEnclosedInQuotes = true;
// This will read the column name of a .CSV file.
string[] colFields = csvReader.ReadFields();
foreach (string column in colFields)
{
DataColumn datecolumn = new DataColumn(column);
datecolumn.AllowDBNull = true;
csvData.Columns.Add(datecolumn);
}
// This code retrieves rows from the .CSV file.
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
//Making empty value as null
for (int i = 0; i < fieldData.Length; i++)
{
if (fieldData[i] == "")
{
fieldData[i] = null;
}
}
csvData.Rows.Add(fieldData);
}
}
}
catch (Exception ex)
{
}
return csvData;
}
check my example code:
(you cannot use it with .columnname as this is always a string, only the content of the columns are of different types:
public static void Main()
{
string str = "6,2"; // float with decimals from europe
Console.WriteLine(mytesttype(str).GetType());
str = "6232";
Console.WriteLine(mytesttype(str).GetType());
str = "6String";
Console.WriteLine(mytesttype(str).GetType());
}
static object mytesttype(string str) {
int i;
float f;
if (int.TryParse(str,out i)) return i;
if (float.TryParse(str, out f)) return f;
return str;
}

how to extract column of data using regular expression

i am trying to write c# code to extract columns of data. my data looks like
what should be the regular expression if i want to extract "everything" "under" a column header for example "COMMAND" or "PID".
No need to use regular expression. String Split method will work. Try code like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
namespace ConsoleApplication53
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("PID", typeof(int));
dt.Columns.Add("TT", typeof(string));
dt.Columns.Add("STAT", typeof(string));
dt.Columns.Add("TIME", typeof(DateTime));
dt.Columns.Add("COMMAND", typeof(string));
StreamReader reader = new StreamReader(FILENAME);
int lineCount = 0;
string inputLine = "";
while ((inputLine = reader.ReadLine) != null)
{
if (++lineCount > 2)
{
string[] inputArray = inputLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
dt.Rows.Add(new object[] {
int.Parse(inputArray[0]),
inputArray[1],
inputArray[2],
DateTime.Parse(inputArray[3]),
inputArray[4]
});
}
}
}
}
}

Unable to open CSV file from internet using C#

I'm new with C#. I've written code to open a CSV file from my documents on my local machine. It works well and the data parsing works. Trouble is when I change the code to open the file from an internet site I cannot get it to work. I am able to open this file using VBA but I now want to use C# ADO.NET. I cannot find the answer by searching with Google. Can anyone help with the code and/or point me to a website with a good tutorial. All help much appreciated. Code attached, I'm sure the problem is with lines 24 - 26;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
//
// Read in a file line-by-line, and store it all in a List.
//
int i = 0;
DateTime dte;
List<string> list = new List<string>();
float[] Prices = new float[4];
WebClient wc = new WebClient();
byte[] data = wc.DownloadData("http://www.datasource.com/apps/qt/csv/pricehistory.ac?section=yearly_price_download&code=XXX");
using (StreamReader reader = new StreamReader(wc))
{
string line;
while ((line = reader.ReadLine()) != null)
{
//list.Add(line); // Add to list.
Console.WriteLine(line); // Write to console.
string[] parts = line.Split(',');
int DateSetter = 1;
int DateDone = 0;
int CountFloat = 0;
int PricesDone = 0;
Double Volume = 0;
foreach (string part in parts)
{
Console.WriteLine("{0} : {1}", i, part);
if (DateSetter == 1)
{
dte = DateTime.Parse(part);
DateSetter = 2;
Console.WriteLine(dte);
}
if (DateDone == 1)
{
if (DateSetter < 6)
{
Prices[CountFloat] = float.Parse(part);
CountFloat++;
DateSetter++;
Console.WriteLine(Prices[3]);
}
}
DateDone = 1;
if (PricesDone == 1)
{
Volume = double.Parse(part);
Console.WriteLine(Volume);
}
if (DateSetter == 6)
{
PricesDone = 1;
}
}
}
}
Console.ReadLine();
}
}
}
Your code as pasted would not compile. You can however use the WebClient to download to a string, then split the string into lines:
string content;
using(WebClient wc = new WebClient())
content = wc.DownloadString("http://www.datasource.com/apps/qt/csv/pricehistory.ac?section=yearly_price_download&code=XXX");
foreach(var line in content.Split(new string [] {Environment.NewLine}, StringSplitOptions.None))
{
//...
}
Another option is to download data as you're doing, and then wrap it with a MemoryStream:
WebClient wc = new WebClient();
byte[] data = wc.DownloadData(
"http://www.datasource.com/apps/qt/csv/pricehistory.ac?section=yearly_price_download&code=XXX");
using (var ms = new MemoryStream(data))
{
using (var reader = new StreamReader(ms))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// do whatever
}
}
}
The advantage of this over splitting the string is that it uses considerably less memory.

Categories