如何在我的谷歌硬盘的特定文件夹中查找重复文件(按名称和/或大小)?

时间:2014-03-29 19:58:40

标签: google-apps-script google-drive-api

是否可以创建一个Google应用脚本,该脚本会选择自动复制特定(当前)文件夹中的文件(然后我只需点击一下就可以删除它们)?

https://developers.google.com/apps-script/reference/drive/

我问这是因为Google驱动PC客户端在更新时会创建随机重复文件!他们想要解决这个错误,但我必须在每个文件夹中手动选择它们然后删除它们。这非常烦人且耗时。 https://productforums.google.com/forum/#!category-topic/drive/report-a-problem/_ApOopI-Xkw

编辑:或者,由于Windows无法在同一文件夹中创建相同的文件名,因此在特定主文件夹(及其每个相关子文件夹)中查找并放入垃圾桶中的所有重复文件名。

2 个答案:

答案 0 :(得分:7)

为了更好的可读性,我在第二个答案中添加了这个答案的下一部分。

以下是处理重复项的代码:它适用于 2个步骤:

  1. 检测重复项并在表单中标记它们以检查一切是否正常( markDuplicates()
  2. 删除要保留的文件上的红色背景(在完成第3步后它们将变为黄色)
  3. 删除所选(标记)的文件,实际上将它们移到垃圾箱,您必须从驱动器Ui手动清空垃圾箱。 ( trashDuplicates())已删除的文件将以深红色显示以确认删除。

  4. 最后编辑:

    在此处放置完整代码并将一些函数设为私有,以避免由于错误的脚本调用而导致的错误。

    function startProcess(){
      PropertiesService.getScriptProperties().deleteAllProperties();
      try{
        ScriptApp.deleteTrigger(ScriptApp.getProjectTriggers()[0]);
      }catch(e){}
      var sh = SpreadsheetApp.getActiveSheet();
      sh.getDataRange().clear();
      sh.getRange(1,1,1,4).setValues([['fileName (logged @'+Utilities.formatDate(new Date(),Session.getScriptTimeZone(),'MMM-dd-yyyy HH:mm')+')','fileSize','parent folders tree','fileID']]);
      var trig = ScriptApp.newTrigger('getDriveFilesList_').timeBased().everyMinutes(5).create();
      Logger.log(trig.getUniqueId()+'  '+trig.getHandlerFunction());
      getDriveFilesList_();
    }
    
    function getDriveFilesList_(){
      var content = [];
      var startTime = new Date().getTime();
      var sh = SpreadsheetApp.getActiveSheet();
      if( ! PropertiesService.getScriptProperties().getProperty('numberOfFiles')){
        PropertiesService.getScriptProperties().setProperty('numberOfFiles',0);
      }
    
      var numberOfFiles = Number(PropertiesService.getScriptProperties().getProperty('numberOfFiles'));
      Logger.log(numberOfFiles);
      var max = numberOfFiles+10000;
      if( ! PropertiesService.getScriptProperties().getProperty('continuationToken')){
        var files = DriveApp.getFiles();
       // var files = DriveApp.getFolderById('0B3qSFd_____MTFZMDQ').getFiles();// use this line and comment the above if you want to process a single folder
       // use your chozen folder ID of course (available from the browser url , the part after "https://drive.google.com/?authuser=0#folders/")
      }else{
        var files = DriveApp.continueFileIterator(PropertiesService.getScriptProperties().getProperty('continuationToken'))
        }
      while(files.hasNext() && numberOfFiles<(max)){
        var file = files.next()
        if(file.getSize()>0){
          numberOfFiles++;
          var folder = '(shared)';
          if(file.getParents().hasNext()){folder = getTree_(file)}
          content.push([file.getName(),file.getSize(),folder,file.getId()])
        }    
        if(new Date().getTime()-startTime > 250000){break};
      }
      sh.getRange(sh.getLastRow()+1,1,content.length,content[0].length).setValues(content);
      if(!files.hasNext()){ScriptApp.deleteTrigger(ScriptApp.getProjectTriggers()[0]);Logger.log('done !'); sh.getRange(sh.getLastRow()+1,1).setValue('All files processed ('+numberOfFiles+' found)')};
      var continuationToken = files.getContinuationToken()
      PropertiesService.getScriptProperties().setProperty('numberOfFiles',numberOfFiles);
      PropertiesService.getScriptProperties().setProperty('continuationToken',continuationToken);
    }
    
    function markDuplicates(){
      handleDuplicates_(false)
    }
    
    function trashDuplicates(){
      handleDuplicates_(true)
    }
    
    function handleDuplicates_(trash){  
      var sh = SpreadsheetApp.getActiveSheet();
      sh.setFrozenRows(1);
      sh.sort(1);
      var data = sh.getDataRange().getValues()
      var headers = data.shift()
      var lastComment = data.pop();
      var toDelete = [];
      var item = data[0];
      for(var n=1 ; n<data.length; n++){
        if(data[n][0]==item[0] && data[n][1]==item[1]){
          toDelete.push('delete '+n);
        }
        item=data[n];
      }
      var marker =   sh.getRange(2,1,data.length,1).getBackgrounds();
      for(var n in data){
        if(!trash){marker.push(['#FFF'])};
        if(toDelete.indexOf('delete '+n)>-1 && !trash){
          marker[n][0] = '#F99';
        }
        if(toDelete.indexOf('delete '+n)>-1 && trash){
          if(marker[n][0]=='#ff9999'){
            try{
            DriveApp.getFileById(data[n][3]).setTrashed(trash);
            marker[n][0] = '#F33';
            }catch(err){Logger.log(err)}
          }else{
            marker[n][0] = '#FF9';
          }
        }
      }
      sh.getRange(2,1,marker.length,1).setBackgrounds(marker);
    }
    
    function getTree_(file){
      var tree = [];
      var folderP = file.getParents()
      while (folderP.hasNext()){
        var folder = folderP.next();
        folderP = folder.getParents();
        tree.push(folder.getName());
      }
      return tree.reverse().join('/');
    }
    

答案 1 :(得分:0)

这并不简单...... DriveApp不是特别快,一个人通常在Drive中有很多文件,因此脚本无法一次性迭代所有文件。

您必须批量处理文件并设置时间触发器以自动继续,直到处理完所有文件。

这是一个脚本,显示如何在小批量项目中进行迭代(在现实生活中,您可以处理超过100个,我为了演示目的限制为一个小数字,只需将值更改为更实际的值一个关于执行需要多长时间的现实想法,请参阅代码中的注释。

我放弃了重复检测,因为我不确定是否所有文件都必须检查(Google文档的大小= 0所以它让我觉得你只想在其他格式文件上工作但我不是&# 39;确定)但这一部分不应该太难处理。

这是迭代代码,它显示了记录器中的文件名和大小,以及全局计数器:

function searchDupInDrive(){
  if( ! PropertiesService.getScriptProperties().getProperty('numberOfFiles')){PropertiesService.getScriptProperties().setProperty('numberOfFiles',0)};
  var numberOfFiles = Number(PropertiesService.getScriptProperties().getProperty('numberOfFiles'));
  Logger.log(numberOfFiles);
  var max = numberOfFiles+100;// use an appropriate value here so that execution time remains < 5 minutes
  if(numberOfFiles >2000){Logger.log('done !');return}; // this is to limit the demo to a short total execution time
  if( ! PropertiesService.getScriptProperties().getProperty('continuationToken')){
    var files = DriveApp.getFiles();
  }else{
    var files = DriveApp.continueFileIterator(PropertiesService.getScriptProperties().getProperty('continuationToken'))
    }
  while(files.hasNext() && numberOfFiles<(max)){
    var file = files.next()
    Logger.log((numberOfFiles)+' : fileName = '+file.getName()+'  size = '+file.getSize())
    numberOfFiles++;

    // set conditions, store file Names and sizes to be able to compare

  }
  var continuationToken = files.getContinuationToken()
  PropertiesService.getScriptProperties().setProperty('numberOfFiles',numberOfFiles);
  PropertiesService.getScriptProperties().setProperty('continuationToken',continuationToken);
}

注意:要实现重复检测,您可能必须在两个脚本运行之间的某个位置存储条件,文件名和大小,我想脚本属性也可用于此。

如果您有最终结果,请在此处更新。

注2:我读到了关于这个问题的帖子:非常可怕!我很高兴我在Mac OS上,没有这样的问题(现在: - )


修改

这是第二个版本。在评论中,您告诉我您已将脚本添加到电子表格中,这样我就可以将文件列表存储在电子表格中,这样,在第二步中,我们可以对文件进行排序并更轻松地查看/选择重复项。

顺便说一下,我注意到driveApp比我想象的要快,甚至不确定我们必须批量处理......然而我将执行时间限制在不到5分钟并且实现了脚本触发器创建/抑制如果你有很多文件......

以下是新代码,我仍然将重复检测放在一边,您可以很容易地找到很多代码示例来选择电子表格中的重复项...获取所有文件的第一步是最不明显的。

现在有2个函数,一个用于启动进程(清除工作表,创建触发器,为列设置标题)和实际驱动器读取一个(只需要文件不是谷歌文档,即文件包含大小大于0):

function startProcess(){
  PropertiesService.getScriptProperties().deleteAllProperties();
  var sh = SpreadsheetApp.getActiveSheet();
  sh.getDataRange().clear();
  sh.getRange(1,1,1,4).setValues([['fileName (logged @'+Utilities.formatDate(new Date(),Session.getScriptTimeZone(),'MMM-dd-yyyy HH:mm')+')','fileSize','parent folder','fileID']]);
  var trig = ScriptApp.newTrigger('getDriveFilesList').timeBased().everyMinutes(5).create();
  Logger.log(trig.getUniqueId()+'  '+trig.getHandlerFunction());
  getDriveFilesList();
}

function getDriveFilesList(){
  var content = [];
  var startTime = new Date().getTime();
  var sh = SpreadsheetApp.getActiveSheet();
  if( ! PropertiesService.getScriptProperties().getProperty('numberOfFiles')){
    PropertiesService.getScriptProperties().setProperty('numberOfFiles',0);
  }

  var numberOfFiles = Number(PropertiesService.getScriptProperties().getProperty('numberOfFiles'));
  Logger.log(numberOfFiles);
  var max = numberOfFiles+10000;
  if( ! PropertiesService.getScriptProperties().getProperty('continuationToken')){
    var files = DriveApp.getFiles();
  }else{
    var files = DriveApp.continueFileIterator(PropertiesService.getScriptProperties().getProperty('continuationToken'))
    }
  while(files.hasNext() && numberOfFiles<(max)){
    var file = files.next()
    if(file.getSize()>0){
      numberOfFiles++;
      var folder = '(shared)';
      if(file.getParents().hasNext()){folder = file.getParents().next().getName()}
      content.push([file.getName(),file.getSize(),folder,file.getId()])
    }    
    if(new Date().getTime()-startTime > 250000){break};
  }
  sh.getRange(sh.getLastRow()+1,1,content.length,content[0].length).setValues(content);
  if(!files.hasNext()){ScriptApp.deleteTrigger(ScriptApp.getProjectTriggers()[0]);Logger.log('done !'); sh.getRange(sh.getLastRow()+1,1).setValue('All files processed ('+numberOfFiles+' found)')};
  var continuationToken = files.getContinuationToken()
  PropertiesService.getScriptProperties().setProperty('numberOfFiles',numberOfFiles);
  PropertiesService.getScriptProperties().setProperty('continuationToken',continuationToken);
}