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

本文介绍如何利用MiniExcel库从Excel文件中读取数据,包括图片信息,通过解压和解析cellimages.xml和cellimages.xml.rels文件找到图片路径,并将图片上传到新的位置,最后将数据导入数据库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

起因:最新要做一个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)至此,就可以往数据库里插入数据了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值