sexta-feira, 14 de abril de 2017

Utilizando a API do Google Drive no C# e VB.NET - Parte 3

Obviamente, o escopo “readonly” não permite a criação ou exclusão de itens. Se quisermos alterar itens no nosso Google Drive, teremos que alterar o escopo para “Scope.Drive” na hora de criarmos as credenciais (método “Autenticar“). Só não esqueça de deletar o subdiretório “credential” dentro da pasta “bin/debug“, uma vez que as credenciais com o escopo menor já estarão cacheadas nesse diretório e a autenticação continuará utilizando esse escopo “readonly” caso você não delete essa pasta para forçar uma nova autenticação.
Depois de seguir todos esses passos, ao executarmos novamente a aplicação, este será o resultado no nosso Google Drive:
Só tome cuidado, pois outra coisa estranha do Google Drive é que ele não liga para nomes repetidos. Ou seja, se você executar esse código duas vezes, ele criará duas vezes o mesmo diretório sem problema algum:

Deletando arquivos ou diretórios

A próxima operação que vamos conferir neste artigo é a exclusão de itens do nosso Google Drive. A exclusão em si é muito simples. Basta criarmos e executarmos um request para o método “Files.Delete” passando o “id” do item a ser deletado. A parte mais difícil está em descobrir o “id” do item que estamos querendo deletar.
Para descobrirmos o “id” de um item através do seu nome, nós temos que basicamente executar um comando de listagem filtrado, requisitando somente o “id” dos itens que tenham um nome específico. Vamos implementar primeiramente um método que retornará esses “ids“:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// C#
private static string[] ProcurarArquivoId(Google.Apis.Drive.v3.DriveService servico, string nome, bool procurarNaLixeira = false)
{
    var retorno = new List<string>();
 
    var request = servico.Files.List();
    request.Q = string.Format("name = '{0}'", nome);
    if (!procurarNaLixeira)
    {
        request.Q += " and trashed = false";
    }
    request.Fields = "files(id)";
    var resultado = request.Execute();
    var arquivos = resultado.Files;
 
    if (arquivos != null && arquivos.Any())
    {
        foreach (var arquivo in arquivos)
        {
            retorno.Add(arquivo.Id);
        }
    }
 
    return retorno.ToArray();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
' VB.NET
Private Function ProcurarArquivoId(Servico As Google.Apis.Drive.v3.DriveService, Nome As String, Optional ProcurarNaLixeira As Boolean = False) As String()
    Dim Retorno = New List(Of String)()
 
    Dim Request = Servico.Files.List()
    Request.Q = String.Format("name = '{0}'", Nome)
    If Not ProcurarNaLixeira Then
        Request.Q += " and trashed = false"
    End If
    Request.Fields = "files(id)"
    Dim Resultado = Request.Execute()
    Dim Arquivos = Resultado.Files
 
    If Arquivos IsNot Nothing AndAlso Arquivos.Any() Then
        For Each Arquivo In Arquivos
            Retorno.Add(Arquivo.Id)
        Next
    End If
 
    Return Retorno.ToArray()
End Function
Note que o método já está preparado para procurar itens na lixeira também. No nosso caso, nós não precisaremos dessa opção, mas já é bom implementá-la caso precisemos mais adiante.
Agora que já conseguimos uma lista com os “ids” dos itens, a exclusão fica muito simples:
1
2
3
4
5
6
7
8
9
10
11
12
13
// C#
private static void DeletarItem(Google.Apis.Drive.v3.DriveService servico, string nome)
{
    var ids = ProcurarArquivoId(servico, nome);
    if (ids != null && ids.Any())
    {
        foreach (var id in ids)
        {
            var request = servico.Files.Delete(id);
            request.Execute();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
' VB.NET
Private Sub DeletarItem(Servico As Google.Apis.Drive.v3.DriveService, Nome As String)
    Dim Ids = ProcurarArquivoId(Servico, Nome)
    If Ids IsNot Nothing AndAlso Ids.Any() Then
        For Each Id In Ids
            Dim Request = Servico.Files.Delete(Id)
            Request.Execute()
        Next
    End If
End Sub
Por fim, a chamada para deletarmos o diretório “NovoDiretorio” que criamos anteriormente ficaria da seguinte maneira:
1
2
3
4
5
6
// C#
Console.Clear();
Console.WriteLine("Deletar item");
DeletarItem(servico, "NovoDiretorio");
Console.WriteLine("Fim Deletar item");
Console.ReadLine();
1
2
3
4
5
6
' VB.NET
Console.Clear()
Console.WriteLine("Deletar item")
DeletarItem(Servico, "NovoDiretorio")
Console.WriteLine("Fim Deletar item")
Console.ReadLine()

Fazendo o upload de arquivos

O upload de arquivos no Google Drive parece ser bem tranquilo à primeira vista. Temos à nossa disposição o método “Files.Create” que recebe uma instância de “File” (com as informações de nome e tipo do arquivo), a Stream com o conteúdo do arquivo e o seu “mime type“.
Se você não sabe o que é “mime type“, ele é um identificador que serve para definir o tipo de um arquivo. Por exemplo, “text/plain” é o “mime type” para arquivos texto, “image/jpeg” é o “mime type” para imagens jpg, e por aí vai. Esse tipo de identificador é muito utilizado em aplicações web na hora de fazer uma requisição.
Para nos ajudar com o cálculo do “mime type” no nosso projeto de exemplo, vamos utilizar a biblioteca MimeTypeMap, que é basicamente um dicionário gigante de “mime types” por extensão de arquivo. Adicione uma referência a essa biblioteca procurando por “MediaTypeMap” no NuGet:
Em seguida, vamos implementar o método que fará o upload do arquivo:
1
2
3
4
5
6
7
8
9
10
11
12
// C#
private static void Upload(Google.Apis.Drive.v3.DriveService servico, string caminhoArquivo)
{
    var arquivo = new Google.Apis.Drive.v3.Data.File();
    arquivo.Name = System.IO.Path.GetFileName(caminhoArquivo);
    arquivo.MimeType = MimeTypes.MimeTypeMap.GetMimeType(System.IO.Path.GetExtension(caminhoArquivo));
    using (var stream = new System.IO.FileStream(caminhoArquivo, System.IO.FileMode.Open, System.IO.FileAccess.Read))
    {
        var request = servico.Files.Create(arquivo, stream, arquivo.MimeType);
        request.Upload();
    }
}
1
2
3
4
5
6
7
8
9
10
' VB.NET
Private Sub Upload(Servico As Google.Apis.Drive.v3.DriveService, CaminhoArquivo As String)
    Dim Arquivo = New Google.Apis.Drive.v3.Data.File()
    Arquivo.Name = System.IO.Path.GetFileName(CaminhoArquivo)
    Arquivo.MimeType = MimeTypes.MimeTypeMap.GetMimeType(System.IO.Path.GetExtension(CaminhoArquivo))
    Using Stream = New System.IO.FileStream(CaminhoArquivo, System.IO.FileMode.Open, System.IO.FileAccess.Read)
        Dim Request = Servico.Files.Create(Arquivo, Stream, Arquivo.MimeType)
        Request.Upload()
    End Using
End Sub
Pronto! Para fazermos o upload de um arquivo chamado “arquivo.txt” que se encontra na pasta “bin/debug” da nossa aplicação, o código que teríamos que colocar no bloco “using” seria este:
1
2
3
4
5
6
// C#
Console.Clear();
Console.WriteLine("Upload");
Upload(servico, "arquivo.txt");
Console.WriteLine("Fim Upload");
Console.ReadLine();
1
2
3
4
5
6
' VB.NET
Console.Clear()
Console.WriteLine("Upload")
Upload(Servico, "arquivo.txt")
Console.WriteLine("Fim Upload")
Console.ReadLine()
E este seria o resultado no nosso Google Drive:
Tudo isso funciona muito bem da primeira vez que executarmos esse código. Porém, se executarmos uma segunda vez, ao invés do arquivo ser substituído, um novo “arquivo.txt” será criado no nosso Google Drive. É simplesmente incompreensível o fato do Google Drive trabalhar dessa maneira, possibilitando que existam dois arquivos com o mesmo nome no mesmo diretório. Mas, enfim, é assim que ele funciona.
Para corrigirmos esse problema (ou seja, substituirmos o arquivo caso ele já exista), teremos que detectar se o arquivo já existe e, caso positivo, temos que utilizar o método “Files.Update“, ao invés de “Files.Create“:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// C#
private static void Upload(Google.Apis.Drive.v3.DriveService servico, string caminhoArquivo)
{
    var arquivo = new Google.Apis.Drive.v3.Data.File();
    arquivo.Name = System.IO.Path.GetFileName(caminhoArquivo);
    arquivo.MimeType = MimeTypes.MimeTypeMap.GetMimeType(System.IO.Path.GetExtension(caminhoArquivo));
 
    using (var stream = new System.IO.FileStream(caminhoArquivo, System.IO.FileMode.Open, System.IO.FileAccess.Read))
    {
        var ids = ProcurarArquivoId(servico, arquivo.Name);
        Google.Apis.Upload.ResumableUpload<Google.Apis.Drive.v3.Data.File, Google.Apis.Drive.v3.Data.File> request;
 
        if (ids == null || !ids.Any())
        {
            request = servico.Files.Create(arquivo, stream, arquivo.MimeType);
        }
        else
        {
            request = servico.Files.Update(arquivo, ids.First(), stream, arquivo.MimeType);
        }
 
        request.Upload();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
' VB.NET
Private Sub Upload(Servico As Google.Apis.Drive.v3.DriveService, CaminhoArquivo As String)
    Dim Arquivo = New Google.Apis.Drive.v3.Data.File()
    Arquivo.Name = System.IO.Path.GetFileName(CaminhoArquivo)
    Arquivo.MimeType = MimeTypes.MimeTypeMap.GetMimeType(System.IO.Path.GetExtension(CaminhoArquivo))
 
    Using Stream = New System.IO.FileStream(CaminhoArquivo, System.IO.FileMode.Open, System.IO.FileAccess.Read)
        Dim Ids = ProcurarArquivoId(Servico, Arquivo.Name)
        Dim Request As Google.Apis.Upload.ResumableUpload(Of Google.Apis.Drive.v3.Data.File, Google.Apis.Drive.v3.Data.File)
 
        If Ids Is Nothing OrElse Not Ids.Any() Then
            Request = Servico.Files.Create(Arquivo, Stream, Arquivo.MimeType)
        Else
            Request = Servico.Files.Update(Arquivo, Ids.First(), Stream, Arquivo.MimeType)
        End If
 
        Request.Upload()
    End Using
End Sub
Agora sim. Se executarmos esse código mais de uma vez, ele simplesmente substituirá o “arquivo.txt” já existente no nosso Google Drive, utilizando o conteúdo da nova “Stream“.


Um comentário:

  1. Bom dia,
    Fiz os passos, porem o meu arquivo não esta sendo atualizado.
    Alguém pode me ajudar

    ResponderExcluir