我已经在我的 C# 程序中实现了 Google Drive 增量更改逻辑。
var request = service.Changes.List(pageToken);
request.Spaces = "drive";
request.IncludeRemoved = false;
request.PageSize = 100;
request.Fields = "changes(file (id,name,mimeType,createdTime,modifiedTime,size,parents,trashed),removed,kind,type),nextPageToken,newStartPageToken";
var changes = request.Execute();
当我在 Google 云端硬盘中上传文件夹(包含一些文件)时,我会获取所有文件和文件夹的增量变化。
但是,当我通过 Google 云端硬盘中的移动到操作将该文件夹(包含文件)移至主文件夹时,我得到的增量更改仅包含我移动到主文件夹的文件夹,而我移动的该文件夹中的文件则不包含在内。报告增量变化。
这就是 Google Drive 增量更改的设计方式吗? 如果是,如何确定增量更改中报告的文件夹是否已移动,以便我可以编写自定义逻辑以将该文件夹中的文件视为移动导致的增量更改?
请推荐
谢谢!
为了进行调查,我在 Google Drive 上设置了一个小“游乐场”,以便在我的轮询循环中注入一些更改。当我用手将Folder-To-Move从Folder-A拖动到Folder-B时,我们可以看到它“移动”,对吗?
但从某种意义上说,这是由于 Folder-To-Move 刚刚有了一个新父级而带来的幻觉。
如何识别增量更改中报告的文件夹是否已被移动?
当我们得到文件夹已被修改的
Change
时,我发现的第一件事可能会有所帮助,那就是迭代其父级以获得完整路径。接下来发生的事情有点难以回答,因为您要根据只有您知道的规则和位置来维护本地文件系统的同步。但首先,您可以将相对于 cloud 根的路径与相对于 local 根的本地文件夹进行比较,并以这种方式进行一些检测。
switch (change.File.MimeType)
{
case "application/vnd.google-apps.folder":
var parent = change.File.Parents.FirstOrDefault();
var builder = new List<string> { change.File.Name };
while (parent is string pid)
{
FilesResource.GetRequest @get = DriveService.Files.Get(pid);
@get.Fields = "*";
var file = @get.Execute();
builder.Add(file.Name);
parent = file.Parents?.FirstOrDefault();
}
builder.Reverse();
var folderPath = string.Join($"{Path.DirectorySeparatorChar}", builder);
Debug.WriteLine(folderPath);
break;
case "application/vnd.google-apps.document":
break;
default:
break;
}
但是移动文件夹中的文档呢?它是否真的“移动”了它是否有了新的父母?不,还没有,因此没有更改通知。但是,如果 has 在 的意义上移动了,那么它现在是否有不同的相对路径?但如果您需要该信息,您可以以相同的方式迭代它。换句话说,使用文件夹的
change.FileID
,您可以(例如)递归查询其所有子元素(及其子元素...),然后从该集合中从子元素迭代返回以获取其新的相对元素路径。
希望这能给您一个开始。
完整上下文
我希望我没有遗漏任何重要细节,但为了以防万一,这是整个轮询循环。
public CancellationTokenSource CancelPolling { get; private set; } = new CancellationTokenSource();
private async Task CheckForChangesAtInterval()
{
TimeSpan INTERVAL = TimeSpan.FromSeconds(15); // Short, for debug purposes.
var changes = DriveService.Changes;
// DEBUG ONLY. Will only detect changes since the start of this app.
var pageToken =
changes
.GetStartPageToken()
.Execute()
.StartPageTokenValue;
while (!CancelPolling.IsCancellationRequested)
{
pageToken = await getChanges(pageToken);
await Task.Delay(INTERVAL);
}
}
private async Task<string> getChanges(string pageToken)
{
ChangeList rsp = null;
while (pageToken != null)
{
if (CancelPolling.IsCancellationRequested) break;
var request = DriveService.Changes.List(pageToken);
request.Spaces = "drive";
request.Fields = "*";
try
{
await Task.Run(() =>
{
rsp = request.Execute();
});
}
catch (Exception ex)
{
Debug.Fail(ex.Message);
break;
}
foreach (var change in rsp.Changes)
{
if (change.Removed == true)
{
Debug.Assert(
change.File == null,
"Expecting that a deleted id has no usable metadata.");
Debug.WriteLine(
$@"ADVISORY: Cloud file id {change.FileId} has been DELETED.");
}
else
{
switch (change.File.MimeType)
{
case "application/vnd.google-apps.folder":
var parent = change.File.Parents.FirstOrDefault();
var builder = new List<string> { change.File.Name };
while (parent is string pid)
{
FilesResource.GetRequest @get = DriveService.Files.Get(pid);
@get.Fields = "*";
var file = @get.Execute();
builder.Add(file.Name);
parent = file.Parents?.FirstOrDefault();
}
builder.Reverse();
var folderPath = string.Join($"{Path.DirectorySeparatorChar}", builder);
Debug.WriteLine($"Folder `{change.FileId}` has changed.");
Debug.WriteLine($"{folderPath}\n");
break;
case "application/vnd.google-apps.document": { /*...*/ } break;
default: { /*...*/ } break;
}
if (change.File.Trashed == true) { /*...*/ }
else { /*...*/ }
}
if (CancelPolling.IsCancellationRequested) break;
}
if (rsp.NewStartPageToken != null)
{
// Last page, save this token for the next polling interval
break;
}
pageToken = rsp.NextPageToken;
}
return string.IsNullOrWhiteSpace(rsp?.NewStartPageToken) ? pageToken : rsp?.NewStartPageToken;
}