2015-10-17 159 views
1

我正在編寫一些C#應用程序和一些Google Spreadsheets集成。我處於一種需要將工作表中的某些數據移入不同電子表格的情況。這個工作表包含大量的數據,所以我想避免遍歷其內容。如何將現有Google工作表插入Google電子表格?

API指南給出an example如何在電子表格中創建新的工作表。我修改了它現有的工作表添加到電子表格:

using System; 
using Google.GData.Client; 
using Google.GData.Spreadsheets; 

namespace MySpreadsheetIntegration 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      SpreadsheetsService service = new SpreadsheetsService("MySpreadsheetIntegration-v1"); 

      SpreadsheetEntry destinationSpreadsheet = fetchGoogleSpreadSheetEntry(service, "some_title"); 
      SpreadsheetEntry originSpreadsheet = fetchGoogleSpreadSheetEntry(service, "some_other_title"); 

      // Create a local representation of the new worksheet. 
      WorksheetEntry originWorksheet = fetchGoogleWorksheet(originSpreadsheet, "some_worksheet_title"); 

      // Send the local representation of the worksheet to the API for 
      // creation. The URL to use here is the worksheet feed URL of our 
      // spreadsheet. 
      WorksheetFeed wsFeed = destinationSpreadsheet.Worksheets; 
      service.Insert(wsFeed, originWorksheet); 
     } 
    } 
} 

爲了清楚起見,上面的代碼試圖以在「some_other_title」電子表格「some_worksheet_title」工作表,並把它納入「some_title」電子表格。以下是上述代碼中引用的功能。

public static WorksheetEntry fetchGoogleWorksheet(SpreadsheetEntry spreadsheet, string worksheet_title) 
{ 
    WorksheetFeed wsFeed = spreadsheet.Worksheets; 
    WorksheetEntry worksheet = null; 

    foreach (WorksheetEntry entry in wsFeed.Entries) 
    { 
     worksheet = entry; 
     if (entry.Title.Text == worksheet_title) 
     { 
      Console.WriteLine(DateTime.Now.ToString("HH:mm") + ": Worksheet found on Google Drive."); 
      break; 
     } 
    } 

    if (worksheet.Title.Text != worksheet_title) 
    { 
     return null; 
    } 

    return worksheet; 
} 

public static SpreadsheetEntry fetchGoogleSpreadSheetEntry(SpreadsheetsService service, string spreadsheet_title) 
{ 
    Console.WriteLine(DateTime.Now.ToString("HH:mm") + ": Looking for spreadsheet on Google Drive."); 
    SpreadsheetQuery query = new SpreadsheetQuery(); 
    SpreadsheetFeed feed; 

    feed = service.Query(query); 

    SpreadsheetEntry spreadsheet = null; 
    // Iterate through all of the spreadsheets returned 
    foreach (SpreadsheetEntry entry in feed.Entries) 
    { 
     // Print the title of this spreadsheet to the screen 
     spreadsheet = entry; 
     if (entry.Title.Text == spreadsheet_title) 
     { 
      Console.WriteLine(DateTime.Now.ToString("HH:mm") + ": Spreadsheet found on Google Drive."); 
      Console.WriteLine(DateTime.Now.ToString("HH:mm") + ": Looking for worksheet in spreadsheet."); 
      break; 
     } 
    } 

    if (spreadsheet.Title.Text != spreadsheet_title) 
    { 
     return null; 
    } 
    return spreadsheet; 

    } 

我希望能夠獲取到我想添加到電子表格中的工作表,並將其添加到電子表格中。這是行不通的。上面的代碼在目標電子表格中創建(正確標題的)工作表,但不傳輸工作表的任何內容。

有什麼辦法讓它正確傳輸內容?

+1

我能想到的是批量更新。 (這意味着應對非常細胞)。或谷歌應用腳​​本有一個命令來做到這一點。您可以通過HTML服務調用Google應用程序腳本。 – eddyparkinson

+0

@eddyparkinson我最初使用批量更新,但結果不可靠。我現在正在使用Apps腳本。我會將它作爲回答後發 –

回答

1

在嘗試了幾種不同的方式之後,最可靠的方法竟然是Google Apps Scripting。一般而言,我的解決方案包含一個Google Apps腳本,該腳本由我的C#應用​​程序通過execution API調用。以下是一些代碼示例,演示了所有這些如何一起工作。

因此,這裏的谷歌應用程序腳本,從一個工作表移動內容到另一個:

function copyWorksheet(destinationSpreadsheetId, destinationWorksheetTitle, originSpreadsheetId, originWorksheetTitle) { 

    // Spreadsheet where new data will go: 
    var dss = SpreadsheetApp.openById(destinationSpreadsheetId); 

    // Spreadsheet where new data is coming from: 
    var oss = SpreadsheetApp.openById(originSpreadsheetId); 

    // Worksheet containing new data: 
    var dataOriginWorksheet = oss.getSheetByName(originWorksheetTitle); 

    // Worksheet whose data will be 'overwritten': 
    var expiredWorksheet = dss.getSheetByName(destinationWorksheetTitle); 

    // If a spreadsheet only has one worksheet, deleting that worksheet causes an error. 
    // Thus we need to know whether the expired worksheet is the only worksheet in it's parent spreadsheet. 
    var expiredWorksheetIsAlone = dss.getNumSheets() == 1 && expiredWorksheet != null; 

    // Delete the expired worksheet if there are other worksheets: 
    if (expiredWorksheet != null && !expiredWorksheetIsAlone) 
    dss.deleteSheet(expiredWorksheet); 

    // Otherwise, rename it to something guaranteed not to clash with the new sheet's title: 
    if(expiredWorksheetIsAlone) 
    expiredWorksheet.setName(dataOriginWorksheet.getName() + destinationWorksheetTitle); 

    // Copy the new data into it's rightful place, and give it it's rightful name. 
    dataOriginWorksheet.copyTo(dss).setName(destinationWorksheetTitle); 

    // Since there are now definitely 2 worksheets, it's safe to delete the expired one. 
    if(expiredWorksheetIsAlone) 
    dss.deleteSheet(expiredWorksheet); 

    // Make sure our changes are applied ASAP: 
    SpreadsheetApp.flush(); 

    return "finished"; 
} 

這是我最後使用的代碼,這是一個嚴重的精簡版,爲什麼有兩個表格ID字段。這意味着兩個工作表是否在同一電子表格中並不重要。

溶液的C#部分看起來像這樣:

// We need these for the method below 
using Google.Apis.Script.v1; 
using Google.Apis.Script.v1.Data; 

...  

public static bool copyWorksheet(ScriptService scriptService, string destinationSpreadsheetId, string destinationWorksheetTitle, string originSpreadsheetId, string originWorksheetTitle) 
    { 
    // You can get the script ID by going to the script in the 
    // Google Apps Scripts Editor > Publish > Deploy as API executable... > API ID 
    string scriptId = "your-apps-script-id"; 

    ExecutionRequest request = new ExecutionRequest(); 
    request.Function = "copyWorksheet"; 
    IList<object> parameters = new List<object>(); 

    parameters.Add(destinationSpreadsheetId); 
    parameters.Add(destinationWorksheetTitle); 
    parameters.Add(originSpreadsheetId); 
    parameters.Add(originWorksheetTitle);    

    request.Parameters = parameters; 

    ScriptsResource.RunRequest runReq = scriptService.Scripts.Run(request, scriptId); 

    try 
    { 
     Operation op = runReq.Execute(); 

     if (op.Error != null) 
     { 
     Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + " The Apps script encountered an error"); 
     // The API executed, but the script returned an error. 

     IDictionary<string, object> error = op.Error.Details[0]; 
     Console.WriteLine("Script error message: {0}", error["errorMessage"]); 
     if (error.ContainsKey("scriptStackTraceElements")) 
     { 

      // There may not be a stacktrace if the script didn't 
      // start executing. 
      Console.WriteLine("Script error stacktrace:"); 
      Newtonsoft.Json.Linq.JArray st = (Newtonsoft.Json.Linq.JArray)error["scriptStackTraceElements"]; 
      foreach (var trace in st) 
      { 
       Console.WriteLine(
       "\t{0}: {1}", 
       trace["function"], 
       trace["lineNumber"]); 
      } 

      } 
     } 
     else 
     { 
      // The result provided by the API needs to be cast into 
      // the correct type, based upon what types the Apps 
      // Script function returns. Here, the function returns 
      // an Apps Script Object with String keys and values. 
      // It is most convenient to cast the return value as a JSON 
      // JObject (folderSet). 

      return true; 

     } 
     } 
     catch (Google.GoogleApiException e) 
     { 
     // The API encountered a problem before the script 
     // started executing. 
     Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + " Could not call Apps Script"); 
     } 

     return false; 
    } 

... 

上述2塊的代碼,當一起使用時,完美地解決了這個問題。執行時間在不同的數據量之間沒有很大差異,並且傳輸沒有數據損壞。

+1

非常好的答案! – Mogsdad

相關問題