使用 Javascript 在 Google 驱动器中创建树状目录结构
Create a tree directory structure in Google Drive with Javascript
我正在尝试使用 Google 驱动器 Javascript API 构建一个简单的目录树。我想我应该检查文件夹是否存在并创建它,然后最终添加它的子文件夹。所以我在下面构建了这些函数:
function createFolder(name, parent) {
if (!parent) parent = 'root';
var fileMetadata = {
'name': name,
'mimeType': 'application/vnd.google-apps.folder',
'parent': parent
};
gapi.client.drive.files.create({
'resource': fileMetadata,
'fields': 'id'
}).then(function (res) {console.log(res); return res.result['id'];}, function (err) {console.log(err); return null;});
}
function getFolder(name, parent) {
if (!parent) parent = 'root';
gapi.client.drive.files.list({
'pageSize': 1,
'fields': "nextPageToken, files(id, name, mimeType, parents)",
'q': "mimeType='application/vnd.google-apps.folder' \
and '" + parent + "' in parents \
and name = '" + name + "'"
}).then(
function (res) {console.log(res); var ret = res.result.files.length > 0 ? res.result.files[0]['id'] : null; return ret;},
function (err) {console.log(err);return null;}
);
}
function checkPhrFolder() {
var phr = getFolder('Personal Health Record');
console.log('get folder: '+phr);
if (!phr) {
console.log('creating ...');
phr = createFolder('Personal Health Record');
}
}
这只是检查我的第一个目录是否存在,如果不存在,则创建它。问题是调用是异步的(使用 "then promises")所以函数不会 return 任何东西(例如 getFolder 从不 returns 文件夹的 id),所以我想知道什么鉴于异步调用的性质,是递归创建多个文件夹的正确方法。我是否需要放置一个始终被调用并选择下一步做什么的控制器函数?
谢谢!
在这种情况下,我发现新的异步 javascript 语法更容易理解。
方法
你是 运行 函数 checkPhrFolder
同步,而其他两个依赖于异步 api 调用的函数正在等待 promise 解析以便 return一个值。当您在同步 checkPhrFolder
执行中评估它时,这将导致 phr 未定义。
基本上,要使其正常工作,您应该链接您的承诺解决方案,以便正确使用它们的 return 值。新的 javascript 语法使您能够用更少的代码行编写异步函数。
使用关键字 async
和 await
,您可以控制承诺解析流程,并且基本上等待异步函数到 return,然后再进行适当的分配。
例子
async function createFolder(name, parent) {
if (!parent) parent = 'root';
var fileMetadata = {
'name': name,
'mimeType': 'application/vnd.google-apps.folder',
'parent': parent
};
const res = await gapi.client.drive.files.create({
'resource': fileMetadata,
'fields': 'id'
});
return res.result['id'];
}
async function getFolder(name, parent) {
if (!parent) parent = 'root';
const res = await gapi.client.drive.files.list({
'pageSize': 1,
'fields': "nextPageToken, files(id, name, mimeType, parents)",
'q': "mimeType='application/vnd.google-apps.folder' \
and '" + parent + "' in parents \
and name = '" + name + "'"
});
return res.result.files.length > 0 ? res.result.files[0]['id'] : null;
}
async function checkPhrFolder() {
var phr = await getFolder('Personal Health Record');
console.log('get folder: '+phr);
if (!phr) {
console.log('creating ...');
phr = createFolder('Personal Health Record');
}
}
这样您的 checPhrFolder
函数将几乎和以前一样容易阅读。当您将在同步上下文中使用 checkPhrFolder
函数时,您将能够将其 return 值包装在同一个 then/catch
语句中。
参考
我使用传统方式构建我的 dirs populator,如下所示:
var phrFolderManager = {
currentName: null,
currentParent: null,
folders: {
'/PersonalHealthRecord': null,
'/PersonalHealthRecord/Some': null,
'/PersonalHealthRecord/Dirs': null,
'/PersonalHealthRecord/ForMe': null
},
addFolder: function (name, id) {
this.folders[name] = id;
},
getFolderId: function (name) {
return this.folders[name];
},
refresh: function (forced) {
console.log('next step ' + forced + ' ...');
console.log(this.folders);
// find the next null in our folder list
for (k in this.folders) {
this.currentName = k;
if (!this.folders[k]) {
var parts = k.split('/');
if (parts.length == 2) {
// this is our base dir inside root
if (forced) {
this.createFolder(parts[1], 'root');
} else {
this.getFolder(parts[1], 'root');
}
} else {
var parent = parts.slice(0, -1).join('/');
var name = parts[parts.length - 1];
var parent_id = this.folders[parent];
if (forced) {
this.createFolder(name, parent_id);
} else {
this.getFolder(name, parent_id);
}
}
break;
} else {
console.log('... defined as ' + this.folders[k]);
}
}
},
getFolder: function (name, parent) {
//M.toast({html: 'check da pasta '+name,classes: 'rounded'});
if (!parent) parent = 'root';
this.currentParent = parent;
console.log('getFolder ' + name + ' ' + parent);
var res = gapi.client.drive.files.list({
'pageSize': 1,
'fields': "files(id, name, mimeType, parents)",
'q': "mimeType='application/vnd.google-apps.folder' \
and '" + parent + "' in parents \
and name = '" + name + "'"
}).then(
function (res) {
console.log(res);
if (res.result.files.length > 0) {
this.folders[this.currentName] = res.result.files[0]['id'];
this.refresh(false);
} else {
this.refresh(true);
}
},
function (err) {
console.log('error in getFolder: ' + err)
},
this
);
},
createFolder: function (name, parent) {
M.toast({
html: 'criando pasta ' + name,
classes: 'rounded'
});
if (!parent) parent = 'root';
console.log('createFolder ' + name + ' ' + parent);
var fileMetadata = {
'name': name,
'mimeType': 'application/vnd.google-apps.folder',
'parents': [parent]
};
gapi.client.drive.files.create({
'resource': fileMetadata,
'fields': 'id'
}).then(
function (res) {
console.log(res);
this.folders[this.currentName] = res.result['id'];
this.refresh();
},
function (err) {
alert('Problem creating ' + this.currentName + ' PersonalHealthRecord structure');
},
this
);
}
};
稍微调整一下,@Alessandro 的解决方案对我有用:
- 为了便于阅读,我颠倒了方法的顺序。
- 我合并了一个 FOR 循环,因为我的文件结构将深入许多文件夹。循环通过包含文件路径中的文件夹名称的字符串数组。
- 我注意到 (!parent) 没有正确返回,因为它是“未定义”,而不是“空”。此外,当找不到现有文件夹时期待“null”是至关重要的,所以我将 parentId 默认为“root”,因为我知道我的第一个文件夹将始终位于根目录
- 变量 newFolderId 保存 found/created 文件夹的值,并传递给 parentId 用于 FOR 循环的下一次迭代
- 最后,我将“'parent': parent”更新为“'parents' : [parent]”。那个“s”和那些括号似乎是必要的,否则每个创建的文件夹都放在根目录下。
async function buildFilePath() {
console.log("buildFilePath()");
var parentId = "root";
for (let i = 0; i < filePath.length; i++) {
var folderName = filePath[i];
newFolderId = await getFolder(folderName, parentId);
console.log(folderName + " id is " + newFolderId + ", parentId is " + parentId);
if (newFolderId == null) {
newFolderId = await createFolder(folderName,parentId);
console.log ("created new folder " + folderName + " with Id " + parentId);
} else {
// parentId = newParentId;
console.log (folderName + " already exist, move on to next.");
}
parentId = newFolderId;
}
}
async function getFolder(name, parent) {
const res = await gapi.client.drive.files.list({
'pageSize': 1,
'fields': "nextPageToken, files(id, name, mimeType, parents)",
'q': "mimeType='application/vnd.google-apps.folder' \
and '" + parent + "' in parents \
and name = '" + name + "' \
and trashed = false"
});
return res.result.files.length > 0 ? res.result.files[0]['id'] : null;
}
async function createFolder(name, parent) {
if (!parent) parent = 'root';
var fileMetadata = {
'name': name,
'mimeType': 'application/vnd.google-apps.folder',
'parents': [parent]
};
const res = await gapi.client.drive.files.create({
'resource': fileMetadata,
'fields': 'id'
});
return res.result['id'];
}
我正在尝试使用 Google 驱动器 Javascript API 构建一个简单的目录树。我想我应该检查文件夹是否存在并创建它,然后最终添加它的子文件夹。所以我在下面构建了这些函数:
function createFolder(name, parent) {
if (!parent) parent = 'root';
var fileMetadata = {
'name': name,
'mimeType': 'application/vnd.google-apps.folder',
'parent': parent
};
gapi.client.drive.files.create({
'resource': fileMetadata,
'fields': 'id'
}).then(function (res) {console.log(res); return res.result['id'];}, function (err) {console.log(err); return null;});
}
function getFolder(name, parent) {
if (!parent) parent = 'root';
gapi.client.drive.files.list({
'pageSize': 1,
'fields': "nextPageToken, files(id, name, mimeType, parents)",
'q': "mimeType='application/vnd.google-apps.folder' \
and '" + parent + "' in parents \
and name = '" + name + "'"
}).then(
function (res) {console.log(res); var ret = res.result.files.length > 0 ? res.result.files[0]['id'] : null; return ret;},
function (err) {console.log(err);return null;}
);
}
function checkPhrFolder() {
var phr = getFolder('Personal Health Record');
console.log('get folder: '+phr);
if (!phr) {
console.log('creating ...');
phr = createFolder('Personal Health Record');
}
}
这只是检查我的第一个目录是否存在,如果不存在,则创建它。问题是调用是异步的(使用 "then promises")所以函数不会 return 任何东西(例如 getFolder 从不 returns 文件夹的 id),所以我想知道什么鉴于异步调用的性质,是递归创建多个文件夹的正确方法。我是否需要放置一个始终被调用并选择下一步做什么的控制器函数?
谢谢!
在这种情况下,我发现新的异步 javascript 语法更容易理解。
方法
你是 运行 函数 checkPhrFolder
同步,而其他两个依赖于异步 api 调用的函数正在等待 promise 解析以便 return一个值。当您在同步 checkPhrFolder
执行中评估它时,这将导致 phr 未定义。
基本上,要使其正常工作,您应该链接您的承诺解决方案,以便正确使用它们的 return 值。新的 javascript 语法使您能够用更少的代码行编写异步函数。
使用关键字 async
和 await
,您可以控制承诺解析流程,并且基本上等待异步函数到 return,然后再进行适当的分配。
例子
async function createFolder(name, parent) {
if (!parent) parent = 'root';
var fileMetadata = {
'name': name,
'mimeType': 'application/vnd.google-apps.folder',
'parent': parent
};
const res = await gapi.client.drive.files.create({
'resource': fileMetadata,
'fields': 'id'
});
return res.result['id'];
}
async function getFolder(name, parent) {
if (!parent) parent = 'root';
const res = await gapi.client.drive.files.list({
'pageSize': 1,
'fields': "nextPageToken, files(id, name, mimeType, parents)",
'q': "mimeType='application/vnd.google-apps.folder' \
and '" + parent + "' in parents \
and name = '" + name + "'"
});
return res.result.files.length > 0 ? res.result.files[0]['id'] : null;
}
async function checkPhrFolder() {
var phr = await getFolder('Personal Health Record');
console.log('get folder: '+phr);
if (!phr) {
console.log('creating ...');
phr = createFolder('Personal Health Record');
}
}
这样您的 checPhrFolder
函数将几乎和以前一样容易阅读。当您将在同步上下文中使用 checkPhrFolder
函数时,您将能够将其 return 值包装在同一个 then/catch
语句中。
参考
我使用传统方式构建我的 dirs populator,如下所示:
var phrFolderManager = {
currentName: null,
currentParent: null,
folders: {
'/PersonalHealthRecord': null,
'/PersonalHealthRecord/Some': null,
'/PersonalHealthRecord/Dirs': null,
'/PersonalHealthRecord/ForMe': null
},
addFolder: function (name, id) {
this.folders[name] = id;
},
getFolderId: function (name) {
return this.folders[name];
},
refresh: function (forced) {
console.log('next step ' + forced + ' ...');
console.log(this.folders);
// find the next null in our folder list
for (k in this.folders) {
this.currentName = k;
if (!this.folders[k]) {
var parts = k.split('/');
if (parts.length == 2) {
// this is our base dir inside root
if (forced) {
this.createFolder(parts[1], 'root');
} else {
this.getFolder(parts[1], 'root');
}
} else {
var parent = parts.slice(0, -1).join('/');
var name = parts[parts.length - 1];
var parent_id = this.folders[parent];
if (forced) {
this.createFolder(name, parent_id);
} else {
this.getFolder(name, parent_id);
}
}
break;
} else {
console.log('... defined as ' + this.folders[k]);
}
}
},
getFolder: function (name, parent) {
//M.toast({html: 'check da pasta '+name,classes: 'rounded'});
if (!parent) parent = 'root';
this.currentParent = parent;
console.log('getFolder ' + name + ' ' + parent);
var res = gapi.client.drive.files.list({
'pageSize': 1,
'fields': "files(id, name, mimeType, parents)",
'q': "mimeType='application/vnd.google-apps.folder' \
and '" + parent + "' in parents \
and name = '" + name + "'"
}).then(
function (res) {
console.log(res);
if (res.result.files.length > 0) {
this.folders[this.currentName] = res.result.files[0]['id'];
this.refresh(false);
} else {
this.refresh(true);
}
},
function (err) {
console.log('error in getFolder: ' + err)
},
this
);
},
createFolder: function (name, parent) {
M.toast({
html: 'criando pasta ' + name,
classes: 'rounded'
});
if (!parent) parent = 'root';
console.log('createFolder ' + name + ' ' + parent);
var fileMetadata = {
'name': name,
'mimeType': 'application/vnd.google-apps.folder',
'parents': [parent]
};
gapi.client.drive.files.create({
'resource': fileMetadata,
'fields': 'id'
}).then(
function (res) {
console.log(res);
this.folders[this.currentName] = res.result['id'];
this.refresh();
},
function (err) {
alert('Problem creating ' + this.currentName + ' PersonalHealthRecord structure');
},
this
);
}
};
稍微调整一下,@Alessandro 的解决方案对我有用:
- 为了便于阅读,我颠倒了方法的顺序。
- 我合并了一个 FOR 循环,因为我的文件结构将深入许多文件夹。循环通过包含文件路径中的文件夹名称的字符串数组。
- 我注意到 (!parent) 没有正确返回,因为它是“未定义”,而不是“空”。此外,当找不到现有文件夹时期待“null”是至关重要的,所以我将 parentId 默认为“root”,因为我知道我的第一个文件夹将始终位于根目录
- 变量 newFolderId 保存 found/created 文件夹的值,并传递给 parentId 用于 FOR 循环的下一次迭代
- 最后,我将“'parent': parent”更新为“'parents' : [parent]”。那个“s”和那些括号似乎是必要的,否则每个创建的文件夹都放在根目录下。
async function buildFilePath() {
console.log("buildFilePath()");
var parentId = "root";
for (let i = 0; i < filePath.length; i++) {
var folderName = filePath[i];
newFolderId = await getFolder(folderName, parentId);
console.log(folderName + " id is " + newFolderId + ", parentId is " + parentId);
if (newFolderId == null) {
newFolderId = await createFolder(folderName,parentId);
console.log ("created new folder " + folderName + " with Id " + parentId);
} else {
// parentId = newParentId;
console.log (folderName + " already exist, move on to next.");
}
parentId = newFolderId;
}
}
async function getFolder(name, parent) {
const res = await gapi.client.drive.files.list({
'pageSize': 1,
'fields': "nextPageToken, files(id, name, mimeType, parents)",
'q': "mimeType='application/vnd.google-apps.folder' \
and '" + parent + "' in parents \
and name = '" + name + "' \
and trashed = false"
});
return res.result.files.length > 0 ? res.result.files[0]['id'] : null;
}
async function createFolder(name, parent) {
if (!parent) parent = 'root';
var fileMetadata = {
'name': name,
'mimeType': 'application/vnd.google-apps.folder',
'parents': [parent]
};
const res = await gapi.client.drive.files.create({
'resource': fileMetadata,
'fields': 'id'
});
return res.result['id'];
}