2012-06-27 63 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

相關問題