借助Chrome FileSystem,用户可以选择目录,并在其中加载文件.并将文件保存在该目录中,而无需再次提示 [英] With Chrome FileSystem, let the user choose a Directory, load files inside. And save files in that directory without prompting again

查看:59
本文介绍了借助Chrome FileSystem,用户可以选择目录,并在其中加载文件.并将文件保存在该目录中,而无需再次提示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这种情况下我找不到任何示例,所以我们开始:

I could not found any examples with this scenario so here we go:

我希望用户选择一个目录,加载其中的所有文件,进行更改,然后保存覆盖该文件的文件或将新文件保存在同一目录中,而无需询问他要保存在何处.

I want the user choose a directory, load all files inside it, change them, and save this file overriding it or saving a new file in that same directory without asking where he want to save.

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

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

I believe it is possible because I see something similar here (last paragraph): http://www.developer.com/lang/using-the-file-api-outside-the-sandbox-in-chrome-packaged-apps.html

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

Any answer will be appreciated, Thank you

编辑:感谢克里斯·约翰森给我这个很好的答案:

Thanks to Chris Johnsen for giving me this great answer:

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();
    };

};

推荐答案

您的save方法应该可以正常工作(大部分情况,请参见下文),以满足您的第二个要求(无需其他用户提示即可写入代码选择的文件名),但是open中有几个错误(至少如问题中所述):

Your save method should work fine (mostly, see below) for your second requirement (write to a code-chosen filename without another user prompt), but there are a couple of bugs in open (at least as presented in the question):

  • chooseEntry回调内部,是this !== fileHandler,因为该回调是通过不同的this(可能是背景页面的window对象)调用的. 您可以通过以下几种方法解决此问题:
    • 使用fileHandler代替this(如果您不将其用作任何原型).
    • 使用.bind(this)将每个回调函数绑定到同一上下文.
    • open的顶部使用var self = this;,并在回调中使用self.entry(et cetera).
    • Inside the chooseEntry callback, this !== fileHandler because the callback is invoked with a different this (probably the background page’s window object).
      You can work around this in several ways:
      • Use fileHandler instead of this (if you are not using it as any kind of prototype).
      • Use .bind(this) to bind each of your callback functions to the same context.
      • Use var self = this; at the top of open and use self.entry (et cetera) in the callbacks.

      对于成功案例,您可能需要致电cb.也许您还有另一种方法来推迟对fileHandler.save的调用(单击某些元素以触发保存?),但是添加类似

      You may want to call cb for the success case. Maybe you have another way of postponing calls to (e.g.) fileHandler.save (clicking on some element to trigger the save?), but adding something like

      ⋮
      cb && cb(self.entry);
      ⋮
      

      之后的

      使其易于(例如)链接opensave:

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

    • save中有一个潜在的错误:如果您覆盖现有文件,则您将要调用writer.truncate()(除非您始终写入的字节数多于最初保存的文件).

      There is a latent bug in save: if you ever overwrite an existing file, then you will want to call writer.truncate() (unless you always write more bytes than the file originally held).

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


      看起来您在文件列表部分上有了一个良好的开端.如果以后要引用文件列表,则可能需要将它们保存在对象中,而不是仅记录它们;而是将它们保存在对象中.如果您想递归到子目录中,这可能会有些毛茸茸(并且还不假定readEntries会在第一次调用时返回所有内容).


      It looks like you have a good start on the file listing part. If you want to reference the list of files later, then you might want to save them in your object instead of just logging them; this can get a bit hairy if you want to recurse into subdirectories (and also not assume that readEntries returns everything for its first call).

      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回调中使用它(假设您添加了它的成功回调),如下所示:

      You could use it in the open callback (assuming you add its success callback) like this:

      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.');
          });
      });
      

      这篇关于借助Chrome FileSystem,用户可以选择目录,并在其中加载文件.并将文件保存在该目录中,而无需再次提示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆