首页 > 解决方案 > 如何知道流是 xlsx 或 xls 或 csv?

问题描述

我知道文件扩展名可以知道它,例如:

void Main()
{
    Console.WriteLine(GetExcelType("xxx.xls")); // Xls
    Console.WriteLine(GetExcelType("xxx.xlsx")); // Xlsx
    Console.WriteLine(GetExcelType("xxx.csv")); // csv
}

// You can define other methods, fields, classes and namespaces here
internal enum ExcelType
{
    Xlsx,Xls,Csv
}

internal ExcelType GetExcelType(string path)
{
    var e = Path.GetExtension(path).ToLowerInvariant();
    switch (Path.GetExtension(path).ToLowerInvariant())
    {
        case ".csv":
            return ExcelType.Csv;
        case ".xlsx":
            return ExcelType.Xlsx;
        case ".xls":
            return ExcelType.Xls;
        default:
            throw new InvalidOperationException("Only allow file extension xlsx,xls,csv");
    } 
}

但如果输入是 Stream,它没有文件扩展名要检查。

标签: .netexcel

解决方案


您可以读取流的几个字节并猜测格式。

var buffer = new byte[512];
stream.Read(buffer, 0, buffer.Length);
var magic = BitConverter.ToUInt32(buffer, 0);
switch (magic)
{
  // Old office format (can be any office file)
  case 0xE011CFD0: return ExcelType.Xls;
  // New office format (can be any ZIP archive)
  case 0x04034B50: return ExcelType.Xlsx;
}
// Text file (the bigger the buffer, the more probability)
// Won't work for UTF-16 encoding, but it's rare
if (buffer.All(b => b >= ' ' || b == '\n' || b == '\r' || b == '\t')) return ExcelType.Csv;
throw new InvalidOperationException();

当然,这只是一个猜测,并不能保证流确实是预期的格式,但文件扩展名也不能提供任何保证。确保输入格式正确的唯一方法是完全解析它并处理可能发生的任何异常。但是这个猜测足以选择尝试哪个解析器。

这也会消耗流中的字节,因此如果要在检查后使用流,则需要考虑这一点。如果stream.CanSeek == true,你可以只设置stream.Position = 0。如果不是,您可以将原始流复制到MemoryStream可以查找的流中(但这可能需要很多时间);或实现您自己的流,它将buffer在读取原始流之前提供内容;或者只是确保在读取流的其余部分之前使用缓冲区。


推荐阅读