C#.NET程序尝试—修复Excel批注错误

Excel2007打不开xlsx文件,这在我的日常工作中是非常常见的现象,究其原因是因为大家用的Excel版本五花八门,而恰好不同版本的Excel的xml代码规范又不一样,于是一个用Excel2013做的表格,如果里面还有很多批注或者数据验证等等内容......那我几乎可以预见接下来就是开始找做表格的人要一份xls格式的表格。因为在不装更新兼容包的情况下,上面说的那种情况,Excel基本上没法打开文件,或者打开了文件,批注被全部修复(直接删除)。

在很早前我就想过这个问题,为什么同样是xlsx文件,Excel2007会认为高版本Excel的批注会有问题?后来在Excelhome我找到了答案......原来仅仅是因为高版本Excel的comments文件里多了一串代码:ShapeId="0"。如果要手动修复,就把xlsx改成rar或者zip,然后把xl/comments*.xml文件都解压出来,把shapeId="0"替换成空值,把文件再放回压缩包,改回xlsx,再次打开文件,Excel2013做的表格这个时候就应该能正常打开了,至于Excel2016的表格,会还需要修复一次,因为批注的代码格式又变了。

 

于是愚钝的我就为这个想法付出了代价(真实原因是我实在是太菜了,连基础都没学好就开始跑)

using System;
using System.Text;
using System.Windows.Forms;
using System.IO.Compression;
using System.IO;
using CZip = ICSharpCode.SharpZipLib.Zip;

private void Button1_Click(object sender, EventArgs e)
        {
            int i = 0;
            OpenFileDialog path = new OpenFileDialog();
            //文件类型过滤
            path.Filter = @"待修复Excel表格|*.xlsx";
            //展开文件选择对话框
            DialogResult result = path.ShowDialog();
            if (result == DialogResult.OK)
            {
                //获取导出文件夹目录
                string expath = path.FileName + @"_Fix";
              if(Directory.Exists(expath))
                {
                    DialogResult fg= MessageBox.Show("导出数据已存在!是否覆盖?覆盖后将失去所有已导出数据!", "警告", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                    if (fg == DialogResult.Yes)//确认删除
                    {
                        //对重复文件夹进行删除操作
                        DirectoryInfo dl = new DirectoryInfo(expath);
                        dl.Delete(true);
                        DialogResult qr= MessageBox.Show("删除命令已执行,是否继续?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                        if (qr == DialogResult.Yes)
                            {
                                //继续执行命令
                            }
                            else
                            {
                                if (qr == DialogResult.No)//删除文件夹后不继续
                                {
                                    i = 1;
                                }
                            }
                    }
                    else
                    {
                        if (fg == DialogResult.No)//确认不删除
                        {
                            i = 1;
                        }
                    }
                }
                //强制用户确认后才进行解压操作
                if (i == 0)
                {
                    //获取打开文件的路径(全路径,含文件名)
                    int fnlength = path.ToString().LastIndexOf("FileName");
                    string sFile = path.ToString().Substring(fnlength + 9, path.ToString().Length - fnlength - 9);
                    //获取打开文件所在目录,传递至sourcepath
                    string sourcepath = Path.GetDirectoryName(sFile);

                    //开始解压文件
                    ZipFile.ExtractToDirectory(path.FileName, expath);
                    //跳转至xl文件夹下
                    string copath = expath + "\\xl\\";
                    //获取xl文件夹下所有带有comments字符的xml文件路径
                    string[] pathFile = Directory.GetFiles(copath, "comments*.xml", SearchOption.TopDirectoryOnly);
                    //将中间文件命名为cobak.xml
                    string strcon = copath + @"cobak.xml";
                    //暂时将替换容器内容清空
                    string con = "";
                    foreach (string str in pathFile)
                    {
                        StreamReader reader = new StreamReader(str, Encoding.UTF8);
                        //读取至文件尾
                        con = reader.ReadToEnd();
                        //替换shapeId="0"为空值
                        con = con.Replace(@"shapeId=""0""", "");
                        //替换Excel2013的不正确的XML代码块
                        con = con.Replace(@"</commment></commentList></comments>", "");

                        //开始以UTF-8编码开始写操作
                        StreamWriter writer = new StreamWriter(strcon, false, Encoding.UTF8);
                        //写入已替换的内容
                        writer.Write(con);
                        //释放写入缓冲区,暂时关闭写入器
                        writer.Flush();
                        writer.Close();
                        reader.Close();

                        //将写入文件复制为原文件,删除写入文件
                        File.Copy(strcon, str, true);
                        File.Delete(strcon);
                    }
                    //到此替换写入操作已完成

                    //开始修改文件扩展名
                    string nFile = Path.ChangeExtension(sFile, ".zip");
                    FileInfo fi = new FileInfo(sFile);
                    fi.MoveTo(nFile);

                        //开始Czip操作
                        CZip.ZipFile zip = new CZip.ZipFile(nFile);
                        zip.BeginUpdate();
                        //获取每个comments.xml文件的目录
                        foreach (string str in pathFile)
                        {
                            string filename = Path.GetFileName(str);
                            zip.Add(str,@"/xl/" + filename);
                            
                        }
                        zip.CommitUpdate();
                    //关闭Czip
                    zip.Close();
                    //将文件扩展名改回xlsx
                    string endFile =Path.ChangeExtension(nFile, ".xlsx");
                    //删除临时目录
                    fi.CopyTo(endFile, true);
                    DirectoryInfo dl = new DirectoryInfo(expath);
                    dl.Delete(true);
                    //删除临时文件
                    File.Delete(nFile);


                    System.Diagnostics.Process.Start("explorer.exe", sourcepath);
                }
            }

 

 

现在回头看自己写的代码......真是蠢爆了,一堆if判断先不说,同时用System.IO.Compression.ZipFile和ICSharpCode.SharpZipLib.Zip,自己也许根本就没想明白,只想着程序怎么顺利执行就完事,在调试的时候发现线程冲突也只是用另一串代码解决。

不过中间有一点没有想到的是sharpzip要将指定文件压缩到指定目录的用法倒是比我想得简单,原本以为会要用zipEntry,结果根本不需要.......只要指定好路径就OK了,过程完美模拟手动放文件进压缩包。

 

 

反正这个程序用处太小,我就当自娱自乐了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值