简体   繁体   English

如何找到一行中最后使用的列? C#

[英]How do i find the last used column in a row? C#

I have an excel sheet that I am reading.我有一张正在阅读的 Excel 表格。 it contains multiple rows (No headers) each row containing a different number of populated columns.它包含多行(无标题),每行包含不同数量的填充列。 ie row 1 has data in the first three columns.即第1行在前三列中有数据。 row 2 has data in the first 140 columns.第 2 行在前 140 列中有数据。 row 3 has data in the first 32 columns.第 3 行在前 32 列中有数据。 etc etc.等等等等

If I need to find out how many columns row 2 uses (How many contain data), how would I start.如果我需要找出第 2 行使用了多少列(有多少包含数据),我将如何开始。

I am teaching myself c sharp at the moment and am jargon illiterate, so please be as "Layman" as possible.我现在正在自学升c,并且是行话文盲,所以请尽可能成为“外行”。

Any help would be greatly appreciated.任何帮助将不胜感激。

Thank you.谢谢你。

Edit ------------------------编辑 - - - - - - - - - - - -

Had a quick look through some bookmarks and have a rough idea of the code i used to get the row number containing the columns i need to count.快速浏览了一些书签,并大致了解了我用来获取包含我需要计算的列的行号的代码。 (i cant test as i don't have VS installed at home. so dont take this as gospel, but it seems "approximately" correct, sorry.) (我无法测试,因为我没有在家里安装 VS。所以不要将此视为福音,但它似乎“大约”正确,抱歉。)

private static Excel.Application HCObjApp = null;
private static Excel.Workbook HCBook = null; 
private static Excel.Worksheet HCSheet = null;

XLApp = new Excel.Application();
HCBook = MyApp.Workbooks.Open(@"WBPATH\WB.exe");
HCSheet = HCBook.Sheets[1];
lastRow = MySheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell).Row; 

Excel.Range range = HCSheet.Columns["A", Type.Missing];

currentFind = range.Find("Australia",HCSheet.Cells[lastrow, 1]);

from here i need to find the number of used columns in row CurrentFind.从这里我需要在 CurrentFind 行中找到使用的列数。

--------------------Edit-------------------------------- Finally back in the office, This was the code i had to find the row number; - - - - - - - - - - 编辑 - - - - - - - - - - - - - - - --- 终于回到办公室,这是我必须找到行号的代码;

        EHObjApp.Visible = true;

        string ColumnHeader = ResourceDetails.ResourceHolder("Root") + ResourceDetails.ResourceHolder("ResourceFolder") + ResourceDetails.ResourceHolder("ColumnHeaders");
        HCBook = EHObjApp.Workbooks.Open(ColumnHeader);
        HCSheet = HCBook.Worksheets.get_Item(1);
        InputBook = EHObjApp.Workbooks.Open(ResourceDetails.ResourceHolder("Root") + @"\Sales\Output\Zoho_Upload\ZOHOSales.xlsx");
        InputSheet = InputBook.Worksheets.get_Item(1);
        long ExRownumber = HCSheet.Range["A:A"].Find("SalesAustralia").Row + 1;
        Range NewColumns = InputSheet.Range["A1:A" + InputSheet.UsedRange.Columns.Count];

With Many thanks to @Hambone i found the solution (more accurately i found 0.1% of the solution. Hambone found the rest);非常感谢@Hambone,我找到了解决方案(更准确地说,我找到了 0.1% 的解决方案。Hambone 找到了其余的);

            Excel.Range ur = HCSheet.UsedRange;
            Excel.Range r = HCSheet.Cells[ExRownumber, ur.Columns.Count +1];
            r = r.Columns.End[Excel.XlDirection.xlToLeft];
//            r = r.get_End(Excel.XlDirection.xlUp);
            long ExistingColumns = r.Column;


            MessageBox.Show(lastCol.ToString());

This will find the last used column in the row.这将找到行中最后使用的列。

You guys have been an amazing help!你们是一个了不起的帮助!

Thank you谢谢

----------Addition--------------- When finding the smaller column numbers, ie rows of 30 or 31 columns etc, this worked fine. ----------添加--------------- 当找到较小的列号时,即 30 或 31 列的行等,这很好用。 I ran into an issue when trying to find the larger numbers, ie rows of 140 columns.当我试图找到更大的数字时,我遇到了一个问题,即 140 列的行。 Changing xlToLeft back to xlUp solved this issue.将 xlToLeft 改回 xlUp 解决了这个问题。

Thought i would add this in for anyone that requires this solution in the future.以为我会为将来需要此解决方案的任何人添加此功能。

I've seen this technique used in VBA to find the last row in a range, and it ports pretty nicely to C#:我已经看到在 VBA 中使用这种技术来查找范围中的最后一行,并且它很好地移植到 C#:

Excel.Range ur = HCSheet.UsedRange;

Excel.Range r = HCSheet.Cells[2, ur.Columns.Count];
r = r.get_End(Excel.XlDirection.xlToLeft);

The value of r at this point will be the last populated cell in row 2. To get a row other than 2, you would simply change the first parameter in the .Cells indexer.此时r的值将是第 2 行中最后填充的单元格。要获得第 2 行以外的行,您只需更改.Cells索引器中的第一个参数。

To prove it works, you can do something like this:为了证明它有效,您可以执行以下操作:

r.Value = "Gotcha";

To find the last column number, which I think was your question:要找到最后一列编号,我认为这是您的问题:

int lastCol = r.Column;

This my simplicity function get last used row and col with Excel Package这是我的简单函数使用 Excel 包获取最后使用的行和列

public int GetLastUsedRow(ExcelWorksheet sheet)
        {
            if (sheet.Dimension == null) { return 0; } // In case of a blank sheet
            var row = sheet.Dimension.End.Row;
            while (row >= 1)
            {
                var range = sheet.Cells[row, 1, row, sheet.Dimension.End.Column];
                if (range.Any(c => !string.IsNullOrEmpty(c.Text)))
                {
                    break;
                }
                row--;
            }
            return row;
        }
        public int GetLastUsedColumn(ExcelWorksheet sheet)
        {
            int count=0;
            int i = 1;
            while(sheet.Cells[1, i].Value != null)
            {
                count++;
                i++;
            }
            return count;
        }

Excel automation is a ambitious endeavor for just starting with any .NET languages. Excel 自动化是从任何 .NET 语言开始的一项雄心勃勃的努力。 Upfront, many examples on the web don't take into consideration properly releasing memory and will resort to using calls to the garbage collector when not needed.首先,网络上的许多示例都没有考虑正确释放内存,而是在不需要时使用对垃圾收集器的调用。 In the example code below the method UsedRowsColumns does not need any calls to the garbage collector simply because I followed what I call the two dot rule (which 99.99 percent of the time releases all object, but as you will see not always).在下面的示例代码中,UsedRowsColumns 方法不需要对垃圾收集器进行任何调用,这仅仅是因为我遵循了我所谓的两点规则(99.99% 的时间会释放所有对象,但您会看到并非总是如此)。 You will note clicking on kevininstructor on that page for the two dot rule will fail, I changed it as I changed to kareninstructor .您会注意到在该页面上单击 kevininstructor 以获取两个点规则将失败,我将其更改为kareninstructor

  • The classes shown below, I would test them and if they suit your needs place them into a class project so if you want to use this code in other projects you simply add a reference to those projects instead of copying code from project to project.下面显示的类,我将对它们进行测试,如果它们适合您的需要,请将它们放入一个类项目中,因此如果您想在其他项目中使用此代码,您只需添加对这些项目的引用,而不是在项目之间复制代码。
  • The Console.WriteLine in button1 uses VS2015 syntax, if using a lower version then adjustments such as this would be needed Console.WriteLine("{0} {1}",.... button1 中的 Console.WriteLine 使用 VS2015 语法,如果使用较低版本,则需要进行此类调整 Console.WriteLine("{0} {1}",....

Unlike UsedRowsColumns method, LastColumnForRow (which should answer your question) must do some extra work in that the garbage collector needs to be called but not in the same method so I setup the class to have a method CallGarbageCollector which after making the call to LastColumnForRow I call this to release the Range xlColumns which would not release even when doing the two dot rule.与 UsedRowsColumns 方法不同,LastColumnForRow (它应该回答你的问题)必须做一些额外的工作,因为垃圾收集器需要被调用,但不是在同一个方法中,所以我将类设置为有一个方法 CallGarbageCollector 在调用 LastColumnForRow 之后我调用它来释放 Range xlColumns,即使执行两个点规则也不会释放。

Form code to test, button1 makes a call to get the last column for row 2.要测试的表单代码,button1 调用以获取第 2 行的最后一列。

using System;
using System.Windows.Forms;
using System.IO;

namespace UsedRowsCols
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private string fileName = Path.Combine(
            AppDomain.CurrentDomain.BaseDirectory, "Demo.xlsx");
        private string sheetName = "Sheet1";
        /// <summary>
        /// Get last row and last column for a worksheet.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            ExcelUsed eu = new ExcelUsed();
            ExcelLast results = eu.UsedRowsColumns(fileName, sheetName);
            // send results to Visual Studio Output window
            Console.WriteLine($"{results.Row} {results.Column}");
        }

        /// <summary>
        /// Get last used column for a specific row
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            ExcelUsed eu = new ExcelUsed();
            try
            {
                int results = eu.LastColumnForRow(fileName, sheetName,2);
                // send results to Visual Studio Output window
                Console.WriteLine(results);
            }
            finally
            {
                eu.CallGarbageCollector();
            }
        }
    }
}

Class responsible for obtaining used column in button1 above and used rows and columns in button2 above.类负责获取上面button1中使用的列和上面button2中使用的行和列。

using System;
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
using System.IO;

namespace UsedRowsCols
{
    public class ExcelUsed
    {
        /// <summary>
        /// Get last used column for a row
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="sheetName"></param>
        /// <param name="row"></param>
        /// <returns></returns>
        public int LastColumnForRow(string fileName, string sheetName, int row)
        {
            int lastColumn = -1;

            if (File.Exists(fileName))
            {
                Excel.Application xlApp = null;
                Excel.Workbooks xlWorkBooks = null;
                Excel.Workbook xlWorkBook = null;
                Excel.Worksheet xlWorkSheet = null;
                Excel.Sheets xlWorkSheets = null;

                xlApp = new Excel.Application();
                xlApp.DisplayAlerts = false;

                xlWorkBooks = xlApp.Workbooks;
                xlWorkBook = xlWorkBooks.Open(fileName);

                xlApp.Visible = false;

                xlWorkSheets = xlWorkBook.Sheets;

                for (int x = 1; x <= xlWorkSheets.Count; x++)
                {
                    xlWorkSheet = (Excel.Worksheet)xlWorkSheets[x];

                    if (xlWorkSheet.Name == sheetName)
                    {
                        Excel.Range xlCells = null;
                        xlCells = xlWorkSheet.Cells;

                        Excel.Range workRange = xlCells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell);

                        Excel.Range xlColumns = xlWorkSheet.Columns;

                        int count = xlColumns.Count;

                        Marshal.FinalReleaseComObject(xlColumns);
                        xlColumns = null;

                        Excel.Range xlLastRange = (Excel.Range)xlWorkSheet.Cells[row, count];
                        Excel.Range xlDirRange = xlLastRange.End[Excel.XlDirection.xlToLeft];

                        Marshal.FinalReleaseComObject(xlLastRange);
                        xlLastRange = null;

                        lastColumn = xlDirRange.Column;
                        Marshal.FinalReleaseComObject(xlDirRange);
                        xlDirRange = null;

                        Marshal.FinalReleaseComObject(workRange);
                        workRange = null;

                        Marshal.FinalReleaseComObject(xlCells);
                        xlCells = null;

                        break;
                    }

                    Marshal.FinalReleaseComObject(xlWorkSheet);
                    xlWorkSheet = null;

                }

                xlWorkBook.Close();
                xlApp.UserControl = true;
                xlApp.Quit();

                Release(xlWorkSheets);
                Release(xlWorkSheet);
                Release(xlWorkBook);
                Release(xlWorkBooks);
                Release(xlApp);

                return lastColumn;

            }
            else
            {
                throw new Exception("'" + fileName + "' not found.");
            }

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName">file to get information form</param>
        /// <param name="sheetName">valid sheet name to get last row and column</param>
        /// <returns>ExcelLast</returns>
        public ExcelLast UsedRowsColumns(string fileName, string sheetName)
        {

            int RowsUsed = -1;
            int ColsUsed = -1;

            if (File.Exists(fileName))
            {
                Excel.Application xlApp = null;
                Excel.Workbooks xlWorkBooks = null;
                Excel.Workbook xlWorkBook = null;
                Excel.Worksheet xlWorkSheet = null;
                Excel.Sheets xlWorkSheets = null;

                xlApp = new Excel.Application();
                xlApp.DisplayAlerts = false;

                xlWorkBooks = xlApp.Workbooks;
                xlWorkBook = xlWorkBooks.Open(fileName);

                xlApp.Visible = false;

                xlWorkSheets = xlWorkBook.Sheets;

                for (int x = 1; x <= xlWorkSheets.Count; x++)
                {
                    xlWorkSheet = (Excel.Worksheet)xlWorkSheets[x];

                    if (xlWorkSheet.Name == sheetName)
                    {
                        Excel.Range xlCells = null;
                        xlCells = xlWorkSheet.Cells;

                        Excel.Range workRange = xlCells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell);

                        RowsUsed = workRange.Row;
                        ColsUsed = workRange.Column;

                        Marshal.FinalReleaseComObject(workRange);
                        workRange = null;


                        Marshal.FinalReleaseComObject(xlCells);
                        xlCells = null;

                        break;
                    }

                    Marshal.FinalReleaseComObject(xlWorkSheet);
                    xlWorkSheet = null;

                }

                xlWorkBook.Close();
                xlApp.UserControl = true;
                xlApp.Quit();


                Release(xlWorkSheets);
                Release(xlWorkSheet);
                Release(xlWorkBook);
                Release(xlWorkBooks);
                Release(xlApp);

                return new ExcelLast() { Row = RowsUsed, Column = ColsUsed };

            }
            else
            {
                throw new Exception("'" + fileName + "' not found.");
            }
        }
        public void CallGarbageCollector()
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();

        }
        private void Release(object sender)
        {
            try
            {
                if (sender != null)
                {
                    Marshal.ReleaseComObject(sender);
                    sender = null;
                }
            }
            catch (Exception)
            {
                sender = null;
            }
        }
    }
    public class ExcelLast
    {
        /// <summary>
        /// Last used row in specific sheet
        /// </summary>
        public int Row { get; set; }
        /// <summary>
        /// Last used column in specific sheet
        /// </summary>
        public int Column { get; set; }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM