www.3015.com

当前位置:澳门唯一金莎娱乐 > www.3015.com > www.3015.com还有什么不能做?——细谈在C#中读写

www.3015.com还有什么不能做?——细谈在C#中读写

来源:http://www.savelapetitebande.com 作者:澳门唯一金莎娱乐 时间:2019-10-16 21:05
  1 using System.Collections.Generic;
  2 using System.Data;
  3 using System.Globalization;
  4 using System.IO;
  5 using System.Text;
  6 using System.Xml;
  7 using ICSharpCode.SharpZipLib.Zip;
  8 
  9 namespace XlsxReadWrite
 10 {
 11     internal static class XlsxRW
 12     {
 13         public static void DeleteDirectoryContents(string directory)
 14         {
 15             var info = new DirectoryInfo(directory);
 16 
 17             foreach (var file in info.GetFiles())
 18             {
 19                 file.Delete();
 20             }
 21 
 22             foreach (var dir in info.GetDirectories())
 23             {
 24                 dir.Delete(true);
 25             }
 26         }
 27 
 28         public static void UnzipFile(string zipFileName, string targetDirectory)
 29         {
 30             new FastZip().ExtractZip(zipFileName, targetDirectory, null);
 31         }
 32 
 33         public static void ZipDirectory(string sourceDirectory, string zipFileName)
 34         {
 35             new FastZip().CreateZip(zipFileName, sourceDirectory, true, null);
 36         }
 37 
 38         public static IList<string> ReadStringTable(Stream input)
 39         {
 40             var stringTable = new List<string>();
 41 
 42             using (var reader = XmlReader.Create(input))
 43             {
 44                 for (reader.MoveToContent(); reader.Read(); )
 45                 {
 46                     if (reader.NodeType == XmlNodeType.Element && reader.Name == "t")
 47                     {
 48                         stringTable.Add(reader.ReadElementString());
 49                     }
 50                 }
 51             }
 52 
 53             return stringTable;
 54         }
 55 
 56         public static void ReadWorksheet(Stream input, IList<string> stringTable, DataTable data)
 57         {
 58             using (var reader = XmlReader.Create(input))
 59             {
 60                 DataRow row = null;
 61                 int columnIndex = 0;
 62                 string type;
 63                 int value;
 64 
 65                 for (reader.MoveToContent(); reader.Read(); )
 66                     if (reader.NodeType == XmlNodeType.Element)
 67                         switch (reader.Name)
 68                         {
 69                             case "row":
 70                                 row = data.NewRow();
 71                                 data.Rows.Add(row);
 72 
 73                                 columnIndex = 0;
 74 
 75                                 break;
 76 
 77                             case "c":
 78                                 type = reader.GetAttribute("t");
 79                                 reader.Read();
 80                                 value = int.Parse(reader.ReadElementString(), CultureInfo.InvariantCulture);
 81 
 82                                 if (type == "s")
 83                                     row[columnIndex] = stringTable[value];
 84                                 else
 85                                     row[columnIndex] = value;
 86 
 87                                 columnIndex++;
 88 
 89                                 break;
 90                         }
 91             }
 92         }
 93 
 94         public static IList<string> CreateStringTables(DataTable data, out IDictionary<string, int> lookupTable)
 95         {
 96             var stringTable = new List<string>();
 97             lookupTable = new Dictionary<string, int>();
 98 
 99             foreach (DataRow row in data.Rows)
100                 foreach (DataColumn column in data.Columns)
101                     if (column.DataType == typeof(string))
102                     {
103                         var value = (string)row[column];
104 
105                         if (!lookupTable.ContainsKey(value))
106                         {
107                             lookupTable.Add(value, stringTable.Count);
108                             stringTable.Add(value);
109                         }
110                     }
111 
112             return stringTable;
113         }
114 
115         public static void WriteStringTable(Stream output, IList<string> stringTable)
116         {
117             using (var writer = XmlWriter.Create(output))
118             {
119                 writer.WriteStartDocument(true);
120 
121                 writer.WriteStartElement("sst", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
122                 writer.WriteAttributeString("count", stringTable.Count.ToString(CultureInfo.InvariantCulture));
123                 writer.WriteAttributeString("uniqueCount", stringTable.Count.ToString(CultureInfo.InvariantCulture));
124 
125                 foreach (var str in stringTable)
126                 {
127                     writer.WriteStartElement("si");
128                     writer.WriteElementString("t", str);
129                     writer.WriteEndElement();
130                 }
131 
132                 writer.WriteEndElement();
133             }
134         }
135 
136         public static string RowColumnToPosition(int row, int column)
137         {
138             return ColumnIndexToName(column) + RowIndexToName(row);
139         }
140 
141         public static string ColumnIndexToName(int columnIndex)
142         {
143             var second = (char)(((int)'A') + columnIndex % 26);
144 
145             columnIndex /= 26;
146 
147             if (columnIndex == 0)
148                 return second.ToString();
149             else
150                 return ((char)(((int)'A') - 1 + columnIndex)).ToString() + second.ToString();
151         }
152 
153         public static string RowIndexToName(int rowIndex)
154         {
155             return (rowIndex + 1).ToString(CultureInfo.InvariantCulture);
156         }
157 
158         public static void WriteWorksheet(Stream output, DataTable data, IDictionary<string, int> lookupTable)
159         {
160             using (XmlTextWriter writer = new XmlTextWriter(output, Encoding.UTF8))
161             {
162                 writer.WriteStartDocument(true);
163 
164                 writer.WriteStartElement("worksheet");
165                 writer.WriteAttributeString("xmlns", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
166                 writer.WriteAttributeString("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
167 
168                 writer.WriteStartElement("dimension");
169                 var lastCell = RowColumnToPosition(data.Rows.Count - 1, data.Columns.Count - 1);
170                 writer.WriteAttributeString("ref", "A1:" + lastCell);
171                 writer.WriteEndElement();
172 
173                 writer.WriteStartElement("sheetViews");
174                 writer.WriteStartElement("sheetView");
175                 writer.WriteAttributeString("tabSelected", "1");
176                 writer.WriteAttributeString("workbookViewId", "0");
177                 writer.WriteEndElement();
178                 writer.WriteEndElement();
179 
180                 writer.WriteStartElement("sheetFormatPr");
181                 writer.WriteAttributeString("defaultRowHeight", "15");
182                 writer.WriteEndElement();
183 
184                 writer.WriteStartElement("sheetData");
185                 WriteWorksheetData(writer, data, lookupTable);
186                 writer.WriteEndElement();
187 
188                 writer.WriteStartElement("pageMargins");
189                 writer.WriteAttributeString("left", "0.7");
190                 writer.WriteAttributeString("right", "0.7");
191                 writer.WriteAttributeString("top", "0.75");
192                 writer.WriteAttributeString("bottom", "0.75");
193                 writer.WriteAttributeString("header", "0.3");
194                 writer.WriteAttributeString("footer", "0.3");
195                 writer.WriteEndElement();
196 
197                 writer.WriteEndElement();
198             }
199         }
200 
201         public static void WriteWorksheetData(XmlTextWriter writer, DataTable data, IDictionary<string, int> lookupTable)
202         {
203             var rowsCount = data.Rows.Count;
204             var columnsCount = data.Columns.Count;
205             string relPos;
206 
207             for (int row = 0; row < rowsCount; row++)
208             {
209                 writer.WriteStartElement("row");
210                 relPos = RowIndexToName(row);
211                 writer.WriteAttributeString("r", relPos);
212                 writer.WriteAttributeString("spans", "1:" + columnsCount.ToString(CultureInfo.InvariantCulture));
213 
214                 for (int column = 0; column < columnsCount; column++)
215                 {
216                     object value = data.Rows[row][column];
217 
218                     writer.WriteStartElement("c");
219                     relPos = RowColumnToPosition(row, column);
220                     writer.WriteAttributeString("r", relPos);
221 
222                     var str = value as string;
223                     if (str != null)
224                     {
225                         writer.WriteAttributeString("t", "s");
226                         value = lookupTable[str];
227                     }
228 
229                     writer.WriteElementString("v", value.ToString());
230 
231                     writer.WriteEndElement();
232                 }
233 
234                 writer.WriteEndElement();
235             }
236         }
237     }
238 }

  1. 成立或复制全数必得的parts。通过标准XML类库来成立这个根据XML数据格式的parts,只怕从此外package中复制那个parts,也许应用另外另外你所通晓的艺术。

  在其次篇小说中自个儿曾经向我们详细介绍了Excel 2006事后版本的文书的OpenXML结构。所谓的OpenXML结构从本质上来说其实正是贰个ZIP压缩包,全体基于OpenXML数据结构的公文都一点差别也没有。这样文件的结构是开放的,你无需依附任何第三方的零件就能够读取文件中的数据,或然修改文件的剧情。而且全数财富文件诸如图片和多媒体文件都以被编写翻译成八个稳住的格式寄放在调整和收缩包中,并不是观念样式上的流。别的,以压缩包的格局累积数据也使得文件所占用的上空越来越小。

 1 private void ReadInput(object sender, RoutedEventArgs e)
 2 {
 3     // Get the input file name from the text box.
 4     var fileName = this.inputTextBox.Text;
 5 
 6     // Delete contents of the temporary directory.
 7     XlsxRW.DeleteDirectoryContents(tempDir);
 8 
 9     // Unzip input XLSX file to the temporary directory.
10     XlsxRW.UnzipFile(fileName, tempDir);
11 
12     IList<string> stringTable;
13     // Open XML file with table of all unique strings used in the workbook..
14     using (var stream = new FileStream(Path.Combine(tempDir, @"xlsharedStrings.xml"),
15         FileMode.Open, FileAccess.Read))
16         // ..and call helper method that parses that XML and returns an array of strings.
17         stringTable = XlsxRW.ReadStringTable(stream);
18 
19     // Open XML file with worksheet data..
20     using (var stream = new FileStream(Path.Combine(tempDir, @"xlworksheetssheet1.xml"),
21         FileMode.Open, FileAccess.Read))
22         // ..and call helper method that parses that XML and fills DataTable with values.
23         XlsxRW.ReadWorksheet(stream, stringTable, this.data);
24 }
25 
26 private void WriteOutput(object sender, RoutedEventArgs e)
27 {
28     // Get the output file name from the text box.
29     string fileName = this.outputTextBox.Text;
30 
31     // Delete contents of the temporary directory.
32     XlsxRW.DeleteDirectoryContents(tempDir);
33 
34     // Unzip template XLSX file to the temporary directory.
35     XlsxRW.UnzipFile(templateFile, tempDir);
36 
37     // We will need two string tables; a lookup IDictionary<string, int> for fast searching 
38     // an ordinary IList<string> where items are sorted by their index.
39     IDictionary<string, int> lookupTable;
40 
41     // Call helper methods which creates both tables from input data.
42     var stringTable = XlsxRW.CreateStringTables(this.data, out lookupTable);
43 
44     // Create XML file..
45     using (var stream = new FileStream(Path.Combine(tempDir, @"xlsharedStrings.xml"),
46         FileMode.Create))
47         // ..and fill it with unique strings used in the workbook
48         XlsxRW.WriteStringTable(stream, stringTable);
49 
50     // Create XML file..
51     using (var stream = new FileStream(Path.Combine(tempDir, @"xlworksheetssheet1.xml"),
52         FileMode.Create))
53         // ..and fill it with rows and columns of the DataTable.
54         XlsxRW.WriteWorksheet(stream, this.data, lookupTable);
55 
56     // ZIP temporary directory to the XLSX file.
57     XlsxRW.ZipDirectory(tempDir, fileName);
58 
59     // If checkbox is checked, show XLSX file in Microsoft Excel.
60     if (this.openFileCheckBox.IsChecked == true)
61         System.Diagnostics.Process.Start(fileName);
62 }

  3. ZipDirectory()方法应用开源类库中的CreateZip()方法将暂且目录中的内容重新打包成zip压缩文件。

www.3015.com 1

  5. ReadWorksheet()方法会依据钦赐的专门的学问表XML文件(如"xl/worksheets/sheet1.xml")在sharedStrings.xml文件中寻找数据,并将结果存放到叁个DataTable中。

  1. DeleteDirectoryContents()方法用来清空偶尔目录的剧情,该临时目录被用来贮存解压Excel之后的文件。

www.3015.com还有什么不能做?——细谈在C#中读写Excel系列文章之三。www.3015.com还有什么不能做?——细谈在C#中读写Excel系列文章之三。  2. 找到Package中您想要读取的parts。有为数不菲的方法能够扶植您找到那个parts,你能够分析relationship,也得以直接通过path来牢固到某三个文书,但是不太鲜明path在明日是还是不是会有变化。可能还是能够透过part的content type来找到它。

www.3015.com 2

www.3015.com还有什么不能做?——细谈在C#中读写Excel系列文章之三。  2. UnzipFile()方法直接动用了开源类库中的ExtractZip()方法,将Excel文件解压到一时目录。

  在Excel单元格内设置的样式被寄放到sharedStrings.xml文件中后会产生如下这种格局:

  3. 读取part中的内容。如果parts是以XML的款型寄存的,通过专门的学业的XML类库就足以丰裕有利地读取到数据。借使是别的格局,如图片、声音或摄像文件则也得以经过相应的法子来获得到内容。

  借用该类库中的ExtractZip()和CreateZip()方法能够帮忙我们读取或改变(成立)Excel文件。当然这几个类库中的某个代码是选择较早的.NET版本中的语法和对象来编排的,诸如ArratList、Hashtable等,它恐怕不切合在Silverlight工程中动用(帮衬Silverlight的.NET Framework与普通的.NET Framework有不稀有别于何况调换相比较频仍),接下去的篇章中小编会向大家介绍如何在Silverlight工程中应用它。但后天并无妨碍我们在任何项目标工程中采纳。

  援救.NET操作zip压缩包的类库应该还应该有众多,任何七个都足以,因为Excel的OpenXML文件自个儿就是二个业内的zip压缩包。然则地点的法子依旧有三个局限性,那正是需求近些日子目录来存放在解压之后的公文,以至重新包装时所钦赐的源文件。对经常的Windows应用程序或asp.net应用程序来讲那些并不曾什么样困难,只要权力允许,读写一时目录未有别的难题,可是在Silverlight中则有所分化,因为在Silverlight中读写顾客端文件须求比较高的安全等第和验证,这就导致解压文件会有难堪,叁个简练的格局就是一向在文书的流中开展解压和修改,然后再将流打包成zip文件。下一篇小说中我会向我们介绍如何在Silverlight中动用,乃至怎么样定义二个类来达成Excel文件中有些字符串样式的改造。

  这年节点si中的内容就不是仅仅的子节点t了。因而,如何深入分析XML文件要求依赖实情去缅怀,那重大在于你在Excel文件中蕴藏的源委。

<si>
    <r>
      <t xml:space="preserve">  Short-term investments (including securities loaned 
    of </t>
    </r>
    <r>
      <rPr>
        <b/>
        <sz val="8"/>
        <color rgb="FF404040"/>
        <rFont val="Verdana"/>
        <family val="2"/>
      </rPr>
      <t>$9,999</t>
    </r>
    <r>
      <rPr>
        <sz val="8"/>
        <color rgb="FF404040"/>
        <rFont val="Verdana"/>
        <family val="2"/>
      </rPr>
      <t xml:space="preserve"> and $8,888)</t>
    </r>
  </si>

  6. CreateStringTables()和WriteStringsTable()方法用来创制一个sharedStrings.xml文件。

  3. 将全部package压缩成一个zip包,然后将文件的后缀修改成供给的项目(如docx,xlsx,大概pptx等)。只要package中的结构相符需要,修改之后的文书能够向来被张开。当然,该进度能够在一丝一毫未有安装office的机械上到位(举例服务器),然后分发给必要的地点使用。

  另一方面,你也能够创建多少个依据OpenXML的文本(如运用非COM组件的款型创造二个Excel文件),

  提供二个主次集下载吧,源代码大家去地点那么些网站下载。ICSharpCode.ShareZipLib.zip

  全数这一体包蕴packages,parts,content types,以至relationships都被称之为OpenXML文书档案,微软将以此名字为Open Packaging Conventions。

  这个都以它的独到之处。其实,微软在.NET中早已提供了相应的类库来援助我们操作OpenXML文件,就好像自个儿在第二篇小说中向我们介绍的毫无二致,微软把OpenXML压缩包称之为一个Package,在Package中的文件称作Parts,差别的Parts有投机的Content Type。Content Type能够描述任何内容,如application XML,user XML,images,sounds,videos,大概别的二进制内容。各类Part之间通过八个被称之为relationship的part连接起来,那么些part其实也是一种新鲜的XML文件,后缀为".rels",在Package中得以找到它。下图表明了贰个Package中相继Part之间的涉及,

  尽管.NET中提供的Package类能够协理大家特别便利地剖析Excel包,不过也可能有为数不菲的局限性,一时你只可以动用部分主意来和煦读取包中的内容,只怕尝试去修改包中的数据。

  有关Excel OpenXML的内部结构以致部分相比较首要的节点含义在前一篇小说中早就做了有的介绍,除了直接使用.NET类库中的Package类之外,我们当然也得以行使其余的第三方类库或然自个儿编排代码读取包中的内容,这里有一个.NET的开源类库特地用来操作zip压缩文件。

  4. ReadStringTable()方法用来读取xl/sharedStrings.xml文件中节点t的内容。其实应该是直接读取si节点的剧情,应为实际不是持有的si节点都有t子节点。

  思虑一个情况:在Excel的单元格中,选中一部分内容,还是事情节中的某一个数字或某一个单词,然后对它独立设置样式。通过这种艺术你能够将Excel单元格中的某一片段剧情设置为粗体、上标,还足以在单元格内进行换行等。如下图:

  来看一看实际的事例。这里有一个类提供了有个别艺术用来读取和修改Excel文件中的数据:

  1. 将Package作为三个规范的zip文件进行解压。

  7. WriteWorksheet()方法用来成立一个干活表XML文件。

  2. 创办relationships部分。也便是成立一个后缀为".rels"的独特XML文件。

  来探视如何调用:

  你所要做的只是对XML实行操作,仅此而以!

本文由澳门唯一金莎娱乐发布于www.3015.com,转载请注明出处:www.3015.com还有什么不能做?——细谈在C#中读写

关键词: