Another Look at Transferring Excel data rows to an Array (Edited) - c#

For clarification, I am trying to transfer each, whole Excel row into list. In the case of the simplified example, I am trying to transfer the first row into a string array.
I have worked through several posts on the topic of converting each row of an Excel spreadsheet and transferring each row to a List, including this post
Despite playing around with examples, I still get a conversion error. I narrowed down my program to a simple example, just offloading the first row, which contains column headers into a string array, and I am getting an error saying cannot convert a generic list to a string[].
I can print the first line using Console.Write(String.Format(dataRange.Value2.ToString() + " "), but cannot save the first line.
Here is the simplified program that produces the error:
static void Main(string[] args)
{
string [] m_column_headings;
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook wbv = excel.Workbooks.Open("H:\\my_documents\\testFile.xlsx");
Microsoft.Office.Interop.Excel.Worksheet wx = excel.ActiveSheet as Microsoft.Office.Interop.Excel.Worksheet;
Range dataRange = (Range)wx.Cells[1, 1];
m_column_headings = dataRange.Cast<object>().Select(o => o.ToString()).ToList(); <--- This line gets the error.
Based on the answer, I made the following modifications to keep the types correct, but I am not able to see what I assigned.
dataRange = (Range)wx.Cells[1, 1];
m_column_headings =
dataRange.Cast<object>().Select(o => o.ToString()).ToArray();

You are trying to retrieve string Array but then asking the code to return .ToList(). Either convert m_column_headings to a list, or change the return type to .ToArray()
i.e.
m_column_headings = dataRange.Cast<object>().Select(o => o.ToString()).ToArray();

I appreciate the answer and comments. They helped jog me into figuring out what was going wrong:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Office.Interop.Excel;
namespace ExcelTest1
{
class Program
{
static void Main(string[] args)
{
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook wbv = excel.Workbooks.Open("H:\\my_documents\\town\\personnel\\May 18 MuniRosterDetailReport.xlsx");
Microsoft.Office.Interop.Excel.Worksheet wx = excel.ActiveSheet as Microsoft.Office.Interop.Excel.Worksheet;
Range dataRange = null;
int totalColumns = wx.UsedRange.Columns.Count;
int totalRows = wx.UsedRange.Rows.Count;
List<string> m_column_headings = new List<string>();
dataRange = (Range)wx.UsedRange;
int row = 1;
for(int colIdx = 1; colIdx < (totalColumns + 1); colIdx++)
{
Range tempRange = (Range )wx.Cells[row, colIdx];
m_column_headings.Add(String.Format(tempRange.Value2.ToString() + ","));
}
int i = 0;
wbv.Close(true, Type.Missing, Type.Missing);
excel.Quit();
}
}
}

Related

How to return cell address if you know cell value

Heads up that I am very new to coding.
I'm writing code in c# and I've linked to an excel document.
I need to be able to find the cell address of a cell that has a cell value that I already know. For example, I need to find the address of the cell that has the word 'chocolate' and for it, for example, to return "A2".
Here's what I've written so far but I'm very new to coding so don't know if it works:
using System;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using Microsoft.Office.Interop.Excel;
using _Excel = Microsoft.Office.Interop.Excel;
namespace Name
{
class Program
static void Main(string[] args)
{
}
class Excel
// client can put in their own excel spreadsheet and whatever worksheet within it, they then put the time down
static int GetCellValue(string ExcelSheet = "C:\Users\Laura Dennis\Desktop\Translation
Internship\Coding\Data.xlsx", int worksheet = 2, int time)
{
// create app
var excelApp = new Excel.Application();
// open workbook
var workbook = excelApp.Workbooks.Open(
# ExcelSheet
);
// open worksheet
var Excel.Worksheet worksheet = worksheet;
// get the value for each cell
int value = cell.InnerText
// read each cell within the first column
Excel.Range namedRange = (Excel.Range)worksheet.get_Range("A2", "A55");
// see if it matches
foreach (Excel.Range cell in namedRange.Cells)
{
// return cell address and from here can get other cell values to calculate the
outstanding series of payments
if (value == time)
{string RangeAddress(Excel.Range rng)
{
return rng.get_AddressLocal(false, false, Excel.XlReferenceStyle.xlA1,
missing, missing);
}
}
}
}
}

Interop Excel reads all Values into 1 Line

I'm tying to read an Excel-Sheet into an array, but when I read out of the array all values of the whole row are saved in the first column separated by ';'.
How can I save them properly in a 2-dimensional array?
This is my code:
using Microsoft.Office.Interop.Excel;
using System;
using System.IO;
namespace BB_Entwurf_2
{
class Program
{
public static void Main(string[] args)
{
ApplicationClass app = new ApplicationClass();
Workbook book = null;
Worksheet sheet = null;
string currentDir = Environment.CurrentDirectory;
string excelPath;
excelPath = Path.Combine(currentDir, "MyFile.csv");
app.Visible = false;
app.ScreenUpdating = false;
app.DisplayAlerts = false;
book = app.Workbooks.Open(excelPath);
sheet = (Worksheet)book.Worksheets[1];
int rowCount = sheet.UsedRange.Rows.Count;
Console.WriteLine(rowCount);
Range range = sheet.UsedRange;
object[,] myExcelFileValues = (object[,])range.Value2;
range = null;
string test = (Convert.ToString(myExcelFileValues[1,1]));
Console.WriteLine(test);
test = (Convert.ToString(myExcelFileValues[2,2]));
Console.WriteLine(test);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheet);
sheet = null;
book.Close(false);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(book);
book = null;
app.Quit();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(app);
app = null;
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}
I'll agree with the comments about a CSV parser, but if you're dead set on using Excel, it won't automatically delimit on your semicolon. You'll need to perform a text to columns first. Something like:
range.TextToColumns(range[1, 1], XlTextParsingType.xlDelimited, XlTextQualifier.xlTextQualifierDoubleQuote, Semicolon: true);
If most/all of the values are strings, you could just split in your c#.
The aforementioned "CSV parser" solution would just be:
excelPath = Path.Combine(currentDir, "MyFile.csv");
string[] lines = File.ReadAllLines(excelPath);
List<string[]> values = new List<string[]>();
foreach (string line in lines)
{
values.Add(line.Split(';'));
}
// parse strings into int, double, date, etc.
Actually less code and no required installations...
You can take first blank array and take a loop to get value one by one as follow
string[] arr = new string[];
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Open(path);
Excel.Worksheet worksheet = workbook.ActiveSheet;
Excel.Range range = worksheet.UsedRange;
for (int row = 1; row <= range.Rows.Count; row++)
{
arr[row-1] = ((Excel.Range)range.Cells[row, 1]).Text;
}

Export List to Excel

So I have a list of data that I am trying to export to excel. I just want to list it going down column 1 but it refuses. I was originally going to use a foreach loop but i was worried that would slow down my program and i wouldn't be able to use the for loop idea i had. Does anyone have any good ideas to just import this. I feel like it shouldn't be as hard as i am making it. This is what i have done so far. Thanks in advance.
if (dialog == DialogResult.Yes)
{
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Workbook wb = excel.Workbooks.Add(XlSheetType.xlWorksheet);
Worksheet ws = (Worksheet)excel.ActiveSheet;
ws.Cells[1, 1] = "Folder Names";
for (int row = 0; row <= count; row++)
{
ws.Cells [1, row+2] = Namelist;
}
excel.Visible = true;
}
I want to go sequentially down the list as well. (the code above wont export Namelist, rest works though)
Namelist = list
int count (it is a counter i started earlier in the program to determine the number of lines of Namelist)
If Namelist is List<string>, the easiest way is to copy it to the Clipboard:
var text = "Folder Names\n" + string.Join("\n", Namelist); // or "\r\n"
System.Windows.Forms.Clipboard.SetText(text);
var xl = new Microsoft.Office.Interop.Excel.Application();
var wb = xl.Workbooks.Add();
var ws = xl.ActiveSheet as Worksheet;
ws.Range("A1").PasteSpecial();
xl.Visible = true;
or even easier because Excel is associated with .csv files by default:
var fileName = #"list.csv"; // or change to .xls and get warning message box
System.IO.File.WriteAllText(fileName, "Folder Names\n" + string.Join("\n", Namelist));
System.Diagnostics.Process.Start(fileName);
Update
CSV stands for Comma Separated Values, so if you want the list in a different column you have to add commas before the values. For example in columns 2 and 4:
,Folder Names,,Folder Size
,name1,,256
,name2,,"1,024"
If you have 2 lists with the same size, you can zip them together:
string[] names = {"name1", "name2"};
int[] sizes = {256, 1024};
var lines = names.Zip(sizes, (name, size) => name + "," + size); // {"name1,256", "name2,1024"}
var csv = "Names,Sizes\n" + string.Join("\n", lines);
The for loop won't slow down your program, but accessing the cells individually will. Each call to Cells is a COM-interop call, which is relatively expensive. It's much faster to put your data in an array, define a Range that represents the entire range of output, and set the Value there:
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
var wbs = excel.Workbooks;
Workbook wb = wbs.Add(XlSheetType.xlWorksheet);
Worksheet ws = (Worksheet)excel.ActiveSheet;
List<object> data = new List<object>
data.Add("Folder Names");
for (int row = 0; row <= count; row++)
{
data.Add(Namelist);
}
Excel.Range rng = (Excel.Range)ws.Range[ws.Cells[1, 1], ws.Cells[1,count + 2]];
rng.Value = data.ToArray();
excel.Visible = true;
Assuming Namelist is a string[] or List<string> what you're missing is the extraction of each item from the Namelist collection before setting the value of each cell:
ws.Cells[1, 1] = #"Folder names";
for(int row = 2; row <= count; row ++)
{
var name = Namelist[row-2];
ws.Cells[1, row] = name;
}
When you use the Cells property the first argument is the row, the second is the column. You have it reversed.
Also, if you haven't gone too far down the path of learning Excel interop, I would switch to EPPlus. It's 100x times easier to work with, doesn't involve messing with COM objects, and doesn't even require Excel. It's just better.
Super easy way to export your list to excel using c#
How to install ClosedXML with NuGet Packager Manager Console:
PM> Get-Project [ProjectName] | Install-Package ClosedXML
using (var conn = new DB.Entities())
{
var stories = (from a in conn.Subscribers
orderby a.DT descending
select a).Take(100).ToList();
var ShowHeader = true;
PropertyInfo[] properties = stories.First().GetType().GetProperties();
List<string> headerNames = properties.Select(prop => prop.Name).ToList();
var wb = new XLWorkbook();
var ws = wb.Worksheets.Add("Subscribers");
if (ShowHeader)
{
for (int i = 0; i < headerNames.Count; i++)
ws.Cell(1, i + 1).Value = headerNames[i];
ws.Cell(2, 1).InsertData(stories);
}
else
{
ws.Cell(1, 1).InsertData(stories);
}
wb.SaveAs(#"C:\Testing\yourExcel.xlsx");
}

How do I get and compare the contents of a cell in an Excel spreadsheet by name?

I'm trying to compare a cell with a string to replace it if it is equal. But when I try to do the code below the 0x800A03EC error occurs.
int cont = 0;
string cell;
do
{
cont++;
cell = rCol.ToUpper() + cont.ToString(); // = "D1"
string cellData = ((Excel.Range)sheet.Cells[cell]).Value2.ToString();
if (cellData == from)
{
sheet.Cells[cell] = to;
}
} while (sheet.Cells[cell] == null);
How can I do this?
If you know the cell you want to check, for example A1, you can do it like this:
using System;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
namespace Test
{
class Program
{
static void Main(string[] args)
{
// create app
var excelApp = new Excel.Application();
// open workbook
var workbook = excelApp.Workbooks.Open(
#"C:\Users\Home\Documents\Book1.xlsx",
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing);
// open sheet
var sheet = (Excel.Worksheet)workbook.Sheets[1];
// create some variables
var from = "Pete";
var to = "Dave";
// compare cell A1 [1,1] with 'from'
if (string.Equals(sheet.Cells[1,1].Value, from))
{
sheet.Cells[1, 1].Value = to;
}
// save the workbook
workbook.Save();
// close the workbook and release resources
workbook.Close(true, workbook.Path);
Marshal.ReleaseComObject(workbook);
workbook = null;
}
}
}
Try this to get at a simple range:
int row = 1;
string col = "D";
string text = sheet.get_Range(col + row.ToString()).Value;
The 0x800A03EC error is a value returned by Excel, which means NAME_NOT_FOUND (see this SA question). Looks like you were passing a parameter that Excel could not find, probably because you were passing a string ("D1"), rather than two integer parameters (4,1).
It's impossible to tell where you are getting the rCol.ToUpper() value, without seeing more of your code. However, if you are attempting to go through a series of columns and rows to check for an equality condition (that's what it looks like you are attempting), you will quickly run into the pesky problem of how to increment the column value using capital letters (just try it; not much fun!).
One solution I did in VB recently was to use the native Excel function index, which uses numeric values to get at a particular cell. You would need to cast an object of the type Excel.WorksheetFunction to use that function. But I have since discovered there are easier solutions than using an Excel function:
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;
namespace exceltest
{
class Program
{
static void Main(string[] args)
{
Microsoft.Office.Interop.Excel.Application xl = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook workbook = xl.Workbooks.Open(#"C:\test.xlsx");
Microsoft.Office.Interop.Excel.Worksheet sheet = workbook.Sheets[1];
xl.Visible = true;
//use this if you want to use native Excel functions (such as index)
Microsoft.Office.Interop.Excel.WorksheetFunction wsFunc = xl.WorksheetFunction;
int maxNum = 100; // set maximum number of rows/columns to search
string from = "blah";
string to = "blum";
//this is pretty slow, since it has to interact with 10,000 cells in Excel
// just one example of how to access and set cell values
for (int col = 1; col <= maxNum; col++)
{
for (int row = 1; row <= maxNum; row ++)
{
Range cell = (Range)sheet.Cells[row, col];
if ((string)cell.Value == from) //cast to string to avoid null reference exceptions
{
cell.Value = to;
}
}
}
}
}
}

How to read cell values from existing excel file

I want to read the each cell value in excel file, But i am not able to get the cell values even after trying different examples in NET. I am not getting result with the following code, can any one get back on this. I am using .net framework 2.0
string filePath = "F:/BulkTest.xlsx";
Microsoft.Office.Interop.Excel.Application ExcelApp = new Microsoft.Office.Interop.Excel.Application();
ExcelApp.Visible = true;
Microsoft.Office.Interop.Excel.Workbook wb = ExcelApp.Workbooks.Open(filePath, Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value,Missing.Value);
Microsoft.Office.Interop.Excel.Worksheet sh = (Microsoft.Office.Interop.Excel.Worksheet)wb.Sheets["Sheet1"];
Range excelRange = sh.UsedRange;
for (int i=2; i<= excelRange.Count + 1 ; i++)
{
string values = sh.Cells[i,2].ToString();
}
Till now i am trying to take cell values directly to variables, now i will try to take cell values to an array using Range. Thanks!!!! – Teja Varma 13 mins ago
No. I didn't even mean that :) As I mentioned in the comment that you can store the entire range in an array. That doesn't mean that you need to loop though each cell to store it in an array. You can directly assign the values of the range to the array. See this example.
xlRng = xlWorkSheet.get_Range("A1", "A20");
Object arr = xlRng.Value;
foreach (object s in (Array)arr)
{
MessageBox.Show(s.ToString());
}
The correct answer would be to use:
Sheet.Cells[row,col].Value.ToString();
C# code
Tested OK
string s = xlSheet.UsedRange.Cells[1, 7].Value.ToString();
//or
string d = xlSheet.UsedRange.Cells[1, "G"].Value.ToString();
Full Code
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlBook;
Excel.Worksheet xlSheet;
string Path = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
xlBook = xlApp.Workbooks.Open(Path + "\\myfile.xlsx");
xlApp.Visible = true;
xlSheet = xlBook.ActiveSheet;
string s = xlSheet.UsedRange.Cells[1, 7].Value.ToString();
string d = xlSheet.UsedRange.Cells[1, "G"].Value.ToString();
xlBook.Close();
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

Categories

Resources