I'm creating an MVC controller action where JSON data passed in to the method is to be written to an excel file. Right now, I'm testing out the functionality by using hardcoded data from a data table based on the example from this blog post.
Here is the code I have:
[HttpPost]
public ActionResult ExportData()
{
Microsoft.Office.Interop.Excel.Application excel;
Microsoft.Office.Interop.Excel.Workbook worKbooK;
Microsoft.Office.Interop.Excel.Worksheet worKsheeT;
Microsoft.Office.Interop.Excel.Range celLrangE;
try
{
excel = new Microsoft.Office.Interop.Excel.Application();
excel.Visible = false;
excel.DisplayAlerts = false;
worKbooK = excel.Workbooks.Add(Type.Missing);
worKsheeT = (Microsoft.Office.Interop.Excel.Worksheet)worKbooK.ActiveSheet;
worKsheeT.Name = "StudentRepoertCard";
worKsheeT.Range[worKsheeT.Cells[1, 1], worKsheeT.Cells[1, 8]].Merge();
worKsheeT.Cells[1, 1] = "Student Report Card";
worKsheeT.Cells.Font.Size = 15;
int rowcount = 2;
foreach (DataRow datarow in ExportToExcel().Rows)
{
rowcount += 1;
for (int i = 1; i <= ExportToExcel().Columns.Count; i++)
{
if (rowcount == 3)
{
worKsheeT.Cells[2, i] = ExportToExcel().Columns[i - 1].ColumnName;
worKsheeT.Cells.Font.Color = System.Drawing.Color.Black;
}
worKsheeT.Cells[rowcount, i] = datarow[i - 1].ToString();
if (rowcount > 3)
{
if (i == ExportToExcel().Columns.Count)
{
if (rowcount % 2 == 0)
{
celLrangE = worKsheeT.Range[worKsheeT.Cells[rowcount, 1], worKsheeT.Cells[rowcount, ExportToExcel().Columns.Count]];
}
}
}
}
}
celLrangE = worKsheeT.Range[worKsheeT.Cells[1, 1], worKsheeT.Cells[rowcount, ExportToExcel().Columns.Count]];
celLrangE.EntireColumn.AutoFit();
Microsoft.Office.Interop.Excel.Borders border = celLrangE.Borders;
border.LineStyle = Microsoft.Office.Interop.Excel.XlLineStyle.xlContinuous;
border.Weight = 2d;
celLrangE = worKsheeT.Range[worKsheeT.Cells[1, 1], worKsheeT.Cells[2, ExportToExcel().Columns.Count]];
worKbooK.SaveAs("\\root\\test.xlsx");
worKbooK.Close();
excel.Quit();
}
catch (Exception ex)
{
return Json(new { saveSuccess = false }, JsonRequestBehavior.AllowGet);
}
finally
{
worKsheeT = null;
celLrangE = null;
worKbooK = null;
}
return Json(new { saveSuccess = true }, JsonRequestBehavior.AllowGet);
}
//private void Form1_Load(object sender, EventArgs e)
//{
// dataGridView1.DataSource = ExportToExcel();
//}
public System.Data.DataTable ExportToExcel()
{
System.Data.DataTable table = new System.Data.DataTable();
table.Columns.Add("ID", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Sex", typeof(string));
table.Columns.Add("Subject1", typeof(int));
table.Columns.Add("Subject2", typeof(int));
table.Columns.Add("Subject3", typeof(int));
table.Columns.Add("Subject4", typeof(int));
table.Columns.Add("Subject5", typeof(int));
table.Columns.Add("Subject6", typeof(int));
table.Rows.Add(1, "Amar", "M", 78, 59, 72, 95, 83, 77);
table.Rows.Add(2, "Mohit", "M", 76, 65, 85, 87, 72, 90);
table.Rows.Add(3, "Garima", "F", 77, 73, 83, 64, 86, 63);
table.Rows.Add(4, "jyoti", "F", 55, 77, 85, 69, 70, 86);
table.Rows.Add(5, "Avinash", "M", 87, 73, 69, 75, 67, 81);
table.Rows.Add(6, "Devesh", "M", 92, 87, 78, 73, 75, 72);
return table;
}
Right now, the code works up until the point where the save happens. For some reason, the file location is not found. I was assuming that the name of the file had to be listed at the end of the path after the containing folder in order to provide the name, but maybe this isn't the correct way to specify the file path.
What I actually need to do is to allow the user to choose the file location in file explorer, provide a name, and then save the file. Since this is the case, the file path would have to be provided dynamically. I've looked at many SO posts and articles but I haven't seen a clear example of how to do this.
How should the code be modified for the user to be able to specify the file name and path?
You cannot choose to save the file from their browser. You need to serve up the file and let them download it and save it where they like.
Also, the server you want a production ASP.NET application deployed to probably doesn't have a copy of Excel installed (and even if it does interop gets a little messy IMHO) so you probably want to use a openXml library such as EPPlus instead.
This would let you do something like this:
public IActionResult ExportData()
{
using (var excel = new ExcelPackage())
{
var wks = excel.Workbook.Worksheets.Add("StudentReportCard");
wks.Cells[1,1].LoadFromCollection(GetStudentRecords(), PrintHeaders:true);
return File(excel.GetAsByteArray(),"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "export.xlsx");
};
}
private static IEnumerable<StudentRecord> GetStudentRecords()
{
yield return new StudentRecord
{
Id = 1,
Name = "John",
Subject = "Maths",
Score = 77.9
};
yield return new StudentRecord
{
Id = 2,
Name = "Jane",
Subject = "Maths",
Score = 78.9
};
yield return new StudentRecord
{
Id = 3,
Name = "Jo",
Subject = "Maths",
Score = 99.9
};
}
Which sends a file like this named 'export.xlsx' for the user to save from their browser:
Related
first of all, I am very new to C#.
I would like to select every row of my excel sheet and put it in a text doc. The problem is, that I only need certain columns(21 out of 70+).
Here is my code:
For example:
Excel:
|1 2 3 4 5
1|x y c v b
2|x y c v b
3|x y c v b
And I need every row 1 to 3 but only the data from column 2,3,5
In my text doc I want it to like like:
y c b
y c b
y c b
But atm it looks like:
y
y
y
c
c
c
b
b
b
int[] spalten = new int[] { 5, 22, 24, 27, 29, 32, 34, 37, 39, 43, 45, 48, 50, 54, 56, 59, 61, 65, 67, 71, 73 };
for (int x = 0; x <= 20; x++)
{
//loop all columns
for (int j = 4; j <= 74; j++)
{
//loop all rows
for (int i = 5; worksheet.Cells[i, 5].Value != null; i++)
{
//add the cell data to the List
if (j == spalten[x])
{
if (worksheet.Cells[i, j].Value == null)
{
Console.WriteLine("leer");
string Inhalt = "leer" + "\t";
string[] lines = { Inhalt };
File.AppendAllLines(Path.Combine(docPath, "Daten2.txt"), lines);
}
else
{
excelData.Add(worksheet.Cells[i, j].Value.ToString());
Console.WriteLine(worksheet.Cells[i, j].Value);
string Inhalt = worksheet.Cells[i, j].Value.ToString()+"\t";
string[] lines = { Inhalt };
File.AppendAllLines(Path.Combine(docPath, "Daten2.txt"), lines);
}
}
}
}
}
Change the order of your loops: loop over the rows first, then over the columns for the current row. Inside the inner loop, concatenate the column values into a single string.
For performance reasons, try to do as little work as possible inside the loop (e.g. do not access worksheet.Cells[] twice with the same indices). Use StringBuilder to concatenate strings. You can use foreach to loop over the configured columns only.
var configuredColumns = new int[] { 5, 22, 24, 27, 29, 32, 34, 37, 39, 43, 45, 48, 50, 54, 56, 59, 61, 65, 67, 71, 73 };
// loop over all data rows (ignore first 5 rows which are headers)
// stop looping if the current row has no data in column 5
var allRowTexts = new List<string>();
for (int row = 5; worksheet.Cells[row, 5].Value != null; row++) {
// loop over the configured columns
var rowText = new StringBuilder();
foreach (var col in configuredColumns) {
var cell = worksheet.Cells[row, col];
if (cell.Value == null) {
rowText.Append("leer" + "\t");
}
else {
rowText.Append(cell.Value.ToString() + "\t");
}
}
// rowText now contains all column values for the current row
allRowTexts.Add(rowText.ToString());
}
// write all rows into file
File.AppendAllLines(Path.Combine(docPath, "Daten2.txt"), allRowTexts);
C# Fiddle using dummy WorkSheet and Console output
Below I have an example of some text (in this case it's C source code, could be any structured text honestly). I am trying to read a couple files, with variable length and different structures and figure out if for example, after every #define an #include "test.h" is present.
The same case can apply to both, within and out of the preprocessor directives (#if, #ifdef, #ifndef, #endif). It is also allowed that a #include "test.h" appears after a #endif, if the proper #define was within the if-directive prior to this.
A few side notes:
I extract the text from the file, do some actions such as removing comments, irrelevant lines, empty lines and soon and return the file as a string[]. This makes it fairly easy to iterate and jump back and forth between the lines SourceCode[i]
I have attempted to implement a solution with a few different approaches, and never managed to fully hit the nail.
My first attempt consisted of an endless amount of if-else-statements and while-loops, for every imaginable path in the logic. This ended up being so hard to maintain, confusing and to hard keep control upon.
Next, I've tried implementing a state machine, to keep track of where I am in the text file, jumping to different states as needed. I couldn't find a perfect solution.
Another attempt I've tried was using a stack, pushing a #define to the stack, checking what it was, pushing the next line to the stack, checking if it is #include, if not then return an error. This also, of course, is a bit more complicated as soon as I have directives, as one #include is sufficient for multiple #defines.
I've looked into parsers (mainly Antlr), realizing that this is possibly way too overkill for such a problem, also considering I have absolutely no clue about parsers and would need to make my own grammar.
Source code example
// directives
#if (TEST == true)
#define START_TEST_1
#include "test.h"
#else
#define START_TEST_2
#include "test.h"
#endif
#if (TEST == true)
#define STOP_TEST_1
#else
#define STOP_TEST_2
#endif
#include "test.h"
// no directives
#define START_TEST_3
#include "test.h"
#define STOP_TEST_3
#include "test.h"
Does anyone have some general tips and can maybe point me in a specific direction. What would be a suitable solution to this problem?
Edit: #jdweng
dt.Columns.Add("Next #elif State", typeof(int));
dt.Rows.Add(new object[] { 12, DEFINE_STATE.FOUND_ELIF, 13, 0, 2, 7, 12, 10, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 13, DEFINE_STATE.FOUND_DEFINE_IN_ELIF, -1, 14, 2, 7, 12, 10, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_ELIF_LINE_NUMBER });
dt.Rows.Add(new object[] { 14, DEFINE_STATE.FOUND_INCLUDE_IN_ELIF, 13, 0, 2, 7, 12, 10, ERROR.NO_ERROR, ACTION.RESET_DEFINE_ELIF_LINE_NUMBER });
I added a check to see if elif_level is == 0, if so, then proceed as usual, removing the level of if-nest. Otherwise I remove elif_level and then the if-nest level.
Do the above rows look correct? I am thinking of either adding a bool variable to states that is set to true if elif is found, and later when I find an #endif I can pop all states that have elif set to true.
I've been parsing text files like this for over 40 years. This is a complicate logic issue so with any complicated logic issue I would use a State Machine. First I drew a state diagram
Then I wrote code to implement the state table
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Data;
namespace ConsoleApplication1
{
public enum DEFINE_STATE
{
SPECIAL = -4, //define followed by IF
NONE = -3,
INVALID = -2, //Compile will give error, cannot occur
ERROR = -1,
DO_NOT_CARE = 0,
START = 1,
FOUND_IF = 2,
FOUND_DEFINE_IN_IF = 3,
FOUND_DEFINE_NOT_IN_IF = 4,
FOUND_INCLUDE_IN_IF = 5,
FOUND_ELSE = 6,
FOUND_DEFINE_IN_ELSE = 7,
FOUND_INCLUDE_IN_ELSE = 8,
FOUND_INCLUDE_NOT_IN_IF = 9,
FOUND_END_IF = 10,
RETURN = 11,
FOUND_ELIF = 12,
FOUND_DEFINE_IN_ELIF = 13,
FOUND_INCLUDE_IN_ELIF = 14,
}
public enum ERROR
{
NO_ERROR,
DEFINE_FOLLOWED_BY_DEFINE,
DEFINE_FOLLOWED_BY_DEFINE_OR_IF
}
public enum TABLE_COLUMN
{
STATE = 0,
DESCRIPTION = 1,
DEFINE,
INCLUDE,
IF,
ELSE,
ELIF,
END_IF,
ERROR,
ACTION
}
public enum ACTION
{
NONE,
RESET_DEFINE_LINE_NUMBER,
RESET_DEFINE_IF_LINE_NUMBER,
RESET_DEFINE_ELSE_LINE_NUMBER,
RESET_DEFINE_ELIF_LINE_NUMBER,
SET_DEFINE_LINE_NUMBER,
SET_DEFINE_IF_LINE_NUMBER,
SET_DEFINE_ELSE_LINE_NUMBER,
SET_DEFINE_ELIF_LINE_NUMBER,
}
public class State_Variables
{
public int define_Line_Number = 0;
public int define_If_Line_Number = 0;
public int define_Else_Line_Number = 0;
public int define_Elif_Line_Number = 0;
public int return_end_level = 0;
public DEFINE_STATE state = DEFINE_STATE.START;
public DataRow row { get; set; }
}
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
string pattern = "#include\\s+\"test.h\"";
StreamReader reader = new StreamReader(FILENAME);
string input = "";
DataTable dt = new DataTable();
dt.Columns.Add("State", typeof(int));
dt.Columns.Add("Description", typeof(DEFINE_STATE));
dt.Columns.Add("Next Define State", typeof(int));
dt.Columns.Add("Next Include State", typeof(int));
dt.Columns.Add("Next IF State", typeof(int));
dt.Columns.Add("Next Else State", typeof(int));
dt.Columns.Add("Next ELIF State", typeof(int));
dt.Columns.Add("Next ENDIF State", typeof(int));
dt.Columns.Add("Error Number", typeof(ERROR));
dt.Columns.Add("Action", typeof(ACTION));
//0 do not care
//-1 error
//-2 invalid
dt.Rows.Add(new object[] { 1, DEFINE_STATE.START, 4, 0, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 2, DEFINE_STATE.FOUND_IF, 3, 0, 2, 6, 12, 10, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 3, DEFINE_STATE.FOUND_DEFINE_IN_IF, -1, 5, 2, 6, 12, 10, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_IF_LINE_NUMBER });
dt.Rows.Add(new object[] { 4, DEFINE_STATE.FOUND_DEFINE_NOT_IN_IF, -1, 9, -4, -2, -2, -2, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_LINE_NUMBER });
dt.Rows.Add(new object[] { 5, DEFINE_STATE.FOUND_INCLUDE_IN_IF, 3, 0, 2, 6, 12, 10, ERROR.NO_ERROR, ACTION.RESET_DEFINE_IF_LINE_NUMBER });
dt.Rows.Add(new object[] { 6, DEFINE_STATE.FOUND_ELSE, 7, 0, 2, -2, -2, 10, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 7, DEFINE_STATE.FOUND_DEFINE_IN_ELSE, -1, 8, 2, -2, -2, 10, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_ELSE_LINE_NUMBER });
dt.Rows.Add(new object[] { 8, DEFINE_STATE.FOUND_INCLUDE_IN_ELSE, 7, 0, 2, -2, -2, 10, ERROR.NO_ERROR, ACTION.RESET_DEFINE_ELSE_LINE_NUMBER });
dt.Rows.Add(new object[] { 9, DEFINE_STATE.FOUND_INCLUDE_NOT_IN_IF, 4, 0, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.RESET_DEFINE_LINE_NUMBER });
dt.Rows.Add(new object[] { 10, DEFINE_STATE.FOUND_END_IF, 11, 1, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 11, DEFINE_STATE.RETURN, -2, -2, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 12, DEFINE_STATE.FOUND_ELIF, 13, 0, 2, -2, 12, 10, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 13, DEFINE_STATE.FOUND_DEFINE_IN_ELIF, -1, 14, 2, -2, 12, 10, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_ELIF_LINE_NUMBER });
dt.Rows.Add(new object[] { 14, DEFINE_STATE.FOUND_INCLUDE_IN_ELIF, 13, 0, 2, 7, 12, 10, ERROR.NO_ERROR, ACTION.RESET_DEFINE_ELIF_LINE_NUMBER });
int level = 0;
List<State_Variables> states = new List<State_Variables>();
State_Variables newState = new State_Variables();
states.Add(newState);
DEFINE_STATE nextState = DEFINE_STATE.START;
ACTION action = ACTION.NONE;
int line_number = 0;
while ((input = reader.ReadLine()) != null)
{
line_number++;
input = input.Trim();
if (input.StartsWith("//")) continue; //ignore comments
if (input.Length == 0) continue;
Boolean returnFromIF = false;
Match match = Regex.Match(input, pattern);
//test if end if is followed by include
if (states[level].state == DEFINE_STATE.FOUND_END_IF)
{
int return_end_level = 0;
do
{
if (!match.Success)
{
int define_If_Line_Number = states[level].define_If_Line_Number;
int define_Else_Line_Number = states[level].define_Else_Line_Number;
int define_Elif_Line_Number = states[level].define_Elif_Line_Number;
if (define_If_Line_Number != 0)
{
Console.WriteLine("Define in IF at line {0} does not have and include", define_If_Line_Number.ToString());
}
if (define_Else_Line_Number != 0)
{
Console.WriteLine("Define in ELSE at line {0} does not have and include", define_Else_Line_Number.ToString());
}
if (define_Elif_Line_Number != 0)
{
Console.WriteLine("Define in ELSE at line {0} does not have and include", define_Else_Line_Number.ToString());
}
}
return_end_level = states[level].return_end_level;
states.RemoveAt(level--);
} while (level > return_end_level);
returnFromIF = true;
}
else
{
states[level].row = dt.AsEnumerable().Where(x => x.Field<int>((int)TABLE_COLUMN.STATE) == (int)states[level].state).FirstOrDefault();
}
nextState = DEFINE_STATE.NONE;
//check if defines are terminated with include
if (input.Contains("#define"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.DEFINE);
}
if (match.Success)
{
if (returnFromIF)
{
nextState = states[level].state;
}
else
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.INCLUDE);
}
}
if (input.Contains("#if"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.IF);
states.Add(new State_Variables());
level++;
states[level].return_end_level = level - 1;
}
if (input.Contains("#else"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.ELSE);
}
if (input.Contains("#elif"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.ELIF);
states.Add(new State_Variables());
level++;
states[level].return_end_level = states[level - 1].return_end_level;
}
if (input.Contains("#endif"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.END_IF);
}
if ((nextState != DEFINE_STATE.ERROR) && (nextState != DEFINE_STATE.DO_NOT_CARE) && (nextState != DEFINE_STATE.NONE))
{
states[level].state = nextState;
}
switch (nextState)
{
case DEFINE_STATE.DO_NOT_CARE:
//stay at current state
break;
case DEFINE_STATE.NONE: //stay at current state
Console.WriteLine("Did not find state at line {0}", line_number);
break;
case DEFINE_STATE.INVALID:
Console.WriteLine("Invalid IF/ELSE/END_IF at line {0}", line_number);
break;
case DEFINE_STATE.ERROR:
action = states[level].row.Field<ACTION>((int)TABLE_COLUMN.ACTION);
switch (action)
{
case ACTION.SET_DEFINE_LINE_NUMBER:
Console.WriteLine("Define followed by Define at line {0}", states[level].define_Line_Number.ToString());
states[level].define_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_IF_LINE_NUMBER:
Console.WriteLine("Define in IF followed by Define by at line {0}", states[level].define_If_Line_Number.ToString());
states[level].define_If_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELSE_LINE_NUMBER:
Console.WriteLine("Define in ELSE followed by Define at line {0}", states[level].define_Else_Line_Number.ToString());
states[level].define_Else_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELIF_LINE_NUMBER :
Console.WriteLine("Define in ELIF followed by Define at line {0}", states[level].define_Elif_Line_Number.ToString());
states[level].define_Elif_Line_Number = line_number;
break;
}
break;
case DEFINE_STATE.SPECIAL:
Console.WriteLine("Define followed IF at line {0}", states[level].define_Line_Number.ToString());
states[level - 1].state = DEFINE_STATE.START;
states[level].state = DEFINE_STATE.FOUND_IF;
nextState = DEFINE_STATE.FOUND_IF;
states[level].row = dt.AsEnumerable().Where(x => x.Field<DEFINE_STATE>((int)TABLE_COLUMN.STATE) == nextState).FirstOrDefault();
break;
default:
states[level].row = dt.AsEnumerable().Where(x => x.Field<DEFINE_STATE>((int)TABLE_COLUMN.STATE) == nextState).FirstOrDefault();
action = states[level].row.Field<ACTION>((int)TABLE_COLUMN.ACTION);
switch (action)
{
case ACTION.RESET_DEFINE_LINE_NUMBER:
states[level].define_Line_Number = 0;
break;
case ACTION.RESET_DEFINE_IF_LINE_NUMBER:
states[level].define_If_Line_Number = 0;
break;
case ACTION.RESET_DEFINE_ELSE_LINE_NUMBER:
states[level].define_Else_Line_Number = 0;
break;
case ACTION.RESET_DEFINE_ELIF_LINE_NUMBER:
states[level].define_Elif_Line_Number = 0;
break;
case ACTION.SET_DEFINE_LINE_NUMBER:
states[level].define_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_IF_LINE_NUMBER:
states[level].define_If_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELSE_LINE_NUMBER:
states[level].define_Else_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELIF_LINE_NUMBER:
states[level].define_Elif_Line_Number = line_number;
break;
}
states[level].state = nextState;
break;
}
}
//final checks
int define_Line_Number = states[level].define_Line_Number;
if (define_Line_Number != 0)
{
Console.WriteLine("Define at line {0} does not have and include", define_Line_Number.ToString());
}
if (level != 0)
{
Console.WriteLine("Did not close all IFs with End_If");
}
Console.WriteLine("Done");
Console.ReadLine();
}
}
}
If the common denominator of all text you want to analyze is a hierarchically structured document, maybe you should start by converting it to that and then do the rest of the analysis on the parsed document and not do both at the same time. Perhaps converting it to an XML-document could be sufficient for your case and then do the analysis using XSLT/XPath (Or LINQ for XDocument if you prefer that). This is basically how other code analysis is performed as well (Roslyn Code Analyzers with Syntax Trees except much more fancy of course).
I'm trying to use csvhelper to create my csv file by following some tutorials but all my data get written in only one column. This is my code:
EDITED As I understood from the comments, the problem is with excel reading the csv files. I found some solution that I can fix this problem by making some changes in Excel setting, in that case my question is: is there anyway to address this issue from my code, that it won't require any changes in Excel setting to be able to read csv files properly?
public void CreateCSVFile()
{
using (var sw = new StreamWriter(#"countrylistoutput.csv"))
{
var writer = new CsvWriter(sw);
using (var dt = ExportToCSV())
{
foreach (DataColumn column in dt.Columns)
{
writer.WriteField(column.ColumnName);
}
writer.NextRecord();
foreach (DataRow row in dt.Rows)
{
for (var i = 0; i < dt.Columns.Count; i++)
{
writer.WriteField(row[i]);
}
writer.NextRecord();
}
}
}
}
I don't get what I'm doing wrong, I would appreciate it if anyone could help me with this issue.
And here is how I tried to feed the data:
public System.Data.DataTable ExportToCSV()
{
System.Data.DataTable table = new System.Data.DataTable();
table.Columns.Add("ID", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Sex", typeof(string));
table.Columns.Add("Subject1", typeof(int));
table.Columns.Add("Subject2", typeof(int));
table.Columns.Add("Subject3", typeof(int));
table.Columns.Add("Subject4", typeof(int));
table.Columns.Add("Subject5", typeof(int));
table.Columns.Add("Subject6", typeof(int));
table.Rows.Add(1, "Amar", "M", 78, 59, 72, 95, 83, 77);
table.Rows.Add(2, "Mohit", "M", 76, 65, 85, 87, 72, 90);
table.Rows.Add(3, "Garima", "F", 77, 73, 83, 64, 86, 63);
table.Rows.Add(4, "jyoti", "F", 55, 77, 85, 69, 70, 86);
table.Rows.Add(5, "Avinash", "M", 87, 73, 69, 75, 67, 81);
table.Rows.Add(6, "Devesh", "M", 92, 87, 78, 73, 75, 72);
return table;
}
}
screenshot of the result
Thanks
That happens when Excel doesn't use commas as the field separator (it depends on Excel's locale). The solution for Excel specifically is to add a special sep=, line at the top of the file, above any headers. For example:
using (var streamWriter = new StreamWriter(outputFilePath))
{
streamWriter.WriteLine("sep=,"); // make Excel use comma as field separator
using (var csvWriter = new CsvWriter(streamWriter))
{
csvWriter.WriteField("field A");
csvWriter.WriteField("field B");
csvWriter.NextRecord();
}
}
That will fix the problem in Excel, but cause problems in other spreadsheet apps. You can support both by making that sep=, line conditional on the intended format. Here's how that might look in a web UI:
Most probably your CSV looks like
a,b,c
d,e,f
you need to make it
"a","b","c"
"d","e","f"
https://stackoverflow.com/a/54027009/9306125
I'm not able to find any information about the possibility of specifying encoding (utf-8 in particular) when opening a text file with the excel.Workbooks.OpenText method. My problem is that I'm trying to open a CSV file that is encoded in UTF-8 and without this setting it loads as a bunch of squiggles.
Thanks a lot!
I found this as a working solution to import an UTF-8 csv file:
(it can be optimized a bit, but with this you can work in the right direction)
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Workbook wb;
Worksheet ws;
Range range;
int[,] a = new int[,] { { 1, 1 }, { 2, 2 }, { 3, 2 }, { 4, 2 }, { 5, 2 }, { 6, 2 }, { 7, 2 }, { 8, 2 }, { 9, 2 }, { 10, 2 }, { 11, 2 }, { 12, 2 }, { 13, 2 }, { 14, 2 }, { 15, 2 }, { 16, 2 }, { 17, 2 }, { 18, 2 }, { 19, 2 }, { 20, 2 }, { 21, 2 }, { 22, 2 } };
excelApp.Workbooks.OpenText(ofdGetExcel.FileName,
65001,
1,
XlTextParsingType.xlDelimited,
XlTextQualifier.xlTextQualifierDoubleQuote,
false,
false,
false,
true,
false,
false,
false,
a,
Type.Missing,//",",
Type.Missing,//".",
Type.Missing,//false,
Type.Missing);//false);
wb = excelApp.ActiveWorkbook;
ws = wb.Worksheets.get_Item(1);
range = ws.get_Range("A2");
Microsoft.Office.Interop.Excel.QueryTable QT = ws.QueryTables.Add("TEXT;" + ofdGetExcel.FileName, range);
QT.Name = ofdGetExcel.FileName;
QT.FieldNames = true;
QT.RowNumbers = true;
QT.FillAdjacentFormulas = false;
QT.PreserveFormatting = true;
QT.RefreshOnFileOpen = false;
QT.RefreshStyle = Microsoft.Office.Interop.Excel.XlCellInsertionMode.xlInsertDeleteCells;
QT.SavePassword = false;
QT.SaveData = true;
QT.AdjustColumnWidth = true;
QT.RefreshPeriod = 0;
QT.TextFilePromptOnRefresh = false;
QT.TextFilePlatform = 65001;
QT.TextFileStartRow = 1;
QT.TextFileParseType = Microsoft.Office.Interop.Excel.XlTextParsingType.xlDelimited;
QT.TextFileTextQualifier = Microsoft.Office.Interop.Excel.XlTextQualifier.xlTextQualifierDoubleQuote;
QT.TextFileConsecutiveDelimiter = false;
QT.TextFileTabDelimiter = false;
QT.TextFileSemicolonDelimiter = false;
QT.TextFileCommaDelimiter = true;
QT.TextFileSpaceDelimiter = false;
QT.TextFileDecimalSeparator = ",";
QT.TextFileThousandsSeparator = ".";
ws.QueryTables[1].Destination.EntireColumn.AutoFit();
ws.QueryTables[1].Refresh(false);
ws.QueryTables[1].Delete();
I am trying to create a StackedColumn chart in my asp.net application. So I have a datatable like this -
DataTable dtTemp = new DataTable();
dtTemp.Columns.Add("Phase", typeof(string));
dtTemp.Columns.Add("Status", typeof(string));
dtTemp.Columns.Add("Count", typeof(int));
dtTemp.Rows.Add("Initiate", "Pending", 10
dtTemp.Rows.Add("Initiate", "OnHold", 20);
dtTemp.Rows.Add("Initiate", "Rejected", 3);
dtTemp.Rows.Add("Initiate", "Cancelled", 5);
dtTemp.Rows.Add("Initiate", "Pending IT", 2);
dtTemp.Rows.Add("Setup", "Setup", 25);
Now I want the chart to display 2 column, first column will show the Initiate phase data with different status data. And 2nd column will show setup phase data. I have tried like this -
foreach (DataRow row in dtTemp.Rows)
{
string seriesName = row["Status"].ToString();
chart_ProjectStatus.Series.Add(seriesName);
chart_ProjectStatus.Series[seriesName].ChartType = SeriesChartType.StackedColumn;
chart_ProjectStatus.Series[seriesName].ChartArea = "ChartArea1";
chart_ProjectStatus.Series[seriesName].CustomProperties = "DrawingStyle=Cylinder, MaxPixelPointWidth=50";
chart_ProjectStatus.Series[seriesName].Points.AddXY(row["Phase"].ToString(), Convert.ToInt32(row["Count"].ToString()));
}
But I am getting only one column -
Please some one help me.
Thanks in advance
Gulrej
<b> Hope this will Help you </b>
DataTable dtTemp = new DataTable();
dtTemp.Columns.Add("Phase", typeof(string));
dtTemp.Columns.Add("Status", typeof(string));
dtTemp.Columns.Add("Count", typeof(int));
dtTemp.Columns.Add("StackGroupName", typeof(string));
dtTemp.Rows.Add("Initiate", "Pending", 10, "Group1");
dtTemp.Rows.Add("Initiate", "OnHold", 20, "Group1");
dtTemp.Rows.Add("Initiate", "Rejected", 3, "Group1");
dtTemp.Rows.Add("Initiate", "Cancelled", 5, "Group1");
dtTemp.Rows.Add("Initiate", "PendingIT", 2, "Group1");
dtTemp.Rows.Add("Setup", "Setup", 25, "Group2");
dtTemp.Rows.Add("Setup", "INSTALLED", 55, "Group2");
dtTemp.AcceptChanges();
Series ss;
for (int i = 0; i < dtTemp.Rows.Count; i++)
{
ss = new Series();
ss.Name = dtTemp.Rows[i][1].ToString();
ss.ChartType = SeriesChartType.StackedColumn;
ss["StackedGroupName"] = dtTemp.Rows[i]["StackGroupName"].ToString();
ss["DrawingStyle"] = "Cylinder";
ss.Points.AddXY(Convert.ToString(dtTemp.Rows[i]["Phase"]), Convert.ToInt32(dtTemp.Rows[i]["Count"]));
ss.IsValueShownAsLabel = true;
ChartSideBySideStacked.Series.Add(ss);
}
ChartArea chartAread = new ChartArea();
chartAread.Area3DStyle.Enable3D = true;
chartAread.Area3DStyle.Rotation = 5;
chartAread.Area3DStyle.Inclination = 10;
chartAread.Area3DStyle.IsRightAngleAxes = false;
ChartSideBySideStacked.ChartAreas.Add(chartAread);
ChartSideBySideStacked.Legends.Add(new Legend("CHartLEgend"));
ChartSideBySideStacked.AlignDataPointsByAxisLabel(); // Chart Object Name : ChartSideBySideStacked
Enable 3D
U must Provide Stacked Group Name for Each Series
Set Rotation Angle
Set Inclination and IsRightAngleAxes
this one is working fine ... please note i am using VS 2010.. Asp.Net