29 private readonly
string filePath;
30 private readonly Stream inputStream;
31 private readonly ReaderOptions readerOptions;
32 private MemoryStream memoryStream;
48 public XlsxReader(
string path, ReaderOptions options =
null)
51 readerOptions = options;
59 public XlsxReader(Stream stream, ReaderOptions options =
null)
62 readerOptions = options;
78 using (memoryStream =
new MemoryStream())
80 ReadInternal().GetAwaiter().GetResult();
83 catch (NotSupportedContentException)
93 throw new IOException(
"There was an error while reading an XLSX file. Please see the inner exception:", ex);
108 using (memoryStream =
new MemoryStream())
110 await ReadInternal();
119 throw new IOException(
"There was an error while reading an XLSX file. Please see the inner exception:", ex);
127 private async Task ReadInternal()
130 if (inputStream ==
null && !
string.IsNullOrEmpty(filePath))
132 using (FileStream fs =
new FileStream(filePath, FileMode.Open))
134 await fs.CopyToAsync(memoryStream);
137 else if (inputStream !=
null)
141 await inputStream.CopyToAsync(memoryStream);
146 throw new IOException(
"No valid stream or file path was provided to open");
149 memoryStream.Position = 0;
150 zf =
new ZipArchive(memoryStream, ZipArchiveMode.Read);
155 }).ConfigureAwait(
false);
162 private void ReadZip(ZipArchive zf)
167 importInProgress =
true
169 HandleQueuePlugIns(PlugInUUID.ReaderPrependingQueue, zf, ref wb);
171 ISharedStringReader sharedStringsReader = PlugInLoader.GetPlugIn<ISharedStringReader>(PlugInUUID.SharedStringsReader,
new SharedStringsReader());
172 ms = GetEntryStream(
"xl/sharedStrings.xml", zf);
173 if (ms !=
null && ms.Length > 0)
175 sharedStringsReader.Init(ms, wb, readerOptions, ReaderPlugInHandler.HandleInlineQueuePlugins);
176 sharedStringsReader.Execute();
178 Dictionary<int, string> themeStreamNames = GetSequentialStreamNames(
"xl/theme/theme", zf);
179 if (themeStreamNames.Count > 0)
184 foreach (KeyValuePair<int, string> streamName
in themeStreamNames)
186 IPluginBaseReader themeReader = PlugInLoader.GetPlugIn<IPluginBaseReader>(PlugInUUID.ThemeReader,
new ThemeReader());
187 ms = GetEntryStream(streamName.Value, zf);
188 themeReader.Init(ms, wb, readerOptions, ReaderPlugInHandler.HandleInlineQueuePlugins);
189 themeReader.Execute();
193 StyleRepository.Instance.ImportInProgress =
true;
194 IPluginBaseReader styleReader = PlugInLoader.GetPlugIn<IPluginBaseReader>(PlugInUUID.StyleReader,
new StyleReader());
195 ms = GetEntryStream(
"xl/styles.xml", zf);
196 styleReader.Init(ms, wb, readerOptions, ReaderPlugInHandler.HandleInlineQueuePlugins);
197 styleReader.Execute();
198 StyleRepository.Instance.ImportInProgress =
false;
200 ms = GetEntryStream(
"xl/workbook.xml", zf);
201 IPluginBaseReader workbookReader = PlugInLoader.GetPlugIn<IPluginBaseReader>(PlugInUUID.WorkbookReader,
new WorkbookReader());
202 workbookReader.Init(ms, wb, readerOptions, ReaderPlugInHandler.HandleInlineQueuePlugins);
203 workbookReader.Execute();
205 ms = GetEntryStream(
"docProps/app.xml", zf);
206 if (ms !=
null && ms.Length > 0)
208 IPluginBaseReader metadataAppReader = PlugInLoader.GetPlugIn<IPluginBaseReader>(PlugInUUID.MetadataAppReader,
new MetadataAppReader());
209 metadataAppReader.Init(ms, wb, readerOptions, ReaderPlugInHandler.HandleInlineQueuePlugins);
210 metadataAppReader.Execute();
212 ms = GetEntryStream(
"docProps/core.xml", zf);
213 if (ms !=
null && ms.Length > 0)
215 IPluginBaseReader metadataCoreReader = PlugInLoader.GetPlugIn<IPluginBaseReader>(PlugInUUID.MetadataCoreReader,
new MetadataCoreReader());
216 metadataCoreReader.Init(ms, wb, readerOptions, ReaderPlugInHandler.HandleInlineQueuePlugins);
217 metadataCoreReader.Execute();
220 IPluginBaseReader relationships = PlugInLoader.GetPlugIn<IPluginBaseReader>(PlugInUUID.RelationshipReader,
new RelationshipReader());
221 ms = GetEntryStream(
"xl/_rels/workbook.xml.rels", zf);
222 relationships.Init(ms, wb, readerOptions, ReaderPlugInHandler.HandleInlineQueuePlugins);
223 relationships.Execute();
225 IWorksheetReader worksheetReader = PlugInLoader.GetPlugIn<IWorksheetReader>(PlugInUUID.WorksheetReader,
new WorksheetReader());
226 worksheetReader.SharedStrings = sharedStringsReader.SharedStrings;
227 List<WorksheetDefinition> workshetDefinitions = wb.AuxiliaryData.GetDataList<WorksheetDefinition>(PlugInUUID.WorkbookReader, PlugInUUID.WorksheetDefinitionEntity);
228 List<Relationship> relationshipDefinitions = wb.AuxiliaryData.GetDataList<Relationship>(PlugInUUID.RelationshipReader, PlugInUUID.RelationshipEntity);
229 foreach (WorksheetDefinition definition
in workshetDefinitions)
231 Relationship relationship = relationshipDefinitions.SingleOrDefault(r => r.RID == definition.RelId);
232 if (relationship ==
null)
234 throw new IOException(
"There was an error while reading an XLSX file. The relationship target of the worksheet with the RelID " + definition.RelId +
" was not found");
236 ms = GetEntryStream(relationship.Target, zf);
237 worksheetReader.Init(ms, wb, readerOptions, ReaderPlugInHandler.HandleInlineQueuePlugins);
238 worksheetReader.CurrentWorksheetID = definition.SheetID;
239 worksheetReader.Execute();
241 if (wb.Worksheets.Count == 0)
243 throw new IOException(
"No worksheet was found in the workbook");
245 HandleQueuePlugIns(PlugInUUID.ReaderAppendingQueue, zf, ref wb);
246 wb.importInProgress =
false;
247 wb.AuxiliaryData.ClearTemporaryData();
257 private static MemoryStream GetEntryStream(
string name, ZipArchive archive)
259 MemoryStream stream =
null;
260 for (
int i = 0; i < archive.Entries.Count; i++)
262 if (archive.Entries[i].FullName == name)
264 MemoryStream ms =
new MemoryStream();
265 archive.Entries[i].Open().CopyTo(ms);
280 private static Dictionary<int, string> GetSequentialStreamNames(
string namePrefix, ZipArchive archive)
282 Dictionary<int, string> files =
new Dictionary<int, string>();
286 string name = namePrefix + ParserUtils.ToString(index) +
".xml";
287 var ms = GetEntryStream(name, archive);
290 files.Add(index, name);
307 private void HandleQueuePlugIns(
string queueUuid, ZipArchive zf, ref
Workbook workbook)
309 string lastUuid =
null;
310 IPluginQueueReader queueReader;
314 queueReader = PlugInLoader.GetNextQueuePlugIn<IPluginQueueReader>(queueUuid, lastUuid, out currentUuid);
315 MemoryStream ms =
null;
316 if (queueReader !=
null)
318 if (queueReader is IPluginPackageReader)
320 string streamPartName = (queueReader as IPluginPackageReader).StreamEntryName;
321 if (!
string.IsNullOrEmpty(streamPartName))
323 ms = GetEntryStream(streamPartName, zf);
326 lastUuid = currentUuid;
331 queueReader.Init(ms, workbook, this.readerOptions,
null);
332 queueReader.Execute();
333 lastUuid = currentUuid;
340 }
while (queueReader !=
null);
348 this.inputStream?.Dispose();
349 GC.SuppressFinalize(
this);