背景:
    在ATBS项目中,需要操作EXCEL 文档,本以为是OBA的应用,但其实不然。OBA是在EXCEL中嵌入.net应用插件,而我们则是需要在SCSF中操作EXCEL。
我大致调查了一下,主要发现3种方式。
    1:使用Microsoft.Office.Interop.Excel,调用EXCEL COM组件,操作EXCEL文件
    2:使用OleDb 操作EXCEL数据源,进而利用ADO.net。
    3:使用OPEN XML,访问EXCEL zip文件并使用DOM。
实现:
    1:使用.net 调用 com
////////////////////////
private static Microsoft.Office.Interop.Excel.Application xApp;
..............


            if (xApp == null)
                xApp = new Microsoft.Office.Interop.Excel.ApplicationClass();

            Microsoft.Office.Interop.Excel.Workbook xBook = null;
            xApp.Visible = false;
            try
            {

                xBook = xApp.Workbooks._Open(@"c:\待发工资.xlsx", 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 xSheet = (Microsoft.Office.Interop.Excel.Worksheet)xBook.Sheets[1];
                //Excel.Worksheet xSheet=(Excel.Worksheet)xApp.ActiveSheet;

                //Microsoft.Office.Interop.Excel.Range rng1 = xSheet.get_Range("A1", Type.Missing);
                Microsoft.Office.Interop.Excel.Range cell = (Microsoft.Office.Interop.Excel.Range)xSheet.Cells[2, 1];
                string str = "";
                for (int i = 2; cell.Value2 != null; i++)
                {
                    str += cell.Value2.ToString() + ".";
                    cell = (Microsoft.Office.Interop.Excel.Range)xSheet.Cells[2, i];
                }

                MessageBox.Show(str);
                xBook.Close(Microsoft.Office.Interop.Excel.XlSaveAction.xlDoNotSaveChanges, @"c:\待发工资.xlsx", Missing.Value);

                xApp.Quit();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }
///////////////////////
    2: 使用oleDB(VSTS 2008 + EXCEL 2007)
//////////////////////


            OleDbConnection objConn = null;

            DataSet data = new DataSet();
            try
            {
                string strConn = @"Provider=Microsoft.ACE.OleDb.12.0;Data Source=c:\待发工资.xlsx;Extended Properties='Excel 12.0;HDR=YES'";//IMEX=1为只读
                //"Provider=Microsoft.Jet.OleDb.4.0;data source=c:\\待发工资.xlsx;Extended Properties=""Excel 12.0;HDR=YES;IMEX=1""";
                objConn = new OleDbConnection(strConn);
                objConn.Open();
                //System .Data . DataTable schemaTable = objConn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null);
                //int SheetIndex = 0;

                //string tableName = schemaTable.Rows[SheetIndex][2].ToString().Trim();

                string strSql = "Select   *   From   [Sheet1$]";
                OleDbCommand objCmd = new OleDbCommand(strSql, objConn);
                OleDbDataAdapter sqlada = new OleDbDataAdapter();
                sqlada.SelectCommand = objCmd;
                sqlada.Fill(data);
                string str = "";
                for (int i = 0; i < data.Tables[0].Rows[0].ItemArray.Length; i++)
                {
                    str += data.Tables[0].Rows[0].ItemArray[i].ToString() + ".";
                }

                MessageBox.Show(str);

                objConn.Close();
            }
            catch (Exception ex)
            {
                objConn.Close();
                Console.WriteLine(ex.Message.ToString());
            }


//////////////////////
    3:使用OPEN XML (比较复杂阿)
//////////////////////


        private const string documentRelationshipType =
              "http://schemas.openxmlformats.org/officeDocument/" +
              "2006/relationships/officeDocument";
        private const string worksheetSchema =
          "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
        private const string sharedStringsRelationshipType =
          "http://schemas.openxmlformats.org/officeDocument/" +
          "2006/relationships/sharedStrings";
        private const string sharedStringSchema =
          "http://schemas.openxmlformats.org/spreadsheetml/2006/main";

        public  static Package xlPackage;

        private static Package OpenReadExcel(string fileName)
        {
            if (xlPackage == null)
                xlPackage = Package.Open(fileName, FileMode.Open, FileAccess.Read);
            return xlPackage;
        }
        private static Package OpenWriteExcel(string fileName)
        {
            if (xlPackage == null)
                xlPackage = Package.Open(fileName, FileMode.Open, FileAccess.ReadWrite);
            return xlPackage;
        }


//////////////////////


        public static string XLGetCellValue(string fileName, string sheetName, string addressName)
        {
            //  Return the value of the specified cell.
            string cellValue = null;

            //  Retrieve the stream containing the requested
            //  worksheet's info:
            using (xlPackage = OpenReadExcel(fileName))
            {
                PackagePart documentPart = null;
                Uri documentUri = null;

                //  Get the main document part (workbook.xml).
                foreach (System.IO.Packaging.PackageRelationship relationship in
                  xlPackage.GetRelationshipsByType(documentRelationshipType))
                {
                    //  There should only be one document part in the package.
                    documentUri = PackUriHelper.ResolvePartUri(
                      new Uri("/", UriKind.Relative), relationship.TargetUri);
                    documentPart = xlPackage.GetPart(documentUri);
                    //  There should only be one instance,
                    //  but get out no matter what.
                    break;
                }

                if (documentPart != null)
                {
                    // Load the contents of the workbook.
                    XmlDocument doc = new XmlDocument();
                    doc.Load(documentPart.GetStream());

                    //  Create a namespace manager, so you can search.
                    //  Add a prefix (d) for the default namespace.
                    NameTable nt = new NameTable();
                    XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
                    nsManager.AddNamespace("d", worksheetSchema);
                    nsManager.AddNamespace("s", sharedStringSchema);
                    string searchString = string.Format("//d:sheet[@name='{0}']", sheetName);
                    XmlNode sheetNode = doc.SelectSingleNode(searchString, nsManager);
                    if (sheetNode != null)
                    {
                        //  Get the relId attribute:
                        XmlAttribute relationAttribute =
                          sheetNode.Attributes["r:id"];
                        if (relationAttribute != null)
                        {
                            string relId = relationAttribute.Value;

                            //  First, get the relation between the
                            // document and the sheet.
                            PackageRelationship sheetRelation =
                              documentPart.GetRelationship(relId);
                            Uri sheetUri = PackUriHelper.ResolvePartUri(
                              documentUri, sheetRelation.TargetUri);
                            PackagePart sheetPart = xlPackage.GetPart(sheetUri);

                            //  Load the contents of the workbook.
                            XmlDocument sheetDoc = new XmlDocument(nt);
                            sheetDoc.Load(sheetPart.GetStream());

                            // Next code block goes here.
                            XmlNode cellNode = sheetDoc.SelectSingleNode(string.Format("//d:sheetData/d:row/d:c[@r='{0}']", addressName), nsManager);
                            if (cellNode != null)
                            {
                                //  Retrieve the value. The value may be stored within
                                //  this element. If the "t" attribute contains "s", then
                                //  the cell contains a shared string, and you must look
                                //  up the value individually.
                                XmlAttribute typeAttr = cellNode.Attributes["t"];
                                string cellType = string.Empty;
                                if (typeAttr != null)
                                {
                                    cellType = typeAttr.Value;
                                }

                                XmlNode valueNode = cellNode.SelectSingleNode("d:v", nsManager);
                                if (valueNode != null)
                                {
                                    cellValue = valueNode.InnerText;
                                }
                                //  Check the cell type. At this point, this code only checks
                                //  for booleans and strings individually.
                                if (cellType == "b")
                                {
                                    if (cellValue == "1")
                                    {
                                        cellValue = "TRUE";
                                    }
                                    else
                                    {
                                        cellValue = "FALSE";
                                    }
                                }
                                else if (cellType == "s")
                                {
                                    //  Go retrieve the actual string from the associated string file.
                                    foreach (System.IO.Packaging.PackageRelationship
                                      stringRelationship in
                                      documentPart.GetRelationshipsByType(sharedStringsRelationshipType))
                                    {
                                        //  There should only be one shared string reference,
                                        // so you exit this loop immediately.
                                        Uri sharedStringsUri = PackUriHelper.ResolvePartUri(
                                          documentUri, stringRelationship.TargetUri);
                                        PackagePart stringPart = xlPackage.GetPart(sharedStringsUri);
                                        if (stringPart != null)
                                        {
                                            //  Load the contents of the shared strings.
                                            XmlDocument stringDoc = new XmlDocument(nt);
                                            stringDoc.Load(stringPart.GetStream());

                                            //  Add the string schema to the namespace manager:
                                            nsManager.AddNamespace("s", sharedStringSchema);

                                            int requestedString = Convert.ToInt32(cellValue);
                                            string strSearch = string.Format(
                                              "//s:sst/s:si[{0}]", requestedString + 1);
                                            XmlNode stringNode =
                                              stringDoc.SelectSingleNode(strSearch, nsManager);
                                            if (stringNode != null)
                                            {
                                                cellValue = stringNode.InnerText;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    return cellValue;
                }
            }
            return "";
        }


/////////////////////


        public static bool XLInsertNumberIntoCell(string fileName, string sheetName, string addressName, string  value)
        {


            //  Retrieve the stream containing the requested
            //  worksheet's info:
            PackagePart documentPart = null;
            Uri documentUri = null;
            bool returnValue = false;
            XmlDocument xDoc = null;
            XmlDocument doc = null;
            PackagePart sheetPart = null;

            using (xlPackage = OpenWriteExcel(fileName))
            {
                //  Get the main document part (workbook.xml).
                foreach (System.IO.Packaging.PackageRelationship relationship
                  in xlPackage.GetRelationshipsByType(documentRelationshipType))
                {
                    //  There should only be one document part in the package.
                    documentUri = PackUriHelper.ResolvePartUri(new Uri("/",
                      UriKind.Relative), relationship.TargetUri);
                    documentPart = xlPackage.GetPart(documentUri);

                    //  There should only be one instance,
                    // but get out no matter what.
                    break;
                }

                // Code removed here.
                if (documentPart != null)
                {
                    // Load the contents of the workbook.
                    doc = new XmlDocument();
                    doc.Load(documentPart.GetStream());

                    // Create a NamespaceManager to handle the default namespace,
                    // and create a prefix for the default namespace:
                    XmlNamespaceManager nsManager =
                      new XmlNamespaceManager(doc.NameTable);
                    nsManager.AddNamespace("d", doc.DocumentElement.NamespaceURI);

                    // Code removed here
                    string searchString =
                      string.Format("//d:sheet[@name='{0}']", sheetName);
                    XmlNode sheetNode = doc.SelectSingleNode(searchString, nsManager);
                    if (sheetNode != null)
                    {
                        //  Get the relId attribute:
                        XmlAttribute relationAttribute = sheetNode.Attributes["r:id"];
                        if (relationAttribute != null)
                        {
                            string relId = relationAttribute.Value;

                            //  First, get the relation between the document and the sheet.
                            PackageRelationship sheetRelation =
                              documentPart.GetRelationship(relId);
                            Uri sheetUri = PackUriHelper.
                              ResolvePartUri(documentUri, sheetRelation.TargetUri);
                            sheetPart = xlPackage.GetPart(sheetUri);

                            //  Load the contents of the sheet into an XML document.
                            xDoc = new XmlDocument();
                            xDoc.Load(sheetPart.GetStream());

                            // Code removed here.
                            //  Use regular expressions to get the row number.
                            //  If the parameter wasn't well formed, this code
                            //  will fail:
                            System.Text.RegularExpressions.Regex r =
                              new System.Text.RegularExpressions.Regex(@"^(?<col>\D+)(?<row>\d+)");
                            string rowNumber = r.Match(addressName).Result("${row}");

                            //  Search for the existing cell:
                            XmlNode cellnode = xDoc.SelectSingleNode(
                              string.Format("//d:sheetData/d:row/d:c[@r='{0}']", addressName),
                              nsManager);
                            if (cellnode == null)
                            {
                                // Code removed here.
                                XmlElement cellElement = xDoc.CreateElement("c", worksheetSchema);
                                cellElement.Attributes.Append(xDoc.CreateAttribute("r"));
                                cellElement.Attributes["r"].Value = addressName;

                                XmlElement valueElement = xDoc.CreateElement("v", worksheetSchema);
                                valueElement.InnerText = value;
                                cellElement.AppendChild(valueElement);

                                //  Default style is "0"
                                cellElement.Attributes.Append(xDoc.CreateAttribute("s"));
                                cellElement.Attributes["s"].Value = "0";

                                XmlNode rowNode = xDoc.SelectSingleNode(string.Format(
                                  "//d:sheetData/d:row[@r='{0}']", rowNumber), nsManager);
                                if (rowNode == null)
                                {
                                    // Code removed here…
                                    //  Didn't find the row, either. Just add a new row element:
                                    XmlNode sheetDataNode = xDoc.SelectSingleNode("//d:sheetData", nsManager);
                                    if (sheetDataNode != null)
                                    {
                                        XmlElement rowElement = xDoc.CreateElement("row", worksheetSchema);
                                        rowElement.Attributes.Append(xDoc.CreateAttribute("r"));
                                        rowElement.Attributes["r"].Value = rowNumber;
                                        rowElement.AppendChild(cellElement);
                                        sheetDataNode.AppendChild(rowElement);
                                        returnValue = true;
                                    }
                                }
                                else
                                {
                                    // Code removed here…
                                    XmlAttribute styleAttr =
                                  ((XmlAttribute)(rowNode.Attributes.GetNamedItem("s")));
                                    if (styleAttr != null)
                                    {
                                        //  You know cellElement has an "s" attribute -- you
                                        //  added it yourself.
                                        cellElement.Attributes["s"].Value = styleAttr.Value;
                                    }

                                    // You must insert the new cell at the correct location.
                                    // Loop through the children, looking for the first cell that is
                                    // beyond the cell you're trying to insert. Insert before that cell.
                                    XmlNode biggerNode = null;
                                    XmlNodeList cellNodes = rowNode.SelectNodes("./d:c", nsManager);
                                    if (cellNodes != null)
                                    {
                                        foreach (XmlNode node in cellNodes)
                                        {
                                            if (String.Compare(node.Attributes["r"].Value, addressName) > 0)
                                            {
                                                biggerNode = node;
                                                break;
                                            }
                                        }
                                    }
                                    if (biggerNode == null)
                                    {
                                        rowNode.AppendChild(cellElement);
                                    }
                                    else
                                    {
                                        rowNode.InsertBefore(cellElement, biggerNode);
                                    }
                                    returnValue = true;
                                }
                            }
                            else
                            {
                                // Code removed here.
                                cellnode.Attributes.RemoveNamedItem("t");
                                XmlNode valueNode = cellnode.SelectSingleNode("d:v", nsManager);
                                if (valueNode == null)
                                {
                                    //  Cell with deleted value. Add a value element now.
                                    valueNode = xDoc.CreateElement("v", worksheetSchema);
                                    cellnode.AppendChild(valueNode);
                                }
                                valueNode.InnerText = value.ToString();
                                returnValue = true;
                            }
                        }
                    }
                    //  Save the XML back to its part.
                    xDoc.Save(sheetPart.GetStream(FileMode.Create, FileAccess.Write));
                   
                }
            }
            return returnValue;
        }


/////////////////////
总结:
        本来比较倾向于OPEN XML,但是在没想到,实现代码那么复杂,(但最后我还是使用了)毕竟是比较新的技术,也很可能使未来的方向。
        使用com来操作,代码并不复杂,而且使用"A3""E5"的方式定位和一般人的思路比较接近,其实也很不错。但毕竟在.net中,com interop性能上可能会被别人怀疑,另外,多用户同时操作一个文档时,比较难于管理(但一般应用也不是主要问题)。
        使用oleDB在性能上是不错的,使用ADO.net也比较利于和其他数据访问层集成,其实如果是大量数据的读取,这应该是最好的选择(个人意见)。
后记:
        第一天写技术日记。希望以后可以不断总结:)

posted on 2008-05-29 23:05  张峻  阅读(819)  评论(3)    收藏  举报