Download files from Google Drive with C# 14


Please Share

google drive Are you working on an application that needs download files from a users Google Drive account. I am going to show you how to do that using C# and the Google .Net Client library.

Prerequisite

The first thing we will need to do is import the Google Drive API v3 NuGet package

Install-Package Google.Apis.Drive.v3

Authenticate

File list is private data which means it is owned by a user. In order to access it you must be authenticated to that user. We also need a users permission to download the file once we have listed it.


        /// <summary>
        /// This method requests Authentcation from a user using Oauth2.  
        /// Credentials are stored in System.Environment.SpecialFolder.Personal
        /// Documentation https://developers.google.com/accounts/docs/OAuth2
        /// </summary>
        /// <param name="clientSecretJson">Path to the client secret json file from Google Developers console.</param>
        /// <param name="userName">Identifying string for the user who is being authentcated.</param>
        /// <returns>DriveService used to make requests against the Drive API</returns>
        public static DriveService AuthenticateOauth(string clientSecretJson, string userName)
        {
            try
            {
                if (string.IsNullOrEmpty(userName))
                    throw new ArgumentNullException("userName");
                if (string.IsNullOrEmpty(clientSecretJson))
                    throw new ArgumentNullException("clientSecretJson");
                if (!File.Exists(clientSecretJson))
                    throw new Exception("clientSecretJson file does not exist.");

                // These are the scopes of permissions you need. It is best to request only what you need and not all of them
                string[] scopes = new string[] { DriveService.Scope.DriveReadonly};         	//View the files in your Google Drive                                                 
                UserCredential credential;
                using (var stream = new FileStream(clientSecretJson, FileMode.Open, FileAccess.Read))
                {
                    string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
                    credPath = Path.Combine(credPath, ".credentials/", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);

                    // Requesting Authentication or loading previously stored authentication for userName
                    credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
                                                                             scopes,
                                                                             userName,
                                                                             CancellationToken.None,
                                                                             new FileDataStore(credPath, true)).Result;
                }

                // Create Drive API service.
                return new DriveService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Drive Oauth2 Authentication Sample"
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine("Create Oauth2 account DriveService failed" + ex.Message);
                throw new Exception("CreateServiceAccountDriveFailed", ex);
            }
        }

File.List

My tutorial on searching for files with the file.list method contains the code you will need to list files. I wont be adding that here i recommend you check out that tutorial first. Search files with Google Drive with C#.


Download File

Downloading a file is done with the Files.get method and a media downloader from the client library to download your file.


 private static void DownloadFile(Google.Apis.Drive.v3.DriveService service, Google.Apis.Drive.v3.Data.File file, string saveTo)
        {

            var request = service.Files.Get(file.Id);
            var stream = new System.IO.MemoryStream();

            // Add a handler which will be notified on progress changes.
            // It will notify on each chunk download and when the
            // download is completed or failed.
            request.MediaDownloader.ProgressChanged += (Google.Apis.Download.IDownloadProgress progress) =>
               {
                   switch (progress.Status)
                   {
                       case Google.Apis.Download.DownloadStatus.Downloading:
                           {
                               Console.WriteLine(progress.BytesDownloaded);
                               break;
                           }
                       case Google.Apis.Download.DownloadStatus.Completed:
                           {
                               Console.WriteLine("Download complete.");
                               SaveStream(stream, saveTo);
                               break;
                           }
                       case Google.Apis.Download.DownloadStatus.Failed:
                           {
                               Console.WriteLine("Download failed.");
                               break;
                           }
                   }
               };
            request.Download(stream);

        }

Assuming that the file download succeeds then we save the file to the hard drive.


private static void SaveStream(System.IO.MemoryStream stream, string saveTo)
{
     using (System.IO.FileStream file = new System.IO.FileStream(saveTo, System.IO.FileMode.Create, System.IO.FileAccess.Write))
        {
         stream.WriteTo(file);
         }
}

Putting it all together

By using file.list I can search for the files that I am interested in then loop though each one downloading it.


// Connect to Google
var service = GoogleSamplecSharpSample.Drivev3.Auth.Oauth2Example.AuthenticateOauth(@"[Location of the Json cred file]", "test");
//List the files with the word 'make' in the name.
var files = DriveListExample.ListFiles(service, 
                 new DriveListExample.FilesListOptionalParms() { Q = "name contains 'Make'" , Fields= "*"});
foreach (var item in files.Files)
     {
     // download each file
     DriveDownload.Download(service, item, string.Format(@"C:\FilesFromGoogleDrive\{0}",item.Name));
      }

Conclusion

Downloading files from Google drive can be quite useful using media downloader makes it quite simple. I have considered setting up a windows service to mirror my google drive account down to my PC and back up to Google Drive. This way i can keep the data backed up and in sync.

Please Share


Linda Lawton

About Linda Lawton

My name is Linda Lawton I have more than 20 years experience working as an application developer and a database expert. I have also been working with Google APIs since 2012 and I have been contributing to the Google .Net client library since 2013. In 2013 I became a a Google Developer Experts for Google Analytics.


Leave a comment

Your email address will not be published. Required fields are marked *

14 thoughts on “Download files from Google Drive with C#

  • Manuel

    Hello Linda!
    How does this work with the file.export method? I used: var request = service.Files.Export(fileId, “application/vnd.openxmlformats-officedocument.spreadsheetml.sheet”);. Shouldnt the file get an extension by itsfel then or am I mistaken?

      • Manuel

        Hello Linda, its been a while but today I noticed a problem. When downloading larger files (well 80MB>, isnt that large) the downlaod wont complete correctly. I tested it with several zip files: 100mb, 200mb, 512mb and 1gb. 100mb and 200mb just work fine but the other two dont. When trying to download the 512mb zip file it stops at about 320 000 000 bytes, writes “Downlaod complete” in the console and goes on to the next file. Obviously the file didnt get saved on my HDD.
        Do you have any clue what could be causing this?

          • Manuel

            Actually the problem is a bit different now. I didn’t change much in my code but for now this works, except files that are larger than 2GB (stops at about 2040MB). I read that this seems to be a common issue because this is a limitation at googles site, right? There must be a way to bypass that, except for installing the desktop app.

          • Linda Lawton
            Linda Lawton Post author

            I am not sure if its a limitation but its something i have heard of. The Google drive api doesn’t appear to like large files. Make sure you are using resumable download or upload then you can pick up where it failed.

  • Kalyani S

    Hi,

    I have written a code to Upload and Download files using from Google Drive.

    It is working very fine in Local, but when I deploy it on Server it is giving error in Download part where we use “GoogleWebAuthorizationBroker.AuthorizeAsync” method to get Service credentials. It gives following error

    “Server Error in ‘/’ Application.
    ________________________________________
    Access is denied
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.ComponentModel.Win32Exception: Access is denied

    Source Error:
    An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

    Stack Trace:

    [Win32Exception (0x80004005): Access is denied]
    Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +185
    Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task) +114
    Google.Apis.Auth.OAuth2.d__1.MoveNext() +483

    [AggregateException: One or more errors occurred.]
    System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) +5836036
    GoogleDriveRestAPI_v3.Models.GoogleDriveFilesRepository.GetService() +467
    GoogleDriveRestAPI_v3.Models.GoogleDriveFilesRepository.DownloadGoogleFile(String fileId) +35
    GoogleDriveRestAPI_v3.Controllers.HomeController.DownloadFile(String id) +356
    System.Web.Mvc.c__DisplayClass1.b__0(ControllerBase controller, Object[] parameters) +15
    System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +242
    System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39
    System.Web.Mvc.Async.AsyncControllerActionInvoker.b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +12
    System.Web.Mvc.Async.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult) +139
    System.Web.Mvc.Async.AsyncInvocationWithFilters.b__3d() +112
    System.Web.Mvc.Async.c__DisplayClass46.b__3f() +452
    System.Web.Mvc.Async.c__DisplayClass33.b__32(IAsyncResult asyncResult) +15
    System.Web.Mvc.Async.c__DisplayClass2b.b__1c() +37
    System.Web.Mvc.Async.c__DisplayClass21.b__1e(IAsyncResult asyncResult) +241
    System.Web.Mvc.Controller.b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +29
    System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +111
    System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53
    System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +19
    System.Web.Mvc.MvcHandler.b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +51
    System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +111
    System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +606
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288

    ________________________________________
    Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.33440”
    Due to this error TokenResponse file is not getting created using following code

    credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
    GoogleClientSecrets.Load(stream).Secrets,
    Scopes,
    “user”,
    CancellationToken.None,
    new FileDataStore(FilePath, true)
    ).Result;

    Please suggest solution so that this code works on Server after deploying in IIS.