我已经看过了,但它并没有解决我的问题,https://stackoverflow.com/questions/51079664/c-sharp-error-with-exceldatareader
我尝试构建一个读取XLS文件并将其转换为string[]的方法,但是当我尝试运行它时会出现一个错误: ExcelDataReader.Exceptions.HeaderException:无效文件签名。
我尝试过使用XLSX运行它,并且运行良好。
我所使用的文件以前是起作用的。
请注意。我运行过与以前使用XLS相同的方法,因此我很困惑为什么会发生此错误。(使用ExcelDataReader版本3.6.0)
以下是代码:
private static List<string[]> GetExcelRecords(string path, bool hasHeaders)
{
var records = new List<string[]>();
using (var stream = File.Open(path, FileMode.Open, FileAccess.Read))
{
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
var sheetFile = reader.AsDataSet().Tables[0];
for (int i = 0; i < sheetFile.Rows.Count; i++)
{
var record = sheetFile.Rows[i];
if (hasHeaders)
{
hasHeaders = false;
continue;
}
var row = record.ItemArray.Select(o => o.ToString()).ToArray();
records.Add(row);
}
}
}
return records;
}异常发生在第4行。
我试过使用ExcelReaderFactory.CreateBinaryReader和ExcelReaderFactory.CreateOpenXlmReader
发布于 2022-12-02 21:17:41
这更多是为了好玩(所以是社区wiki),但下面是我写它的方式:
private static IEnumerable<string[]> GetExcelRecords(string path, int headerRowsToSkip = 0)
{
using (var stream = File.Open(path, FileMode.Open, FileAccess.Read))
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
while(headerRowsToSkip-- > 0 && reader.Read()) {} //intentionally empty
while(reader.Read())
{
object[] temp = new object[reader.FieldCount];
reader.GetValues(temp);
yield return temp.Select(o => o.ToString()).ToArray();
}
}
}我对此还不满意,特别是这部分:
object[] temp = new object[reader.FieldCount];
reader.GetValues(temp);
yield return temp.Select(o => o.ToString()).ToArray();问题是,我们在每次迭代中最终得到三个数据副本:读取器中包含的副本、object[]中的副本和string[]中的副本。
还值得一提的是,由于文化/国际化问题,在字符串和日期/数值之间来回转换是我们在计算机中经常做的最慢的事情之一。如果ExcelDataReader尊重表中的类型信息,并给出数字和日期值,那么通常会导致LOT的性能比您意识到的要转换为字符串的性能要高。
我们不能避免一次从读取器中复制数据,所以无论如何我们都需要两个副本。考虑到这一点,我认为这样做可能更好:
object[] temp = new object[reader.FieldCount];
reader.GetValues(temp);
yield return temp;然后,我们还需要更改方法签名。这就让我们返回一组object[]s,它仍然不太理想。
另一种选择更具有转换性:使用泛型和函数式编程概念来创建一个实际的类型化对象,而不仅仅是一个数组:
private static IEnumerable<T> GetExcelRecords<T>(string path, Func<IDataRecord, T> transform, int headerRowsToSkip = 0)
{
using (var stream = File.Open(path, FileMode.Open, FileAccess.Read))
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
while(headerRowsToSkip-- > 0 && reader.Read()) {} //intentionally empty
while(reader.Read())
{
yield return transform(reader);
}
}
}这就把艰苦的工作推到了lambda表达式上。为了解释如何使用它,假设您有一个带有一个标题行和列(按顺序排列)的工作表,用于整数ID、日期、十进制价格、双重数量和字符串描述。您可以这样调用该方法:
var rows = GetExcelRecords("file path", row =>
{
return (row.GetInt32(0), row.GetDateTime(1), row.GetDecimal(2), row.GetDouble(3), row.GetString(4) );
}, 1);它使用ValueTuple来避免声明类,同时仍然保留原始数据类型并避免两个类(2!)为每一行分配数组。由于我们使用的是IEnumerable<>而不是List<>,这也意味着每次只需要在内存中保留一行。
我想我们最终会在一个好地方结束。我用来读取标题行的技巧可能有点太聪明了--依赖于布尔短路排序、操作符优先级的细微性和空置的here循环--但我喜欢这里的对称性。
发布于 2022-12-02 21:28:59
问题似乎是我的笔记本电脑损坏了XLS文件(我不知道为什么),错误不是文件类型造成的,而是我的文件已损坏的事实。
https://stackoverflow.com/questions/74660257
复制相似问题