需求:在Winform使用NOPI做导入时候,需要导入数据的同时导入图片。

虽然代码方面不适用(我好像也没仔细看过代码),但是感谢大佬给了灵感http://www.wjhsh.net/IT-Ramon-p-13100039.html,将excel后缀修改成Zip,解压,在其中找到图片的xml位置信息,以及对应的xml图片

效果图:

1、核心读取代码

        System.Data.DataTable dt;
private void btnImport_Click(object sender, EventArgs e)
{
dt = null;
string copyAfterFileName = DateTime.Now.ToString("yyyyMMddHHssmm");//文件名 以及解压后的文件夹名
string copyAfterFileNameExt = ".zip";//压缩后缀
string modelExlPath = Environment.CurrentDirectory + "\\Temp\\Cache";//缓存文件
if (!Directory.Exists(modelExlPath)) { Directory.CreateDirectory(modelExlPath); }//创建缓存文件夹
string copyAfterFullName = Path.Combine(modelExlPath, copyAfterFileName + copyAfterFileNameExt);//移动到该目录并改为压缩包
string copyDirFullName = Path.Combine(modelExlPath, copyAfterFileName);//解压后的文件夹位置 OpenFileDialog openfile = new OpenFileDialog();
openfile.Filter = "导入Excel(*.xls,*.xlsx)|*.xls;*.xlsx";
openfile.FilterIndex = 0;
openfile.RestoreDirectory = true;
openfile.Title = "导入文件路径";
//openfile.ShowDialog();
if (openfile.ShowDialog() != DialogResult.OK)
{
return;
} Common.ShowWaitForm();//正在加载..窗口
FileInfo fi1 = new FileInfo(openfile.FileName);
fi1.CopyTo(copyAfterFullName);//移动文件,并修改称为yyyyMMddHHssmm.zip try
{
wsDr wsDrModel = null;
if (!Directory.Exists(copyDirFullName)) { Directory.CreateDirectory(copyDirFullName); }
//解压到当前文件夹
if (SharpZip.UnpackFiles(copyAfterFullName, copyDirFullName) == false)//yyyyMMddHHssmm.zip为文件夹yyyyMMddHHssmm
{
Common.ShowErrorDialog("导入失败!");
LogHelper.Instance.Error("产品导入失败," + copyDirFullName + "自解压失败!");
return;
}
else
{
wsDrModel = GetImgLoaction(copyDirFullName);//读取excel图片信息,对应位置,对应的绝对路径,对应的图片实体
} string msg = "";
dt = ExcelUtil.ExcelToTable(openfile.FileName, wsDrModel, ref msg);//获得Excel
if (!string.IsNullOrEmpty(msg))
{
Common.ShowInfoDialog(msg);
}
if (dt == null || dt.Rows.Count <= 0)
{
Common.ShowSuccessTip("导入失败!");
return;
}
LoadList();//刷新表格
}
catch (Exception ex)
{
Common.ShowErrorDialog("导入错误!" + ex.Message);
}
finally
{
Common.HideWaitForm();//隐藏正在加载..窗口
}
} private wsDr GetImgLoaction(string copydirfullname)
{
//copydirfullname = "E:\\administrator\\Desktop\\test\\yyyyMMddHHssmm";
string pathMap = Path.Combine(copydirfullname, "xl\\drawings\\drawing1.xml");
var doc = XDocument.Load(pathMap);
//清理大部分命名空间,blip属性中的情况只能手动指定了
doc.Descendants().Attributes().Where(x => x.IsNamespaceDeclaration).Remove();
foreach (var elem in doc.Descendants())
{
elem.Name = elem.Name.LocalName;
}
doc.Save(pathMap);
wsDr model = XmlHelper.XmlToModelFile<wsDr>(pathMap);
Relationships relationships = GetImg(copydirfullname); if (model.twoCellAnchorList.Count > 0)
{
//将图片路径,图片实体保存在图片位置表(wsDr)中
foreach (var item in model.twoCellAnchorList)
{
item.pic1.nvPicPr1.cNvPr1.img = relationships.Relationship.SingleOrDefault(a => a.Id == item.pic1.blipFill1.blip1.imgid).img;
item.pic1.nvPicPr1.cNvPr1.imgUrl = relationships.Relationship.SingleOrDefault(a => a.Id == item.pic1.blipFill1.blip1.imgid).imgUrl;
}
}
return model;
}
private Relationships GetImg(string copydirfullname)
{
string pathMap = Path.Combine(copydirfullname, "xl\\drawings\\_rels\\drawing1.xml.rels");//获取图片所在目录的xml.rels
FileInfo fi = new FileInfo(pathMap); string newpathMap = Path.Combine(copydirfullname, "xl\\drawings\\_rels\\drawing1.xml");//转换为xml,不然不可读取
if (fi.Exists)
{
fi.MoveTo(newpathMap);
} //代码可用
var doc = XDocument.Load(newpathMap);
doc.Descendants().Attributes().Where(x => x.IsNamespaceDeclaration).Remove();//移除大部分命名空间
foreach (var elem in doc.Descendants())
elem.Name = elem.Name.LocalName;
doc.Save(newpathMap); Relationships model = XmlHelper.XmlToModelFile<Relationships>(newpathMap);//获取图片所在目录的xml
string pathMap1 = Path.Combine(copydirfullname, "xl\\drawings\\drawing1.xml");//../media/image1.png 是以xl/drawings文件夹的基础上,而不是xl/drawings/_rels
foreach (var item in model.Relationship)
{
string newpath = GetPath(Path.GetFullPath(pathMap1), item.Target);//获取 yyyyMMddHHssmm\xl\drawings target ../media/image1.png 转换为yyyyMMddHHssmm\xl\media\image1.png
//保存路径,该路径在上传图片时使用
item.imgUrl = newpath;
//以流形式读取图片,不占用图片
using (var stream = new FileStream(newpath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
{
item.img = Image.FromStream(stream);
}
}
return model;
}
private string GetPath(string sourPath, string path)
{
string[] pathT = path.Split('/');
string newpath = sourPath;
for (int i = 0; i < pathT.Length; i++)
{ if (pathT[i] == "..")
{
DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(newpath)); newpath = di.Parent.FullName;
}
else
{
newpath = Path.GetFullPath(Path.Combine(newpath, pathT[i]));
}
}
return newpath;
}

2、根据xml生成的实体,并处理后

  #region 主要实体
//实体主要部分,根据xml生成
[Serializable]
public class wsDr
{
[XmlElement(ElementName = "twoCellAnchor")]//指定节点名称
public List<twoCellAnchor> twoCellAnchorList { get; set; } }
//读取图片实体
public class Relationships
{
[XmlElement("Relationship")]
public List<Relationship> Relationship { get; set; } }
#endregion
#region 其他实体
public class from
{
//这里列名称和节点名称相同,不需要特意指定xml节点名称
public int col { get; set; }
public int row { get; set; } }
public class to
{
public int col { get; set; }
public int row { get; set; }
}
public class cNvPr
{
[XmlAttribute( "id")]
public string _id { get; set; }
[XmlAttribute("name")]
public string _name { get; set; }
public Image img { get; set; }
public string imgUrl { get; set; }
}
public class blip
{
/*手动指定xml命名空间,该命名空间使用..Where(x => x.IsNamespaceDeclaration).Remove()移除不了。
* 注:xml中这块读取出来后不认为它是命名空间,因为是子级特意指定的
*/
[XmlAttribute("embed",Namespace= "http://schemas.openxmlformats.org/officeDocument/2006/relationships")]
public string imgid { get; set; } }
public class blipFill
{
[XmlElement("blip")]
public blip blip1 { get; set; } }
public class nvPicPr
{
[XmlElement(ElementName = "cNvPr")]
public cNvPr cNvPr1 { get; set; } }
public class pic
{
[XmlElement(ElementName = "nvPicPr")]
public nvPicPr nvPicPr1 { get; set; }
[XmlElement("blipFill")]
public blipFill blipFill1 { get; set; }
}
public class twoCellAnchor
{
[XmlElement(ElementName = "from")]
public from from1 { get; set; }
[XmlElement(ElementName = "to")]
public to to1 { get; set; }
[XmlElement(ElementName = "pic")]
public pic pic1 { get; set; } } public class Relationship
{
[XmlAttribute("Id")]
public string Id { get; set; }
[XmlAttribute("Target")]
public string Target { get; set; }
public Image img { get; set; }
public string imgUrl { get; set; }
}
#endregion

3、使用NOPI读取Excel内容

private static ISheet ExcelToSheet(string file)
{
IWorkbook workbook;
string fileExt = Path.GetExtension(file).ToLower();
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
//XSSFWorkbook 适用XLSX格式,HSSFWorkbook 适用XLS格式
if (fileExt == ".xlsx") { workbook = new XSSFWorkbook(fs); } else if (fileExt == ".xls") { workbook = new HSSFWorkbook(fs); } else { workbook = null; }
if (workbook == null) { return null; }
ISheet sheet = workbook.GetSheetAt(0);
return sheet;
}
}
/// <summary>
/// Excel导入成Datable
/// </summary>
/// <param name="file">导入路径(包含文件名与扩展名)</param>
/// <returns></returns>
public static DataTable ExcelToTable(string file, wsDr wsDrModel, ref string msg)
{
try
{
ISheet sheet = ExcelToSheet(file);
DataTable dt = new DataTable();
//表头
IRow header = sheet.GetRow(sheet.FirstRowNum);
//List<int> columns = new List<int>();
int columnsCount = 1;
dt.Columns.Add(new DataColumn("Id"));
dt.Columns.Add(new DataColumn("dnxh"));
dt.Columns.Add(new DataColumn("dwxh"));
dt.Columns.Add(new DataColumn("zwmc"));
dt.Columns.Add(new DataColumn("ywmc"));
dt.Columns.Add(new DataColumn("cplx"));
dt.Columns.Add(new DataColumn("dw"));
dt.Columns.Add(new DataColumn("sfwgcp"));
dt.Columns.Add(new DataColumn("sflscp"));
dt.Columns.Add(new DataColumn("mlj"));
dt.Columns.Add(new DataColumn("Img", typeof(Image)));
dt.Columns.Add(new DataColumn("cpcc"));
dt.Columns.Add(new DataColumn("cpjz"));
dt.Columns.Add(new DataColumn("ImgUrl")); for (int i = 1; i <= sheet.LastRowNum; i++)
{
DataRow dr = dt.NewRow();
object dnxh = sheet.GetRow(i).GetCell(0).GetRealValue();//对内型号
if (dnxh == null || string.IsNullOrEmpty(dnxh.ToString()))
{
msg += "请填写第" + i + "行的【对内型号】!";
break;
}
dr["dnxh"] = dnxh;
object dwxh = sheet.GetRow(i).GetCell(1).GetRealValue();//对外型号
if (dwxh == null || string.IsNullOrEmpty(dwxh.ToString()))
{
msg += "请填写第" + i + "行的【对外型号】!";
break;
}
dr["dwxh"] = dwxh;
object zwmc = sheet.GetRow(i).GetCell(2).GetRealValue();//zwmc
if (zwmc == null || string.IsNullOrEmpty(zwmc.ToString()))
{
msg += "请填写第" + i + "行的【中文名称】!";
break;
}
dr["zwmc"] = zwmc;
object ywmc = sheet.GetRow(i).GetCell(3).GetRealValue();//英文名称
if (ywmc == null || string.IsNullOrEmpty(ywmc.ToString()))
{
msg += "请填写第" + i + "行的【英文名称】!";
break;
}
dr["ywmc"] = ywmc;
object cplx = sheet.GetRow(i).GetCell(4).GetRealValue();//产品类型
if (cplx == null || string.IsNullOrEmpty(cplx.ToString()))
{
msg += "请填写第" + i + "行的【产品类型】!";
break;
}
dr["cplx"] = cplx;
object dw = sheet.GetRow(i).GetCell(5).GetRealValue();//单位
if (dw == null || string.IsNullOrEmpty(dw.ToString()))
{
msg += "请填写第" + i + "行的【单位】!";
break;
}
dr["dw"] = dw;
object sfwgcp = sheet.GetRow(i).GetCell(6).GetRealValue();//是否外购
if (sfwgcp == null)
{
msg += "请填写第" + i + "行的【是否外购】!";
break;
}
if (sfwgcp.ToString() != "自制" && sfwgcp.ToString() != "外购")
{
msg += "请填写第" + i + "行的【是否外购】自制/外购,请勿填写其他内容!";
break;
}
dr["sfwgcp"] = sfwgcp;
object sflscp = sheet.GetRow(i).GetCell(7).GetRealValue();//是否临时产品
if (sflscp == null)
{
msg += "请填写第" + i + "行的【是否临时产品】!";
break;
}
if (sflscp.ToString() != "是" && sflscp.ToString() != "否")
{
msg += "请填写第" + i + "行的【是否临时产品】是/否,请勿填写其他内容!";
break;
}
dr["sflscp"] = sflscp;
object mljobj = sheet.GetRow(i).GetCell(8).GetRealValue();//目录价
decimal mlj = 0;
if (mljobj != null)
{
if (!decimal.TryParse(mljobj.ToString(), out mlj))
{
msg += "第" + i + "行的【目录价】数值错误,请正确填写!";
break;
}
}
dr["mlj"] = mlj;
object cpcc = sheet.GetRow(i).GetCell(10).GetRealValue();//产品尺寸
dr["cpcc"] = cpcc;
object cpjz = sheet.GetRow(i).GetCell(11).GetRealValue();//净重
dr["cpjz"] = cpjz;
dr["id"] = Guid.NewGuid().ToString();
//-----------获取图片
//产品主图 第9列
int col = 9;
if (wsDrModel != null && wsDrModel.twoCellAnchorList.Count > 0)
{
var list = wsDrModel.twoCellAnchorList.Where(a => i >= a.from1.row && col >= a.from1.col && i <= a.to1.row && col <= a.to1.col).ToList();
if (list.Count > 0)
{
dr["Img"] = (Image)list[0].pic1.nvPicPr1.cNvPr1.img;
dr["ImgUrl"] = list[0].pic1.nvPicPr1.cNvPr1.imgUrl; }
}
//XmlHelper.SetValue
//XmlHelper.XmlToModel<>(pathMap);
//-----------
dt.Rows.Add(dr);
}
return dt;
}
catch (Exception ex)
{
LogHelper.Instance.Info(ex.ToString());
throw ex;
}
}

4、保存信息

  private void btnSave_Click(object sender, EventArgs e)
{
List<Model.Product> listProduct = new List<Model.Product>(); foreach (DataRow item in dt.Rows)
{
Model.Product model = new Model.Product();
//组建信息保存到实体
listProduct.Add(model);
}
if (listProduct.Count <= 0)
{
Common.ShowInfoTip("没有需要保存的信息!请先导入");
return;
}
Loading2.Show(this, new Action(() => UpLoadImage(listProduct)), new Action(() => this.Close()));//这个Loading异步加载在其他文章有
}
bool isSuccess = false;
private void UpLoadImage(List<Model.Product> listProduct)
{
List<CommandInfo> commandInfos = new List<CommandInfo>();
foreach (var item in listProduct)
{
item.Cpzp = CommonUtil.UploadFile(item.Cpzp);//上传后转换成服务器路径 \\Upload\Image\202211030918546.png commandInfos.Add(BLLService.Instance.BaseProducts.AddSql(item));
}
try
{
if (BLLService.DoTran(commandInfos))//事务执行insert产品信息
{
Common.ShowSuccessTip("导入成功!");
dt = null;
isSuccess = true;
}
else
{
Common.ShowErrorDialog("导入失败!");
}
}
catch (Exception ex)
{
LogHelper.Instance.Error("导入失败!" + ex);
Common.ShowErrorDialog("导入失败!" + ex);
}
}

过程:

将Excel后缀换成zip解压得到文件夹。

其中xl\drawings\drawing1.xml记录了图片位置信息和id。对应xl\drawings\_rels\drawing1.xml.rels中图片位置和名称

根据图片位置,找到xl\media\image1.png

作者:兮去博客
出处:https://www.cnblogs.com/bklsj/p/16784749.html
版权:本文版权归作者和博客园共有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任

C#winform使用NOPI读取Excel读取图片的更多相关文章

  1. PHP读取Excel内的图片

    今天接到了一个从Excel内读取图片的需求,在网上查找了一些资料,基本实现了自己的需求,不过由于查到的一些代码比较久远,不能直接移植到自己的项目里,需要稍加改动一下. 这里介绍一下分别使用phpspr ...

  2. 10.ODBC创建/读取Excel QT4

    看到一篇MFC的参考链接:https://blog.csdn.net/u012319493/article/details/50561046 改用QT的函数即可 创建Excel //创建Excel v ...

  3. Aspose.cells 读取Excel表中的图片问题

    一.说明 本文主要是讲解,怎么使用aspose.cells读取Excel表中的图片,并把图片转换成流或是image对象. 二.开发环境说明 开发工具vs2012,c#语言, 三.Aspose.cell ...

  4. Open Xml 读取Excel中的图片

      在我的一个项目中,需要分析客户提供的Excel, 读出其中的图片信息(显示在Excel的第几行,第几列,以及图片本身). 网络上有许多使用Open Xml插入图片到Word,Excel的文章, 但 ...

  5. Python读取excel中的图片

    作为Java程序员,Java自然是最主要的编程语言.但是Java适合完成大型项目,对于平时工作中小的工作任务,需要快速完成,易于修改和调试,使用Java显得很繁琐,需要进行类的设计,打成jar包,出现 ...

  6. poi读取Excel文件和图片

    首先得说一下,Excel文件是有03版和07版的区别的,也就是.xls和.xlsx,这两个文件需要分开读取. 其它的废话就不说了,直接贴代码: package util; import java.io ...

  7. winform下读取excel文件并绑定datagridview例子

    首先我要读取这个excel文件然后生成Datable 用winform编程的方式 前台界面: 后台的代码 using System; using System.Collections.Generic; ...

  8. WinForm 读取Excel 数据显示到窗体中

    最近教学中,需要用到WinForm 读取Excel数据,于是就做了一个简单的,废话不多说,直接codding... //读取Excel的帮助类 class SqExcellHelper { publi ...

  9. java--poi读取excel图片和内容(支持03版本)

    有的时候需要将excel中所包含的图片在导入的时候取出来存到服务器中, 详细实现代码如下: package com.liuf.util; import java.io.BufferedInputStr ...

  10. thinkphp用phpexcel读取excel,并修改列中的值,再导出excel,带往excel里写入图片

    <?php class GetpriceAction extends AdministratorAction { // 文件保存路径 protected $savepath; // 允许上传的文 ...

随机推荐

  1. JavaWeb核心篇(3)——JSP,MVC,三层架构

    JavaWeb核心篇(3)--JSP,MVC,三层架构 在本篇文章中我们会学习到JSP,MVC,三层架构 虽然JSP已经快被时代所淘汰,但是在一些老旧的工作场所还是有在使用,所以了解一下也不为过 至于 ...

  2. IO流的文件输入输出效率问题

    IO流的文件输入输出效率问题 第一种方法 我用使用一个数组,把FIleInputStream获取到的二进制数存入这个数组,然后使用FIleOutputStream进行输出 缺点:速度慢 优点:不消耗内 ...

  3. MySQL8更改数据存储目录

  4. Elasticsearch:Index生命周期管理入门

    如果您要处理时间序列数据,则不想将所有内容连续转储到单个索引中. 取而代之的是,您可以定期将数据滚动到新索引,以防止数据过大而又缓慢又昂贵. 随着索引的老化和查询频率的降低,您可能会将其转移到价格较低 ...

  5. MySQL之pt-query-digest分析慢查询日志的详情介绍

    一.简介 pt-query-digest是用于分析mysql慢查询的一个工具,它可以分析binlog.General log.slowlog,也可以通过SHOWPROCESSLIST或者通过tcpdu ...

  6. 线段树学习笔记(基础&进阶)(一) | P3372 【模板】线段树 1 题解

    什么是线段树 线段树是一棵二叉树,每个结点存储需维护的信息,一般用于处理区间最值.区间和等问题. 线段树的用处 对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是 O(log n). 基础 ...

  7. [题解] Codeforces 438 E The Child and Binary Tree DP,多项式,生成函数

    题目 首先令\(f_i\)表示权值和为\(i\)的二叉树数量,\(f_0=1\). 转移为:\(f_k=\sum_{i=0}^n \sum_{j=0}^{k-c_i}f_j f_{k-c_i-j}\) ...

  8. C#-10 事件

    一 发布者和订阅者 很多时候都有这种需求,当一个特定的程序事件发生时,程序的其他部分可以得到该事件已经发生的通知. 发布者/订阅者模式可以满足这种需求. 发布者:发布某个事件的类或结构,其他类可以在该 ...

  9. 基于tauri打造的HTTP API客户端工具-CyberAPI

    国庆长假和朋友聚会的时候,和朋友谈起最近这段时间捣鼓tauri,写了一个HTTP API客户端工具.『你写了这么多东西,其实有想过是为了啥不?』为了啥这是一个很大的命题,当初每个项目的时候都想过它应该 ...

  10. 7.RabbitMQ系列之topic主题交换器

    topic主题交换器它根据在队列绑定的路由键和路由模式通配符匹配将消息路由到队列. 生产者在消息头中添加路由键并将其发送到主题交换器. 收到消息后,exchange尝试将路由键与绑定到它的所有队列的绑 ...