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