使用Chrome FileSystem,让用户选择一个目录,在里面加载文件。并保存该目录中的文件而不再提示

时间:2014-02-20 01:40:29

标签: google-chrome-app

我找不到这个场景的任何例子,所以我们走了:

我希望用户选择一个目录,加载其中的所有文件,更改它们,并保存此文件覆盖它或将新文件保存在同一目录中,而不询问他想要保存的位置。

  • 我不知道如何列出目录的文件
  • 我不知道如何在不提示filechooser窗口的情况下将文件保存在目录中

我相信这是可能的,因为我在这里看到类似的东西(最后一段): http://www.developer.com/lang/using-the-file-api-outside-the-sandbox-in-chrome-packaged-apps.html

任何答案都将不胜感激,谢谢

编辑:感谢Chris Johnsen给了我这个很好的答案:

var fileHandler = function() {

  var _entry = null;

  this.open = function(cb) {

    chrome.fileSystem.chooseEntry({
      type: 'openDirectory'
    }, function(dirEntry) {

      if (!dirEntry || !dirEntry.isDirectory) {
        cb && cb(null);
        return;
      }

      _entry = dirEntry;

      listDir(_entry, cb);
    });


  };

  this.save = function(filename, source) {

    chrome.fileSystem.getWritableEntry(_entry, function(entry) {

      entry.getFile(filename, {
        create: true
      }, function(entry) {
        entry.createWriter(function(writer) {

          writer.onwrite = function() {
            writer.onwrite = null;
            writer.truncate(writer.position);
          };

          writer.write(new Blob([source], {
            type: 'text/javascript'
          }));
        });
      });

    });

  };

  this.saveAs = function(filename, source) {

    chrome.fileSystem.chooseEntry({
      type: 'openDirectory'
    }, function(entry) {

      chrome.fileSystem.getWritableEntry(entry, function(entry) {

        entry.getFile(filename, {
          create: true
        }, function(entry) {
          entry.createWriter(function(writer) {

            writer.onwrite = function() {
              writer.onwrite = null;
              writer.truncate(writer.position);
            };

            writer.write(new Blob([source], {
              type: 'text/javascript'
            }));
          });
        });

      });
    });

  };

  var listDir = function(dirent, cb, listing) {
      if (listing === undefined) {
        listing = [];
      }

      var reader = dirent.createReader();

      var read_some = reader.readEntries.bind(reader, function(ents) {

        if (ents.length === 0) {
          return cb && cb(listing);
        }

        var process_some = function(ents, i) {

            for (; i < ents.length; i++) {
              listing.push(ents[i]);

              if (ents[i].isDirectory) {
                return listDir(ents[i], process_some.bind(null, ents, i + 1), listing);
              }
            }

            read_some();
          };

        process_some(ents, 0);

      }, function() {
        console.error('error reading directory');
      });

      read_some();
    };

};

1 个答案:

答案 0 :(得分:5)

您的save方法应该可以正常工作(大多数情况下见下文)以满足您的第二个要求(在没有其他用户提示的情况下写入代码选择的文件名),但open中存在一些错误(至少在问题中提出):

  • chooseEntry回调中this !== fileHandler,因为回调是使用不同的this(可能是背景页的window对象)调用的。
    您可以通过以下几种方式解决此问题:
    • 使用fileHandler代替this(如果您没有将其用作任何原型)。
    • 使用.bind(this)将每个回调函数绑定到同一个上下文。
    • 使用var self = this;顶部的open并在回调中使用self.entry(等等)。
  • 您可能需要为成功案例致电cb。也许你有另一种方法可以将调用推迟到(例如)fileHandler.save(点击某个元素来触发保存?),但是添加类似

    的内容
    ⋮
    cb && cb(self.entry);
    ⋮
    
    self.entry = dirEntry轻松(例如)链opensave之后

    fileHandler.open(function(ent) {
        fileHandler.save('newfile','This is the text\nto save in the (possibly) new file.');
    });
    

save中存在潜在错误:如果您覆盖现有文件,则需要调用writer.truncate()(除非您总是写入比原始文件更多的字节)。

⋮
writer.onwrite = function() {
    writer.onwrite = null;
    writer.truncate(writer.position);
};
writer.write(…);
⋮

看起来你在文件列表部分有一个良好的开端。如果您想稍后引用文件列表,那么您可能希望将它们保存在对象中而不是仅记录它们;如果你想要递归到子目录中,这可能会有点毛茸茸(并且也不能假设readEntries返回第一次调用的所有内容。)

function list_dir(dirent, cb, listing) {
    if (listing === undefined) listing = [];
    var reader = dirent.createReader();
    var read_some = reader.readEntries.bind(reader, function(ents) {
        if (ents.length === 0)
            return cb && cb(listing);
        process_some(ents, 0);
        function process_some(ents, i) {
            for(; i < ents.length; i++) {
                listing.push(ents[i]);
                if (ents[i].isDirectory)
                    return list_dir(ents[i], process_some.bind(null, ents, i + 1), listing);
            }
            read_some();
        }
    }, function() {
        console.error('error reading directory');
    });
    read_some();
}

您可以在open回调中使用它(假设您添加其成功回调),如下所示:

fileHandler.open(function(ent) {
    ent && list_dir(ent, function(listing) {
        fileHandler.listing = listing;
        console.log('listing', fileHandler.listing.map(function(ent){return ent.fullPath}).join('\n'));
        fileHandler.save('a_dir/somefile','This is some data.');
    });
});