将Excel图表导出为图像

时间:2017-05-22 04:25:10

标签: c# excel charts export

我有一个Excel文件,其中有一个图表,这些图表代表列中的数据,在我的程序中我更改这些数据的列和图表更改,之后我将这些图表导出到.png文件中,但我遇到了一个异常HRESULT:0x80030020(STG_E_SHAREVIOLATION)

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Excel = Microsoft.Office.Interop.Excel;
using RTO.Models;
using Novacode;
using System.Drawing;
using Word = Microsoft.Office.Interop.Word;
using System.Reflection;
using CommonLib.SharedModels;

namespace RTO
{
    class Program
    {
        public static void ReportRTO(RtoCommonData cmnData, List<Antenna> antennas)
        {
            Novacode.Image imageh, imagev, image1, image2;
            Picture pictureh, picturev, picture1, picture2;
            Paragraph pimg;

            var exApp = new Excel.Application();
            exApp.ScreenUpdating = false;
            var exBook = exApp.Workbooks.Open(fileLeaf);
            var exSheet = exBook.Worksheets[1] as Excel.Worksheet;
            Excel.Range r1 = exSheet.get_Range("A1", "A360");
            Excel.Range r2 = exSheet.get_Range("B1", "B360");
            double[,] d1 = new double[360, 1];
            double[,] d2 = new double[360, 1];
            int w = 1;

            var application = new Excel.Application();
            application.ScreenUpdating = false;
            var workbook = application.Workbooks.Open(fileExcel);
            var worksheet = workbook.Worksheets[1] as Excel.Worksheet;
            Excel.Range rng1 = worksheet.get_Range("A1", "A361");
            Excel.Range rng2 = worksheet.get_Range("B1", "B361");
            Excel.Range rng3 = worksheet.get_Range("C1", "C361");
            Excel.Range rng4 = worksheet.get_Range("D1", "D361");
            double[,] data1 = new double[361, 1];
            double[,] data2 = new double[361, 1];
            double[,] data3 = new double[361, 1];
            double[,] data4 = new double[361, 1];
            int flnmadd = 1;

            for (int i = 0; i < antennas.Count; i++)
            {
                //Save chart as image
                w = 1;
                foreach (Excel.Worksheet ws in exBook.Worksheets)
                {
                    Excel.ChartObjects chartObjects = (Excel.ChartObjects)(ws.ChartObjects(Type.Missing));
                    foreach (Excel.ChartObject co in chartObjects)
                    {
                        co.Select();
                        Excel.Chart chart = co.Chart;
                        chart.Export(exportPath + @"\leaf" + w + ".png", "PNG", false);
                        w++;
                    }
                }

                //Insert image to doc
                image1 = doc.AddImage(leafimg1);
                picture1 = image1.CreatePicture();
                picture1.Width = 310;
                picture1.Height = 310;
                image2 = doc.AddImage(leafimg2);
                picture2 = image2.CreatePicture();
                picture2.Width = 310;
                picture2.Height = 310;
                pimg = doc.InsertParagraph();
                pimg.AppendPicture(picture1);
                pimg.AppendPicture(picture2);

                for (int j = 0; j < boztrows; j++)
                {
                    data1[j, 0] = sumbozres[i].Rxhor[j];
                    data2[j, 0] = sumbozres[i].Rzhor[j];
                    data3[j, 0] = sumbozres[i].Rxver[j];
                    data4[j, 0] = sumbozres[i].Rzver[j];
                }
                data1[boztrows, 0] = data1[0, 0];
                data2[boztrows, 0] = data2[0, 0];
                data3[boztrows, 0] = data3[0, 0];
                data4[boztrows, 0] = data4[0, 0];
                rng1.Value = data1;
                rng2.Value = data2;
                rng3.Value = data3;
                rng4.Value = data4;

                //Save chart as image
                flnmadd = 1;
                foreach (Excel.Worksheet ws in workbook.Worksheets)
                {
                    Excel.ChartObjects chartObjects = (Excel.ChartObjects)(ws.ChartObjects(Type.Missing));
                    foreach (Excel.ChartObject co in chartObjects)
                    {
                        co.Select();
                        Excel.Chart chart = co.Chart;
                        chart.Export(exportPath + @"\charthv" + flnmadd + ".png", "PNG", false);
                        flnmadd++;
                    }
                }

                //Insert image to doc
                if (antennas[i].Type == "БС")
                {
                    imageh = doc.AddImage(charthimg);
                    pictureh = imageh.CreatePicture();
                    pictureh.Width = 624;
                    pictureh.Height = 357;
                    imagev = doc.AddImage(chartvimg);
                    picturev = imagev.CreatePicture();
                    picturev.Width = 624;
                    picturev.Height = 156;
                    pimg = doc.InsertParagraph();
                    pimg.AppendPicture(pictureh);
                    pimg = doc.InsertParagraph();
                    pimg.AppendPicture(picturev);
                }
                else if (antennas[i].Type == "РРС")
                {
                    imageh = doc.AddImage(rrsimg);
                    pictureh = imageh.CreatePicture();
                    pictureh.Width = 624;
                    pictureh.Height = 156;
                    pimg = doc.InsertParagraph();
                    pimg.AppendPicture(pictureh);
                }

                trsprev += trs;
                freqs = "";
                pows = "";
                koefgs = "";
                koefgrazs = "";
                poteri = "";
                poteriraz = "";
                freqAvg = 0;
            }

            exBook.Save();
            exBook.Close();
            exApp.Workbooks.Close();
            exApp.Quit();
            workbook.Save();
            workbook.Close();
            application.Workbooks.Close();
            application.Quit();
        }
    }
}

2 个答案:

答案 0 :(得分:0)

可能是您的程序有两个同一文件的实例。另一件事可以是在您尝试保存图片之前保存文件。

答案 1 :(得分:0)

正如问题评论中所指出的那样:HRESULT:0x80030020(STG_E_SHAREVIOLATION)是“拒绝访问,因为另一个调用者打开并锁定了文件”更多信息here。该文件仍处于打开/使用状态,可以通过先删除旧文件来解决。

有一些选项,这取决于您打算如何使用该程序。添加try / catch语句将使程序崩溃。除此之外,我没有看到任何特定的最佳实践,这取决于使用情况。 在我看来,如果程序无法保存,退出计划是非常合理的。

为了提供一个可以根据自己的喜好调整的解决方案:首先是一种保存图表的方法,如果成功则返回true(不是很漂亮但是工作):

using System.IO;

private static bool SaveExcelChartAsPNG(ChartObject co, 
    string path, string filename)
{
    try
    {
        string filenamePNG = Path.ChangeExtension(filename, "png");
        string fullFilenamePNG = Path.Combine(path, filenamePNG);

        co.Select();
        co.Chart.Export(fullFilenamePNG, "PNG", false);
    }
    catch
    {
        // Save was not successful
        return false;
    }
    return true;
}

此解决方案将在失败的保存时退出:

            foreach (var co in chartObjects)
            {
               if (!SaveExcelChartAsPNG(exportPath, @"\leaf" + w + ".png"))
                   Application.Exit();
            }

通过递增'w'参数重试保存10次的较长示例,然后尝试随机文件名。如果这不起作用,程序将退出。

            //Save chart as image
            w = 1;
            foreach (var ws in exBook.Worksheets)
            {
                var chartObjects = (Excel.ChartObjects)(ws.ChartObjects(Type.Missing));
                foreach (var co in chartObjects)
                {
                    int retry = 0;
                    bool successfulSave = false;
                    while (!successfulSave && retry < 10) // retry by incerementing w parameter 10 times)
                    {
                       successfulSave = SaveExcelChartAsPNG(exportPath, @"\leaf" + w + ".png"))
                       retry++;
                       w++;
                    }

                    if (!successfulSave)
                    {
                        // Try again with random filename, otherwise exit
                        string filename = Path.GetRandomFileName();
                        if (!SaveExcelChartAsPNG(exportPath, filename))
                        {
                            // Save still not successful, exit
                            Application.Exit();
                        }
                    }
                }
            }

关于上述代码的评论:(首先它有缺陷,因为如果你已经生成10次图表11次,你将始终首先生成图表0-99然后你将最终得到10个完全随机名称的图表。你可能只想生成随机名称。) 在大多数情况下,捕获所有异常并返回true / false并不好。当引发与文件名无关的其他异常时,可能会出现未来的问题。用户和程序员都不会忘记发生的事情。最好要求可以使用的文件名,可能使'w'或输出文件名成为程序的输入参数,以提供一些灵活性。

最后一个选项可能是创建一个新的随机输出目录,以保证它是空的并在那里输出首选的文件名。同样使用Path.GetRandomFileName(),其优势超过Path.GetTempFileName()无法创建文件。