那么,.NET没有内置的Office功能?

时间:2009-09-10 13:08:41

标签: .net interop ms-office

我一直认为它确实如此,虽然我不知道我的想法在哪里...我总是认为将电子表格视为2D数组很容易,但有些搜索SO表明每个人都是使用第三方库?或者,所有那些需要安装不需要Office的解决方案的人......如果我没有这个限制,它会变得更容易吗?

正如我所说,我看了SO,但没有看到这个特定问题的答案。不过也许我的搜索技巧很糟糕......

编辑:我的想法是想在C#应用中打开XLS / CSV文档。我不希望来自单元格的任何复杂数据,只需能够从每个单元格中读取文本值。理想情况下,使用Cell.getText()方法将电子表格视为2D单元格数组的包装器是我需要的所有复杂性。

13 个答案:

答案 0 :(得分:7)

Yes, .NET has built-in Office functionality。但是你会试图用它来打败自己。它也很好隐藏,只与Office 2007及更高版本兼容(除非您下载Office 2003 / XP的兼容性插件)。

最好使用some of the APIs designed to interoperate with Office而不是单独行动。链接用于Office Open XML SDK,可用于创建。* x Office文件(.docx,.xslx等)。


如果您想知道System.IO.Packaging如何与Office相关,则文档跟踪从此处开始:

http://msdn.microsoft.com/en-us/library/dd371623(VS.85).aspx

简写版本是新的办公室格式为Open XML documents。什么是Open XML文档?它们是包含在ZIP文件中的资源包(例如图像)和XML文件。您可以使用任何新的Office文件,将扩展名更改为.zip,然后将其打开以进行查看。

这是什么意思?这意味着您可以解压缩这些文件,将部件作为XDocuments加载并转到城镇。当然,您必须将文件解压缩到一个临时位置,对多个XML文件进行排序以找到您想要的文件,管理更改文件之间的所有连接等等。

或者,您可以使用System.IO.Packaging命名空间及其类型来打开这些文件,访问包中的不同组件(甚至远程),更改它们,并将更改刷新回磁盘。

现在,虽然您可以使用命名空间轻松完成此操作,但您无法安全访问Open XML文件中的不同包。你必须使用魔法字符串来获取部分。这也意味着您几乎必须了解Open XML架构,这很糟糕。

这就是MS提供Open XML SDK的原因,您可以将它与System.IO.Packaging结合使用来打开,更改和保存Open XML office文档。

使用我的first link添加second link,您就会得到原始问题的答案。


要回答OP的澄清,它不会那么容易。 xls文件很复杂;细胞不仅仅是一个二维阵列。但是有免费的API可以帮助您打开和访问其中的数据。

如果您要打开Office 2007兼容文件,我强烈建议您查看Office Open XML SDK。如果您打算打开旧版本(Office 2003,XP),我建议在codeplex.com上使用Excel中的众多项目之一(我想想我使用了{{ 3}})。其中有很多,旨在使Excel电子表格中的数据访问变得非常容易。但不太容易[x] [y]。

答案 1 :(得分:4)

如果要打开较旧格式的.XLS(Excel 97-2003)文件,而不是较新的* .XLSX,则可以尝试使用JET提供程序:

OleDbConnection con = new OleDbConnection(string.Format(
                 "Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1\"",
                 "filename.xls"
                 ));
con.Open();
OleDbDataAdapter ad = new OleDbDataAdapter("SELECT * FROM [Sheet1$]", con);
DataTable t = new DataTable();
ad.Fill(t);

这会将数据放入DataTable中,操作相当容易。

答案 2 :(得分:2)

Visual Basic是(或至少是)用于处理Office应用程序的.NET语言中的优秀,尽管您也可以使用C#。

Programming Office Applications

答案 3 :(得分:2)

不确定您想要做什么,但有一个完整的网站可以在Visual Studio中使用Office。

Understanding the Excel Object Model from a Visual Studio 2005 Developer's Perspective

您可能需要Visual Studio Tools for Office。

答案 4 :(得分:2)

我认为Excel Data Reader会有所帮助。您可以将Microsoft Excel文件('97 -2007)直接读入数据集。

以下是一些示例代码(来自网站):

FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read);

//1. Reading from a binary Excel file ('97-2003 format; *.xls)
IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream);
//...
//2. Reading from a OpenXml Excel file (2007 format; *.xlsx)
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
//...
//3. DataSet - The result of each spreadsheet will be created in the result.Tables
DataSet result = excelReader.AsDataSet();
//...
//4. DataSet - Create column names from first row
excelReader.IsFirstRowAsColumnNames = true;
DataSet result = excelReader.AsDataSet();

//5. Data Reader methods
while (excelReader.Read())
{
    //excelReader.GetInt32(0);
}

//6. Free resources (IExcelDataReader is IDisposable)
excelReader.Close();

答案 5 :(得分:0)

不,.NET没有内置的Office功能。

答案 6 :(得分:0)

您需要安装Visual Studio Tools for Office

答案 7 :(得分:0)

我发现将办公室文件保存为XML文档然后解析和操作XML比在Office Interop深处停留更容易。我发现自己说的很多。你的旅费可能会改变。 XML格式适用于较大的文件,但它的易用性非常值得。

答案 8 :(得分:0)

您是否尝试过查看Visual Studio Tools for Office?它是一个完整的托管API,用于处理所有Office应用程序。

使用VSTO进行了大量的开发工作,通过论坛等进行判断。以下是使用LINQ等处理VSTO的辅助API:

VSTO Power Tools

答案 9 :(得分:0)

约翰,

这取决于环境。我们的应用程序几乎完全一样。直到最近我们才使用Interop。只要不留下COM组件,就不会太难使用。

不幸的是,缺点是Office 2007不支持任何类型的服务器自动化(对操作系统没有讨厌的黑客攻击),因此如果您在非UI环境/自动化任务中运行,那么您将无法使用Interop。

你可以使用像ADO这样的东西,我相信它没有相同的细胞概念,所以它不能用于我们需要的东西。

或者,有一些好的图书馆,请查看我的review。 FlexCel是我们购买的优先选择。便宜,快速且易于使用。

答案 10 :(得分:0)

实际上,我会把它恰恰相反......所以Office仍然没有.Net功能?如果能够在.Net中构建宏而不是坚持使用VBA,那将是很好的。

我知道我可以从Visual Studio中的Office扩展性项目中获得相同的功能,但我正在谈论的事情本身对Office本身更为“原生”。对于某些情况,做一个可扩展性项目是一个很大的过度杀伤。

答案 11 :(得分:0)

尝试使用http://www.codeplex.com/xlslinq

以下示例按工作表的名称查找工作表。

using(XlsWorkbook book = new XlsWorkbook("TestData\\100.xls")) {

    var sheets = from s in book.Worksheets
                 where s.Name == "100"
                 select s;

    foreach(var sheet in sheets) Console.WriteLine(sheet.Name);
}

答案 12 :(得分:0)

Office的界面并不难以使用。这里的小Excel示例(如下) - 打开工作表,使用RegExp解析整个事物寻找特定的“命中”:

    internal void OpenSearchAndReplace(string path, Logger log)
    {
        object nullobj = System.Reflection.Missing.Value;
        ConfigurationManager conf = new ConfigurationManager();

        try
        {
            if (_excelApp == null)
                _excelApp = new Excel.Application();

            Excel.Workbook book = _excelApp.Workbooks.Open(path, nullobj, nullobj, nullobj, nullobj, nullobj, nullobj,
                                                           nullobj, nullobj, nullobj, nullobj,
                                                           nullobj, nullobj, nullobj, nullobj);
            Excel.Worksheet worksheet;
            if( book.Worksheets.Count > 1 )
                worksheet = (Excel.Worksheet)book.Worksheets.get_Item("Sheet1");
            else
                worksheet = (Excel.Worksheet)book.ActiveSheet;

            Excel.Range range = worksheet.UsedRange;

            object[,] values = (object[,])range.Value2;

            for (int row = 1; row <= values.GetUpperBound(0); ++row)
            {
                for (int col = 1; col <= values.GetUpperBound(1); ++col)
                {
                    string value = Convert.ToString(values[row, col]);
                    if (Regex.IsMatch(value, @conf.GetFullyQualifiedRegExp()))
                    {
                        range.Cells.set_Item(row, col, conf.GetReplacementText());
                    }
                }
            }
            book.Save();
            Marshal.ReleaseComObject(worksheet );

            log.LogExcelFile( "File " + path + " has been processed\n" );
        }
        catch (Exception ex)
        {...}

但是请 - 如果你不想让很多物品挂在地上,请记得强制使用Garbagecollector :):

            // Force the garbagecollector to kill objects. 
            // Waiting for it to finish
            GC.Collect();
            GC.WaitForPendingFinalizers();