- A+
CSharpe中的IO+NPOI+序列化
文件文件夹操作
学习一下常见的文件、文件夹的操作。
什么是IO流?
I:就是input O:就是output,故称:输入输出流
将数据读入内存或者内存输出的过程。
常见的IO流操作,一般说的是[内存]与[磁盘]之间的输入输出。
作用
持久化数据,保证数据不再丢失!
文件操作流程:打开文件、读写数据、关闭文件。
常见的文件IO操作
//这是操作文件、文件夹必备 if (!Directory.Exists(LogPath))//检测文件夹是否存在 { } DirectoryInfo directory = new DirectoryInfo(LogPath);//对文件夹、文件的描述对象、不存在不报错 注意exists属性 Console.WriteLine($"全名称:{directory.FullName} || 创建时间:{directory.CreationTime} || 最后写入时间:{directory.LastWriteTime}"); //路径拼接,得到一个完整的路径 string filePath = Path.Combine(LogPath, "info.txt"); if (!File.Exists(filePath)) { } FileInfo fileInfo = new FileInfo(filePath); Console.WriteLine($"全名称:{fileInfo.FullName} || 创建时间:{fileInfo.CreationTime} || 最后写入时间:{fileInfo.LastWriteTime}");
常见的文件夹操作
{ if (!Directory.Exists(LogPath)) { DirectoryInfo directoryInfo = Directory.CreateDirectory(LogPath);//一次性创建全部的子路径 Directory.Move(LogPath, LogMovePath);//移动 原文件夹就不在了 Directory.Delete(LogMovePath);//删除 } }
常见的文件读写 操作
string fileName = Path.Combine(LogPath, "log.txt"); string fileNameCopy = Path.Combine(LogPath, "logCopy.txt"); string fileNameMove = Path.Combine(LogPath, "logMove.txt"); bool isExists = File.Exists(fileName); if (!isExists) { Directory.CreateDirectory(LogPath);//创建了文件夹之后,才能创建里面的文件 using (FileStream fileStream = File.Create(fileName))//打开文件流 (创建文件并写入) { string name = "12345567778890"; byte[] bytes = Encoding.Default.GetBytes(name); fileStream.Write(bytes, 0, bytes.Length); fileStream.Flush(); } using (FileStream fileStream = File.Create(fileName))//打开文件流 (创建文件并写入) { StreamWriter sw = new StreamWriter(fileStream); sw.WriteLine("1234567890"); sw.Flush(); } using (StreamWriter sw = File.AppendText(fileName))//流写入器(创建/打开文件并写入) { string msg = "大家好,我是Richard老师!!"; sw.WriteLine(msg); sw.Flush(); } using (StreamWriter sw = File.AppendText(fileName))//流写入器(创建/打开文件并写入) { string name = "0987654321"; byte[] bytes = Encoding.Default.GetBytes(name); sw.BaseStream.Write(bytes, 0, bytes.Length); sw.Flush(); } //文件的读取 foreach (string result in File.ReadAllLines(fileName))//读取文件中所有的行信息 { Console.WriteLine(result); } string sResult = File.ReadAllText(fileName); Byte[] byteContent = File.ReadAllBytes(fileName); string sResultByte = System.Text.Encoding.UTF8.GetString(byteContent); //建议大家不要去做多线程读取,即使要多线程读取,也要加锁,加锁----反多线程; //你们有没有遇到过大文件Txt---10G using (FileStream stream = File.OpenRead(fileName))//分批读取 { int length = 5; int result = 0; do { byte[] bytes = new byte[length]; result = stream.Read(bytes, 0, 5); for (int i = 0; i < result; i++) { Console.WriteLine(bytes[i].ToString()); } } while (length == result); } File.Copy(fileName, fileNameCopy); File.Move(fileName, fileNameMove); File.Delete(fileNameCopy); File.Delete(fileNameMove);//尽量不要delete }
常见的盘符操作
{//DriveInfo DriveInfo[] drives = DriveInfo.GetDrives();//获取当前计算机所有盘符 foreach (DriveInfo drive in drives) { if (drive.IsReady) Console.WriteLine($"类型:{drive.DriveType} 卷标:{drive.VolumeLabel} 名称:{drive.Name} 总空间:{drive.TotalSize} 剩余空间:{drive.TotalFreeSpace}"); else Console.WriteLine("类型:{drive.DriveType} is not ready"); } } { Console.WriteLine(Path.GetDirectoryName(LogPath)); //返回目录名,需要注意路径末尾是否有反斜杠对结果是有影响的 Console.WriteLine(Path.GetDirectoryName(@"d:\abc")); //将返回 d: Console.WriteLine(Path.GetDirectoryName(@"d:\abc"));// 将返回 d:abc Console.WriteLine(Path.GetRandomFileName());//将返回随机的文件名 Console.WriteLine(Path.GetFileNameWithoutExtension("d:\abc.txt"));// 将返回abc Console.WriteLine(Path.GetInvalidPathChars());// 将返回禁止在路径中使用的字符 Console.WriteLine(Path.GetInvalidFileNameChars());//将返回禁止在文件名中使用的字符 Console.WriteLine(Path.Combine(LogPath, "log.txt"));//合并两个路径 }
递归获取所有的文件
public static List<DirectoryInfo> GetAllDirectory(string rootPath) { if (!Directory.Exists(rootPath)) return new List<DirectoryInfo>(); List<DirectoryInfo> directoryList = new List<DirectoryInfo>();//容器 DirectoryInfo directory = new DirectoryInfo(rootPath);//root文件夹 directoryList.Add(directory); return GetChild(directoryList, directory); } /// <summary> /// 完成 文件夹--子目录--放入集合 /// </summary> /// <param name="directoryList"></param> /// <param name="directoryCurrent"></param> /// <returns></returns> private static List<DirectoryInfo> GetChild(List<DirectoryInfo> directoryList, DirectoryInfo directoryCurrent) { var childArray = directoryCurrent.GetDirectories(); if (childArray != null && childArray.Length > 0) { directoryList.AddRange(childArray); foreach (var child in childArray) { GetChild(directoryList, child); } } return directoryList; }
NPOI操作Excel
NPOI背景
Apache Poi是一种流行的API,它允许程序员使用java程序创建,修改和显示MS Office文件。这由Apche软件基金会开发使用java分布式设计或修改该Microsoft Office文件的开源库,它包含类和方法对用户输入数据或文件到Ms Office文档进行解码;
NPOI是什么呢?顾名思义就是POI的.NET版本,可以通过.NET来操作Office文档。
使用NPOI
名词解释
整个Excel:工作簿
Sheet页:页签,一个工作簿客户可以包含多个Sheet页。
表格:对应一个Sheet
行、列、单元格
C#中的常规操作:
导出一个Excel:其实就是要生成一个Excel文件,Excel文件对应的文件流。
导入一个Excel:读取一个文件,读取文件流,需要从文件流中读取我们需要的各种数据,解析Excel的数据。
创建一个Excel文件:
public class ExcelOperationHelper { public static IWorkbook CreateExcelWorkbook(string filePath) { IWorkbook workbook = null; if (filePath.EndsWith(".xls")) { workbook = new NPOI.HSSF.UserModel.HSSFWorkbook(); } else if (filePath.EndsWith(".xlsx")) { workbook = new NPOI.XSSF.UserModel.XSSFWorkbook(); } ISheet sheet = workbook.CreateSheet("Sheet1"); { IRow row = sheet.CreateRow(0); ICell cell = row.CreateCell(0); cell.SetCellValue("学生姓名"); ICell cell1 = row.CreateCell(1); cell1.SetCellValue("数学成绩"); ICell cell2 = row.CreateCell(2); cell2.SetCellValue("语文成绩"); } { IRow row = sheet.CreateRow(1); ICell cell = row.CreateCell(0); cell.SetCellValue("JJ鹏"); ICell cell1 = row.CreateCell(1); cell1.SetCellValue("100"); ICell cell2 = row.CreateCell(2); cell2.SetCellValue("150"); } return workbook; } }
Programs.cs
IWorkbook work = ExcelOperationHelper.CreateExcelWorkbook(path); using (FileStream file=new FileStream(path,FileMode.Create)) { work.Write(file); file.Close(); }
数据实体设置
需要考虑的问题
- 数据写道工作簿中的哪个sheet页中
- 生成的Excel---考虑表头放在哪个位置
- 直接集合中的某一个对象来直接生成---如果对象是一个实体---实体中有多少个属性;就表示多少个列;
最终的目标:做到业务系统不需要考虑其他,只需要按照规则来给定数据即可,就可以生成Excel出来。
数据实体
public class ExcelDataResource { /// <summary> /// 保存到Sheet的名称 /// </summary> public string SheetName { get; set; } /// <summary> /// 标题所在行 /// </summary> public int TitleIndex { get; set; } /// <summary> /// 每一个sheet的数据 /// </summary> public List<object> SheetDataResource { get; set; } }
添加一个新的特性
public class TitleAttribute:Attribute { public string Title { get; set; } public TitleAttribute(string title) { Title = title; } }
用户的信息
public class UserInfo { [Title("用户ID")] public int UserId { get; set; } [Title("用户名称")] public string UserName { get; set; } [Title("用户年龄")] public int UserAge { get; set; } [Title("用户类型")] public string UserType { get; set; } [Title("描述")] public string Description { get; set; } } }
根据固定格式生成IWorkBook
生成我们需要的excel的数据
static List<ExcelDataResource> GetExcelDataList() { List<object> objlist = new List<object>(); for (int i = 0; i < 100; i++) { objlist.Add(new UserInfo() { UserId = i + 1, UserName = $"名称-{i}", UserAge = i + i + 1, UserType = i + 1, Description = $"描述_描述_描述_描述_描述_描述_描述_描述_描述_描述_{i}" }); } List<object> Classobjlist = new List<object>(); for (int i = 0; i < 200; i++) { Classobjlist.Add(new ClassInfo() { UserId = i + 1, UserName = $"名称-{i}", Age = i + i + 1, UserType = i + 1, Description1 = $"描述_描述_描述_描述_描述_描述_描述_描述_描述_描述_{i}", Description2 = $"描述_描述_描述_描述_描述_描述_描述_描述_描述_描述_{i}", Description3 = $"描述_描述_描述_描述_描述_描述_描述_描述_描述_描述_{i}", Description4 = $"描述_描述_描述_描述_描述_描述_描述_描述_描述_描述_{i}" }); } return new List<ExcelDataResource>() { new ExcelDataResource(){ SheetName="页签1", TitleIndex=1, SheetDataResource=objlist }, new ExcelDataResource(){ SheetName="页签2", TitleIndex=1, SheetDataResource=Classobjlist } }; }
生成DataToXSSFWorkbook工作簿
public static IWorkbook DataToXSSFWorkbook(List<ExcelDataResource> dataResources) { XSSFWorkbook _Workbook = new XSSFWorkbook(); if (dataResources == null && dataResources.Count == 0) { return _Workbook; } foreach (var sheetResource in dataResources) { if (sheetResource.SheetDataResource != null && sheetResource.SheetDataResource.Count == 0) { break; } ISheet sheet = _Workbook.CreateSheet(sheetResource.SheetName); object obj = sheetResource.SheetDataResource[0]; Type type = obj.GetType(); List<PropertyInfo> propList = type.GetProperties().Where(c => c.IsDefined(typeof(TitleAttribute), true)).ToList(); IRow titleRow = sheet.CreateRow(0); ICellStyle style = _Workbook.CreateCellStyle(); style.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Grey25Percent.Index; style.FillPattern = FillPattern.SolidForeground; style.FillBackgroundColor = NPOI.HSSF.Util.HSSFColor.Automatic.Index; style.Alignment = HorizontalAlignment.CenterSelection; style.VerticalAlignment = VerticalAlignment.Center; titleRow.Height = 100 * 4; for (int i = 0; i < propList.Count(); i++) { TitleAttribute propertyAttribute = propList[i].GetCustomAttribute<TitleAttribute>(); ICell cell = titleRow.CreateCell(i); cell.SetCellValue(propertyAttribute.Title); cell.CellStyle = style; } for (int i = 0; i < sheetResource.SheetDataResource.Count(); i++) { IRow row = sheet.CreateRow(i + 1); object objInstance = sheetResource.SheetDataResource[i]; for (int j = 0; j < propList.Count; j++) { ICell cell = row.CreateCell(j); cell.SetCellValue(propList[j].GetValue(objInstance).ToString()); } } } return _Workbook; }
对应的使用的例子为:
List<ExcelDataResource> excelDataList = GetExcelDataList(); IWorkbook workbook1 = ExcelOperationHelper.DataToXSSFWorkbook(excelDataList); using (FileStream file=new FileStream(path,FileMode.Create)) { workbook1.Write(file); file.Close(); }
开发中的各种应用场景
- 写入Response二进制流
public void ImportExcelFileOnWriteResponse(int id) { ///设置ContentType HttpContext.Response.ContentType = "application/vnd.ms-excel"; ///生成文件名 string fileName = DateTime.Now.ToString("yyyyMMddHHmmssffffff"); ///设置Excel文件名 HttpContext.Response.Headers.Add("Content-Disposition", $"attachment;filename={fileName}.xls"); // 获取导出Excel需要的数据源 List<ExcelDataResource> excelDataResources = GetExcelSheetData(id); byte[] bt = ExcelOperationHelper.ToExcelByteArray(excelDataResources); HttpContext.Response.BodyWriter.WriteAsync(bt); }
- 调用框架的file方法
public IActionResult ImportExcelFileOnFileMethod(int id) { List<ExcelDataResource> excelDataResources = GetExcelSheetData(id); byte[] bt = ExcelOperationHelper.ToExcelByteArray(excelDataResources); string fileName = DateTime.Now.ToString("yyyyMMddHHmmssffffff"); return File(bt, "application/vnd.ms-excel", $"{fileName}.xls"); }
- 扩展IActionResult方法 ExcelResult方法
public IActionResult ImportExcelFileOnActionResultExtend(int id) { // 获取导出Excel需要的数据源 List<ExcelDataResource> list = GetExcelSheetData(id); return new ExcelResult(list); //调用IActionResult的扩展返回Excel }
对应IActionResult的实现
public class ExcelResult : IActionResult { private string _ExcelName; private List<ExcelDataResource> _ExcelDataResources; /// <summary> /// 如果没有时间就默认以当前时间为文件名称 /// </summary> /// <param name="excelDataResources"></param> public ExcelResult(List<ExcelDataResource> excelDataResources) : this(DateTime.Now.ToString("yyyyMMddHHmmssffffff"), excelDataResources) { } /// <summary> /// 构造函数 /// </summary> /// <param name="excelName">文件名称</param> /// <param name="excelDataResources">数据源</param> public ExcelResult(string excelName, List<ExcelDataResource> excelDataResources) { this._ExcelName = excelName; this._ExcelDataResources = excelDataResources; } public Task ExecuteResultAsync(ActionContext context) { return Task.Run(() => { context.HttpContext.Response.ContentType = "application/vnd.ms-excel"; context.HttpContext.Response.Headers.Add("Content-Disposition", $"attachment;filename={_ExcelName}.xls"); byte[] bt = ExcelOperationHelper.ToExcelByteArray(_ExcelDataResources); context.HttpContext.Response.BodyWriter.WriteAsync(bt); }); } }
excel导入
本质:目的是把Excel文件提交到服务器,然后把Excel文件中的数据信息读取出来,然后要处理的就是数据信息,
Excel文件的解析
- Excel文件---文件流 fileStream MemoryStream Byte[]----->IWorkbook,如果得到了一个IWorkbook就可以使用Npoi来进行解析.
转换为DataTable
public static List<DataTable> ToExcelDateTable(IWorkbook hSSFWorkbook) { List<DataTable> datatableList = new List<DataTable>(); for (int sheetIndex = 0; sheetIndex < hSSFWorkbook.NumberOfSheets; sheetIndex++) { ISheet sheet = hSSFWorkbook.GetSheetAt(sheetIndex); //获取表头 FirstRowNum 第一行索引 0 IRow header = sheet.GetRow(sheet.FirstRowNum);//获取第一行 if (header == null) { break; } int startRow = 0;//数据的第一行索引 DataTable dtNpoi = new DataTable(); startRow = sheet.FirstRowNum + 1; for (int i = header.FirstCellNum; i < header.LastCellNum; i++) { ICell cell = header.GetCell(i); if (cell != null) { string cellValue = $"Column{i + 1}_{cell.ToString()}"; if (cellValue != null) { DataColumn col = new DataColumn(cellValue); dtNpoi.Columns.Add(col); } else { DataColumn col = new DataColumn(); dtNpoi.Columns.Add(col); } } } //数据 LastRowNum 最后一行的索引 如第九行---索引 8 for (int i = startRow; i <= sheet.LastRowNum; i++) { IRow row = sheet.GetRow(i);//获取第i行 if (row == null) { continue; } DataRow dr = dtNpoi.NewRow(); //遍历每行的单元格 for (int j = row.FirstCellNum; j < row.LastCellNum; j++) { if (row.GetCell(j) != null) dr[j] = row.GetCell(j).ToString(); } dtNpoi.Rows.Add(dr); } datatableList.Add(dtNpoi); } return datatableList; }
Excel文件导入的多种场景demo
public IActionResult ImportExcelOnFormSubmit() { //获取上传的Excel文件 IFormFile file = Request.Form.Files["file"]; if (file != null && file.Length > 0) { string suffixName = Path.GetExtension(file.FileName).ToLower(); if (suffixName != ".xls" && suffixName != ".xlsx") { return Content("请导入文件为Excel格式"); } XSSFWorkbook hSSFWorkbook = new XSSFWorkbook(file.OpenReadStream()); List<DataTable> datatableList = ExcelOperationHelper.ToExcelDateTable(hSSFWorkbook); ViewBag.Info = Newtonsoft.Json.JsonConvert.SerializeObject(datatableList); } else { ViewBag.Info = "请上传文件"; } return View(); }
序列化和反序列化
序列化(Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或永久性存储区。以后,可以通过存储区中读取或反序列化对象的状态,重新创建该对象。
序列化之前:对象
序列化之后:把一个对象转换成另外一种形式来存储。
原始数据:
public class DataFactory { /// <summary> /// 初始化数据的 /// </summary> /// <returns></returns> public static List<Programmer> BuildProgrammerList() { #region data prepare List<Programmer> list = new List<Programmer>(); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "SoWhat", Sex = "男" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "day", Sex = "男" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "领悟", Sex = "男" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "Sam", Sex = "男" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "AlphaGo", Sex = "男" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "折腾", Sex = "男" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "Me860", Sex = "男" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "打兔子的猎人", Sex = "男" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "Nine", Sex = "女" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "望", Sex = "女" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "微笑刺客", Sex = "男" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "waltz", Sex = "男" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "爱在昨天", Sex = "男" }); list.Add(new Programmer() { Id = 1, Description = "Richard老师的学员", Name = "waltz", Sex = "男" }); #endregion return list; } } [Serializable] //必须添加序列化特性 public class Person { [NonSerialized] public int Id = 1; public string Name { get; set; } public string Sex { get; set; } } [Serializable] //必须添加序列化特性 public class Programmer : Person { private string Language { get; set; }//编程语言 public string Description { get; set; } }
XML序列化
public class XmlHelper { /// <summary> /// XmlSerializer序列化实体为字符串 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <returns></returns> public static string ToXml<T>(T t) where T : new() { XmlSerializer xmlSerializer = new XmlSerializer(t.GetType()); Stream stream = new MemoryStream(); xmlSerializer.Serialize(stream, t); stream.Position = 0; StreamReader reader = new StreamReader(stream); string text = reader.ReadToEnd(); return text; } /// <summary> /// 字符串序列化成XML /// </summary> /// <typeparam name="T"></typeparam> /// <param name="content"></param> /// <returns></returns> public static T ToObject<T>(string content) where T : new() { using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(content))) { XmlSerializer xmlFormat = new XmlSerializer(typeof(T)); return (T)xmlFormat.Deserialize(stream); } } /// <summary> /// 文件反序列化成实体 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="fileName"></param> /// <returns></returns> public static T FileToObject<T>(string fileName) where T : new() { fileName = Path.Combine(Constant.basePath, "File", @"Student.xml"); using (Stream fStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite)) { XmlSerializer xmlFormat = new XmlSerializer(typeof(T)); return (T)xmlFormat.Deserialize(fStream); } } }
jSON序列化
public class JsonHelper { #region Json /// <summary> /// JavaScriptSerializer /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj"></param> /// <returns></returns> public static string ObjectToString<T>(T obj) { JavaScriptSerializer jss = new JavaScriptSerializer(); return jss.Serialize(obj); } /// <summary> /// JavaScriptSerializer /// </summary> /// <typeparam name="T"></typeparam> /// <param name="content"></param> /// <returns></returns> public static T StringToObject<T>(string content) { JavaScriptSerializer jss = new JavaScriptSerializer(); return jss.Deserialize<T>(content); } /// <summary> /// JsonConvert.SerializeObject /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj"></param> /// <returns></returns> public static string ToJson<T>(T obj) { return JsonConvert.SerializeObject(obj); } /// <summary> /// JsonConvert.DeserializeObject /// </summary> /// <typeparam name="T"></typeparam> /// <param name="content"></param> /// <returns></returns> public static T ToObject<T>(string content) { try { return JsonConvert.DeserializeObject<T>(content); } catch (Exception) { throw; } } #endregion Json }
调用的实例
/// <summary> /// XML序列化器 /// </summary> public static void XmlSerialize() { //使用XML序列化对象 string fileName = Path.Combine(Constant.basePath, "File", "Student.xml"); ;//文件名称与路径 List<Programmer> pList = DataFactory.BuildProgrammerList(); using (Stream fStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite)) { XmlSerializer xmlFormat = new XmlSerializer(typeof(List<Programmer>));//创建XML序列化器,需要指定对象的类型 xmlFormat.Serialize(fStream, pList); } List<Programmer> resultList = null; using (Stream fStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite)) { XmlSerializer xmlFormat = new XmlSerializer(typeof(List<Programmer>));//创建XML序列化器,需要指定对象的类型 //使用XML反序列化对象 fStream.Position = 0;//重置流位置 resultList = pList = (List<Programmer>)xmlFormat.Deserialize(fStream); } } /// <summary> /// json也可以的 /// </summary> public static void Json() { List<Programmer> pList = DataFactory.BuildProgrammerList(); string result = JsonHelper.ObjectToString<List<Programmer>>(pList); List<Programmer> pList1 = JsonHelper.StringToObject<List<Programmer>>(result); }