C#导入EXCEL时读取单元格中的图片(WPS)

起因:最新要做一个excel批量导入商品的功能,但是文本内容好读取,但是图片文件在网上没有找到比较好的解决办法
解决方案1:(不推荐)先导入excel数据,再通过文件夹/压缩包的方式导入图片,但是这样比较麻烦,如果说excel表格后续还需要维护的话,对于做excel表格的同学来说不太友好
解决方案2:解压缩excel文件,可以得到对应的文件夹,如下图所示的内容,其中xl文件夹下存在几个数据文件,可以手动拼接起来,下面着重说一下该如何一步步实现指定单元格的文件读取

1)上传excel文件

定义好接受类,我的类是这样,可以根据自己需要进行修改

/// <summary>
/// 导入产品dto
/// </summary>
public class ImportSoftProductDto:PrimaryKey
{
    /// <summary>
    /// 供应商编号
    /// </summary>
    [ExcelColumnIndex("A")]
    public string SupplierNo { get; set; }
    /// <summary>
    /// 产品编号
    /// </summary>
    [ExcelColumnIndex("B")]
    public string ProductNo { get; set; }
    /// <summary>
    /// 产品名称
    /// </summary>
    [ExcelColumnIndex("C")]
    public string ProductName { get; set; }
    /// <summary>
    /// 主分类
    /// </summary>
    [ExcelColumnIndex("D")]
    public string MainCategory { get; set; }
    /// <summary>
    /// 次分类
    /// </summary>
    [ExcelColumnIndex("E")]
    public string SubCategory { get; set; }
    /// <summary>
    /// 采购单价
    /// </summary>
    [ExcelColumnIndex("F")]
    public decimal PurchasePrice { get; set; }
    /// <summary>
    /// 销售单价
    /// </summary>
    [ExcelColumnIndex("G")]
    public decimal SalesPrice { get; set; }
    /// <summary>
    /// 单位
    /// </summary>
    [ExcelColumnIndex("H")]
    public string Unit { get; set; }
    /// <summary>
    /// 尺寸
    /// </summary>
    [ExcelColumnIndex("I")]
    public string Size { get; set; }
    /// <summary>
    /// 材质报价
    /// </summary>
    [ExcelColumnIndex("J")]
    public string Texture { get; set; }
    /// <summary>
    /// 备注说明
    /// </summary>
    [ExcelColumnIndex("K")]
    public string Explain { get; set; }
    /// <summary>
    /// 图片_DISPIMG函数字符串
    /// </summary>
    [ExcelColumnIndex("L")]
    public string IMG_DISPIMG { get; set; }
    //= DISPIMG("ID_498B62A4F63D447D9F9E1640DAF57A45", 1)
    public string DISPIMG_Id
    {
        get
        {
            if (!string.IsNullOrWhiteSpace(IMG_DISPIMG))
            {
                var split = IMG_DISPIMG.Split('"');
                return split[1];
            }
            else
            {
                return "";
            }
        }
    }
    /// <summary>
    /// 图片原始路径
    /// </summary>
    public string ImgOriginalUrl { get; set; }
    /// <summary>
    /// 图片最终路径
    /// </summary>
    public string ImgFinalUrl { get; set; }
    public string ImgSuffix
    {
        get
        {
            if (!string.IsNullOrWhiteSpace(ImgOriginalUrl))
            {
                return Path.GetExtension(ImgOriginalUrl).ToLower().Replace(".", "");
            }
            else
            {
                return string.Empty;
            }
        }
    }
}


2)读取excel文件内容,这里使用的是MiniExcel,可以在nuget中安装,注意:wps嵌入的图片可以通过string得到如下的字符串=DISPIMG("ID_8C72DF5CE3FA413298278785876E9D65",1),其中,ID_8C72DF5CE3FA413298278785876E9D65是我们需要的东东

var rows = MiniExcel.Query<ImportSoftProductDto>(absoluteUrl, startCell: "A3").ToList();

3)解压缩excel,需要用到命名空间:System.IO.Compression,这里,我是直接以该excel的文件名作为解压文件夹的

var zipFileDirectory = absoluteUrl.Substring(0, absoluteUrl.LastIndexOf("."));
ZipFile.ExtractToDirectory(absoluteUrl, zipFileDirectory);

4)读取cellimages.xml内容,该文件位于xl文件夹下

var cellimagesXML = File.ReadAllText(Path.Combine(zipFileDirectory, "xl/cellimages.xml"));

5)读取cellimages.xml.rels内容

var cellimagesXMLRels = File.ReadAllText(Path.Combine(zipFileDirectory, "xl/_rels/cellimages.xml.rels"));

6)结合2个文件内容和图片资源名称,计算出第二步中ID_8C72DF5CE3FA413298278785876E9D65对应的图片,这里也可以自己解析xml内容,主要是为了获得他们直接的对应关系

var imgList = new List<ImportSoftProductImgDto>();

var nodes_XML = XElement.Parse(cellimagesXML);
foreach (var xNode in nodes_XML.DescendantNodes().OfType<XCData>().ToList())
{
    xNode.Parent.Add(xNode.Value);
    xNode.Remove();
}
var json_XML = JObject.Parse(JsonConvert.SerializeXNode(nodes_XML, Formatting.Indented));
foreach (var item in json_XML["etc:cellImages"]["etc:cellImage"])
{
    var DISPIMG_Id = item["xdr:pic"]["xdr:nvPicPr"]["xdr:cNvPr"]["@name"].ToString();
    var id = item["xdr:pic"]["xdr:blipFill"]["a:blip"]["@r:embed"].ToString();

    imgList.Add(new ImportSoftProductImgDto
    {
        Id = id,
        Target = string.Empty,
        DISPIMG_Id = DISPIMG_Id
    });
}

var nodes_XMLRels = XElement.Parse(cellimagesXMLRels);
foreach (var xNode in nodes_XMLRels.DescendantNodes().OfType<XCData>().ToList())
{
    xNode.Parent.Add(xNode.Value);
    xNode.Remove();
}
var json_XMLRels = JObject.Parse(JsonConvert.SerializeXNode(nodes_XMLRels, Formatting.Indented));

foreach (var item in json_XMLRels["Relationships"]["Relationship"])
{
    var id = item["@Id"].ToString();
    var target = item["@Target"].ToString();
    //可能公用一张图片
    foreach (var imgItem in imgList.Where(o => o.Id == id))
    {
        imgItem.Target = target;
    }
}

7)遍历赋值图片路径

foreach (var item in rows)
{
    item.ImgOriginalUrl = imgList.FirstOrDefault(o => o.DISPIMG_Id == item.DISPIMG_Id)?.Target;
}

8)接下来就是图片上传到新地址的方式了,这里是我的上传实现

foreach (var item in rows)
{
    if (!string.IsNullOrWhiteSpace(item.ImgOriginalUrl))
    {
        var suffix = Path.GetExtension(item.ImgOriginalUrl).ToLower().Replace(".", "");//文件后缀
        var relativePath = Path.Combine("uploads", suffix, DateTime.Now.ToString("yyyyMM"));//相对路径
        var fileName = Guid.NewGuid().ToString("N") + "." + suffix;//图片重命名

        var absolutePath = Path.Combine(App.HostEnvironment.ContentRootPath, relativePath);//绝对路径

        if (!Directory.Exists(absolutePath))
        {
            Directory.CreateDirectory(absolutePath);
        }

        FileInfo file = new FileInfo(Path.Combine(zipFileDirectory, "xl", item.ImgOriginalUrl));
        if (file.Exists) //可以判断源文件是否存在
        {
            // 这里是true的话覆盖
            file.CopyTo(Path.Combine(absolutePath, fileName), true);
            item.ImgFinalUrl = Path.Combine(_appInfo.Host, relativePath, fileName).Replace("\\", "/");
        }
    }
}

9)至此,就可以往数据库里插入数据了

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-29 15:30:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-29 15:30:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-29 15:30:02       82 阅读
  4. Python语言-面向对象

    2024-04-29 15:30:02       91 阅读

热门阅读

  1. 遭遇字节对齐导致的错误一例

    2024-04-29 15:30:02       31 阅读
  2. 【前端开发】可拉动宽度窗口

    2024-04-29 15:30:02       29 阅读
  3. 解读霍兰德测试:高考生专业选择的新视角

    2024-04-29 15:30:02       34 阅读
  4. 前端项目学习记录1:svg图标的封装与使用

    2024-04-29 15:30:02       31 阅读
  5. 揭秘FastStone Capture

    2024-04-29 15:30:02       36 阅读
  6. postgres14 版本 pg_basebackup 基本备份+恢复

    2024-04-29 15:30:02       32 阅读
  7. vue-cli+vue3+vite+ts 搭建uniapp项目全过程(二)

    2024-04-29 15:30:02       34 阅读
  8. 富格林:虚假交易明晰安全应对方法

    2024-04-29 15:30:02       34 阅读
  9. 2024年一季度金融读报集锦

    2024-04-29 15:30:02       28 阅读