2017-05-22 6 views
1

Ich habe eine Excel-Datei, die Diagramme enthält, diese Diagramme stellen Daten in Spalten dar, in meinem Programm ändere ich diese Daten in Spalten und Diagrammänderungen, danach exportiere ich diese Diagramme in .png-Dateien, aber dort traf ich eine Ausnahme HRESULT: 0x80030020 (STG_E_SHAREVIOLATION)Excel-Tabelle als Bild exportieren

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(); 
     } 
    } 
} 
+0

Ausnahme erscheint hier: chart.Export (ExportPfad + @ "\ leaf" + w + ".png", "PNG", false); –

+0

STG_E_SHAREVIOLATION: "Zugriff verweigert, da ein anderer Aufrufer die Datei geöffnet und gesperrt hat". Eine Vermutung ist, dass Ihnen der Zugriff verweigert wird, weil eine alte Datei mit dem gleichen Dateinamen geöffnet ist/verwendet wird. Haben Sie die alten Dateien gelöscht, bevor Sie sie erneut ausführen? – NLindbom

+0

@NLindbom Sie haben Recht, Problem war, weil ich die gleichen .png Dateien mit dem gleichen Namen in Schleife erstelle und speichere. Erstens habe ich versucht, die Datei nach jeder Iteration zu löschen, aber es gab eine Fehlermeldung wie "konnte nicht gelöscht werden, weil diese Datei geöffnet ist". Also habe ich das Problem gelöst, indem ich für jedes Diagramm verschiedene .png-Dateien erstellt habe. Aber ist es ein guter Weg das zu tun oder gibt es einen anderen, der besser ist? –

Antwort

0

Könnte sein, dass Ihr Programm zwei Instanzen derselben Datei hat. Eine andere Sache kann die Datei speichern, bevor Sie versuchen, das Bild zu speichern.

0

Wie in der Frage erwähnt Kommentare HRESULT: 0x80030020 (STG_E_SHAREVIOLATION) ist "Zugriff verweigert, weil ein anderer Aufrufer die Datei geöffnet und gesperrt hat" Weitere Informationen here. Die Datei war einfach noch offen/in Verwendung und kann gelöst werden, indem zuerst die alten Dateien gelöscht werden.

Es gibt einige Optionen, und es hängt davon ab, wie Sie beabsichtigen, das Programm zu verwenden. Das Hinzufügen einer try/catch-Anweisung verhindert, dass das Programm abstürzt. Außerdem sehe ich keine besondere Best Practice, es hängt von der Nutzung ab. Meiner Meinung nach ist es sehr vernünftig, dass das Programm beendet wird, wenn es nicht speichern kann.

Im Interesse eine Lösung anzubieten, die Sie nach Ihren Wünschen anpassen können: zuerst ein Verfahren zur Diagramme speichern, die bei Erfolg (nicht schön, aber machen den Job) true zurückgibt: wird

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; 
} 

Diese Lösung Ausfahrt erfolglos sparen:

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

ein längeres Beispiel, das 10-fache Speicher wird erneut versuchen, indem Sie die ‚w‘ Parameter erhöht wird, dann einen zufälligen Dateinamen versuchen. Wenn das nicht funktioniert, wird das Programm beendet.

  //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(); 
         } 
        } 
       } 
      } 

Und eine Bemerkung in Bezug auf die oben genannten Code: (First off es fehlerhaft ist, denn wenn man schon 10 Charts 11 Mal generieren Sie immer zuerst Charts generieren 0-99 dann werden Sie mit 10 Charts am Ende mit völlig zufällig In diesem Fall möchten Sie möglicherweise nur zufällige Namen generieren. In den meisten Fällen ist es nicht gut, alle Ausnahmen abzufangen und true/false zurückzugeben. Zukünftige Probleme können auftreten, wenn eine andere Ausnahme ausgelöst wird, die nicht mit Dateinamen zusammenhängt. Sowohl der Benutzer als auch der Programmierer werden nicht merken, was passiert ist. Es ist besser, Dateinamen zu verlangen, die verwendet werden können, vielleicht machen 'w' oder die Ausgabedateinamen einen Eingabeparameter für das Programm, um etwas Flexibilität zu bieten.

Eine letzte Option könnte sein, stattdessen ein neues zufälliges Ausgabeverzeichnis zu erstellen, um zu garantieren, dass es leer ist und die bevorzugten Dateinamen dort auszugeben. Auch unter Verwendung von Path.GetRandomFileName(), die den Vorteil gegenüber Path.GetTempFileName() hat, die Datei nicht zu erstellen.