2012-06-27 31 views
3

我正在使用Javascript编写将与Phonegap一起使用以制作Android应用程序的应用程序。我正在使用Phonegap File API来读取目录和文件。相关的代码如下所示:如何使用javascript迭代文件系统目录和文件?

document.addEventListener("deviceready", onDeviceReady, false); 

// PhoneGap is ready 
// 
function onDeviceReady() { 
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFileSystemSuccess, fail); 
} 

function onFileSystemSuccess(fileSystem) { 
    fileSystem.root.getDirectory("/sdcard", {create: false, exclusive: false}, getDirSuccess, fail); 
} 

function getDirSuccess(dirEntry) { 
    // Get a directory reader 
    var directoryReader = dirEntry.createReader(); 

    // Get a list of all the entries in the directory 
    directoryReader.readEntries(readerSuccess,fail); 
} 

var numDirs = 0; 
var numFiles = 0; 

function readerSuccess(entries) { 
    var i; 
    for (i=0; i<entries.length; i++) 
    { 
     if(entries[i].isFile === true) 
     { 
     numFiles++; 
     entries[i].file(fileSuccess,fail); 
     } 
     else if (entries[i].isDirectory === true) 
     { 
     numDirs++; 
     getDirSuccess(entries[i]); 
     } 
    } 
} 

因此截至目前,程序工作正常。读者将读取/ sdcard目录中的内容。如果遇到文件,它会调用fileSuccess(为简洁起见,我已在代码中排除),如果遇到另一个目录,它将再次调用getDirSuccess。我的问题是这样的:我怎么知道整个/ sdcard目录是什么时候被读取的?我想不到通过/ sdcard目录不止一次完成此操作的好方法。任何想法都表示感谢,并提前感谢您!

回答

2

+1在一个很好的问题,因为我必须自己做这个。我会使用旧的setTimeout技巧。一旦取消不再发生,你知道你已经完成并且可以解雇你的事件,但是确保它只被解雇一次。

这里就是我的意思是,我已经叫长只是为了更具可读性的变量(不是我的风格)...

// create timeout var outside your "readerSuccess" function scope 
var readerTimeout = null, millisecondsBetweenReadSuccess = 100; 

function readerSuccess(entries) { 
    var i = 0, len = entries.length; 
    for (; i < len; i++) { 
     if (entries[i].isFile) { 
      numFiles++; 
      entries[i].file(fileSuccess,fail); 
     } else if (entries[i].isDirectory) { 
      numDirs++; 
      getDirSuccess(entries[i]); 
     } 
     if (readerTimeout) { 
      window.clearTimeout(readerTimeout); 
     } 
    } 
    if (readerTimeout) { 
     window.clearTimeout(readerTimeout); 
    } 
    readerTimeout = window.setTimeout(weAreDone, millisecondsBetweenReadSuccess); 
} 

// additional event to call when totally done 
function weAreDone() { 
    // do something 
} 

因此,在这个逻辑是你继续取消“weAreDone”功能当你正在阅读东西时被调用。不确定这是最好的方法还是更高效,但是如果给出适当的“毫秒间隔读取成功”,它不会导致多于一个循环。

+0

这种方法做的工作,所以+1为了那个原因。我将millisecondsBetweenReadSuccess设置为5000,weAreDone()仅被调用一次。设置为4000,它会被调用两次。我希望避免使用时间敏感的函数,因为如果我在不同的设备上使用此代码,它可能无法正常工作(毫秒之间的读取成功可能需要更大)。如果我找不到更好的解决方案,我会将你的标记标记为已接受。如果我找到更优雅的解决方案,我一定会在这里发布。 – vdelricco

+0

哇,5秒这是很长的时间。我会稍微修改一下,所以你没有这么长的超时时间。在我需要它之前,您通过验证我的想法来帮助我,所以我很感激。 –

+0

有趣的是,将额外的if语句放在for循环中导致weAreDone函数被调用两次(同时设置为5秒)。 – vdelricco

1

而不是使用setTimeout,如果你有一个非常慢的设备可能会失败,你可以使用一个计数器来看看还有多少回调仍然需要调用。如果计数器达到零,你就大功告成了:)

这是递归代码:

var fileSync = new function(){ 
    this.filesystem = null; 

    this.getFileSystem = function(callback){ 
     var rfs = window.requestFileSystem || window.webkitRequestFileSystem; 

     rfs(
       1// '1' means PERSISTENT 
      , 0// '0' is about max. storage size: 0==we don't know yet 
      , function(filesystem){ 
       fileSync.filesystem = filesystem; 
       callback(filesystem); 
      } 
      , function(e){ 
       alert('An error occured while requesting the fileSystem:\n\n'+ e.message); 
      } 
     ); 
    } 

    this.readFilesFromReader = function(reader, callback, recurse, recurseFinishedCallback, recurseCounter) 
    { 
     if (recurse && !recurseCounter) 
      recurseCounter = [1]; 

     reader.readEntries(function(res){ 
       callback(res); 

       if (recurse) 
       { 
        for (var i=0; i<res.length; i++) { 
         /* only handle directories */ 
         if (res[i].isDirectory == true) 
         { 
          recurseCounter[0]++; 
          fileSync.readFilesFromReader(res[i].createReader(), callback, recurse, recurseFinishedCallback, recurseCounter); 
         } 
        } 
       } 
       /* W3C specs say: Continue calling readEntries() until an empty array is returned. 
       * You have to do this because the API might not return all entries in a single call. 
       * But... Phonegap doesn't seem to accommodate this, and instead always returns the same dir-entries... OMG, an infinite loop is created :-/ 
       */ 
       //if (res.length) 
       // fileSync.readFilesFromReader(reader, callback, recurse, recurseFinishedCallback, recurseCounter); 
       //else 
       if (recurse && --recurseCounter[0] == 0) 
       { 
        recurseFinishedCallback(); 
       } 
      } 
     , function(e){ 
      fileSync.onError(e); 
      if (recurse && --recurseCounter[0] == 0) 
       recurseFinishedCallback(); 
     }); 
    }; 

    this.onError = function(e){ 
     utils.log('onError in fileSync: ' + JSON.stringify(e)); 
     if (utils.isDebugEnvironment()) 
      alert('onError in fileSync: '+JSON.stringify(e)); 
    } 
} 

var utils = new function(){ 
    this.log = function(){ 
     for (var i=0;i<arguments.length;i++) 
      console.log(arguments[i]); 
    } 
    this.isDebugEnvironment = function(){ return true }// simplified 
} 

示例代码来测试这一点:

var myFiles = []; 
var directoryCount = 0; 

window.onerror = function(){ alert('window.onerror=\n\n' + arguments.join('\n')) } 

var gotFilesCallback = function(entries) 
{ 
    for (var i=0;i<entries.length;i++) 
    { 
     if (entries[i].isFile == true) 
      myFiles.push(entries[i].fullPath) 
     else 
      ++directoryCount; 
    } 
} 

var allDoneCallback = function(){ 
    alert('All files and directories were read.\nWe found '+myFiles.length+' files and '+directoryCount+' directories, shown on-screen now...'); 
    var div = document.createElement('div'); 
    div.innerHTML = '<div style="border: 1px solid red; position: absolute;top:10px;left:10%;width:80%; background: #eee;">' 
     + '<b>Filesystem root:</b><i>' + fileSync.filesystem.root.fullPath + '</i><br><br>' 
     + myFiles.join('<br>').split(fileSync.filesystem.root.fullPath).join('') 
    + '</div>'; 
    document.body.appendChild(div); 
} 

/* on-device-ready/on-load, get the filesystem, and start reading files */ 
var docReadyEvent = window.cordova ? 'deviceready':'load'; 
document.addEventListener(docReadyEvent, function() 
{ 
    fileSync.getFileSystem(function(filesystem){ 
     var rootDirReader = filesystem.root.createReader(); 
     fileSync.readFilesFromReader(rootDirReader, gotFilesCallback, true, allDoneCallback); 
    }) 
}, false); 
+0

嘿@PaulFrinky,我在前一段时间停止了这个项目,所以我将无法测试它。逻辑和代码似乎听起来不错,所以你可以有一个upvote :) – vdelricco

相关问题