2016-12-08 1 views
11

Je travaille sur une fonction qui va écrire des données sur un serveur distant en morceaux en utilisant une API tierce. Grâce à de l'aide sur Stack Overflow, j'ai pu accomplir cela, où il fonctionne maintenant comme prévu. Le problème est que je ne peux écrire qu'un seul bloc de 16 Ko car je devrai avancer le pos de l'endroit où les octets suivants sont écrits.Obtenir la position d'octet pendant la boucle de téléchargement

L'écriture initiale commence à 0 facilement. En raison de mon manque de familiarité avec cela, je ne suis pas sûr si le prochain pos devrait juste être 16 ou quoi. Si cela aide, l'appel API writeFileChunk() prend 3 paramètres, chemin de fichier (str), pos (int64) et données (chaîne codée en base64).

reader.onload = function(evt) 
    { 
     // Get SERVER_ID from URL 
     var server_id = getUrlParameter('id'); 

     $("#upload_status").text('Uploading File...'); 
     $("#upload_progress").progressbar('value', 0); 

     var chunkSize = 16<<10; 
     var buffer = evt.target.result; 
     var fileSize = buffer.byteLength; 
     var segments = Math.ceil(fileSize/chunkSize); // How many segments do we need to divide into for upload 
     var count = 0; 

     // start the file upload 
     (function upload() 
     { 
      var segSize = Math.min(chunkSize, fileSize - count * chunkSize); 

      if (segSize > 0) 
      { 
       $("#upload_progress").progressbar('value', (count/segments)); 

       var chunk = new Uint8Array(buffer, count++ * chunkSize, segSize); // get a chunk 
       var chunkEncoded = btoa(String.fromCharCode.apply(null, chunk)); 

       // Send Chunk data to server 
       $.ajax({ 
        type: "POST", 
        url: "filemanagerHandler.php", 
        data: { 'action': 'writeFileChunk', 'server_id': server_id, 'filepath': filepath, 'pos': 0, 'chunk': chunkEncoded }, 
        dataType: 'json', 
        success: function(data) 
        { 
         console.log(data); 
         setTimeout(upload, 100); 
        }, 
        error: function(XMLHttpRequest, textStatus, errorThrown) 
        { 
         alert("Status: " + textStatus); alert("Error: " + errorThrown); alert("Message: " + XMLHttpRequest.responseText); 
        } 
       }); 
      } 
      else 
      { 
       $("#upload_status").text('Finished!'); 
       $("#upload_progress").progressbar('value', 100); 

       getDirectoryListing(curDirectory); 
      } 
     })() 
    }; 
+1

Qu'est-ce que l'API 3ème partie, et ne la documentation mentionne pas cela? // Supposer que ce soit juste la position de l'octet semble être une supposition assez juste - alors quels résultats avez-vous obtenus lorsque vous avez essayé cela? – CBroe

+0

Si cette API tierce ne permet que le téléchargement en base64, je ne l'utiliserais pas ... – Endless

Répondre

9

La position actuelle du fichier côté client serait représenté par cette ligne, ou plus précisément le deuxième argument à l'étape de pré-incrémentale:

var chunk = new Uint8Array(buffer, count++ * chunkSize, segSize); 

bien que, dans ce cas, il avance (count++) avant de pouvoir le réutiliser si vous avez besoin de la position réelle (ci-après pos), vous pouvez l'extraire en réécrivant simplement la ligne en:

var pos = count++ * chunkSize; // here chunkSize = 16kb 
var chunk = new Uint8Array(buffer, pos, segSize); 

Dans ce cas, chaque mise à jour de position incrémentera 16 ko étant donné que c'est la taille de bloc. Pour le progrès, il est calculé pos/fileSize * 100. Ceci en supposant bien sûr d'utiliser la taille du tampon non codé.

Le seul cas particulier est le dernier bloc, mais quand il n'y a plus de morceaux à lire, la position doit être égale à la longueur du fichier (fileSize), donc il devrait être assez simple. Lorsque l'appel ajax revient, le serveur doit avoir la même position à moins que quelque chose ne se passe mal (connexion, changement d'accès en écriture, disque plein, etc.).

2

Vous pouvez utiliser l'API Filereader pour lire les fragments et les envoyer à votre serveur distant.

HTML

<input type="file" id="files" name="file" /> Read bytes: 
<span class="readBytesButtons"> 
    <button>Read entire file in chuncks</button> 
</span> 

Javascript

// Post data to your server. 
    function postChunk(obj) { 
    var url = "https://your.remote.server"; 
    return new Promise(function(resolve, reject) { 
     var xhr = new XMLHttpRequest(); 
     xhr.open('post', url, true); 
     xhr.responseType = 'json'; 
     xhr.onload = function() { 
      var status = xhr.status; 
      if (status == 200) { 
       resolve(xhr.response); 
      } else { 
       reject(status); 
      } 
     }; 
     var params = ""; 
     // check that obj has the proper keys and create the url parameters 
      if (obj.hasOwnProperty(action) && obj.hasOwnProperty(server_id) && obj.hasOwnProperty(filepath) && obj.hasOwnProperty(pos) && obj.hasOwnProperty(chunk)) { 
      params += "action="+obj[action]+"&server_id="+obj[server_id]+"&filepath="+obj[filepath]+"&pos="+obj[pos]+"&chunk="+obj[chunk]; 
      } 
     if(params.length>0) { 
     xhr.send(params); 
     } else { 
     alert('Error'); 
     }  
    }); 
    } 
// add chunk to "obj" object and post it to server 
function addChunk(reader,obj,divID) { 
    reader.onloadend = function(evt) { 
     if (evt.target.readyState == FileReader.DONE) { // DONE == 2 
     obj.chunk = evt.target.result; 
     console.log(obj); 
      document.getElementById(divID).textContent += 
      ['Sending bytes: ', obj.pos*16000, ' - ', ((obj.pos*16000)+(obj.pos+1)*obj.chunk.length), 
      '\n'].join(''); 
     // post data to server 
     postChunk(obj).then(function(data) { 
      if(data!=="" && data!==null && typeof data!=="undefined") { 
      // chunk was sent successfully 
      document.getElementById(divID).textContent += 
      ['Sent bytes: ', obj.pos*16000, ' - ', ((obj.pos*16000)+(obj.pos+1)*obj.chunk.length),'\n'].join(''); 
      } else { 
      alert('Error! Empty response'); 
      } 
     }, function(status) { 
      alert('Resolve Error'); 
     }); 
     } 
    }; 
} 
// read and send Chunk 
function readChunk() { 
    var files = document.getElementById('files').files; 
    if (!files.length) { 
     alert('Please select a file!'); 
     return; 
    } 
    var file = files[0]; 
    var size = parseInt(file.size); 
    var chunkSize = 16000; 
    var chunks = Math.ceil(size/chunkSize); 
    var start,stop = 0; 
    var blob = []; 
    for(i=0;i<chunks;i++) { 
    start = i*chunkSize; 
    stop = (i+1)*chunkSize-1; 
    if(i==(chunks-1)) { 
    stop = size; 
    } 
    var reader = new FileReader(); 
    blob = file.slice(start, stop); 
    reader.readAsBinaryString(blob); 
    var obj = {action: 'writeFileChunk', server_id: 'sid', filepath: 'path', pos: i, chunk: ""}; 
    var div = document.createElement('div'); 
    div.id = "bytes"+i; 
    document.body.appendChild(div); 
    addChunk(reader,obj,div.id);  
    } 
} 
// Check for the various File API support. 
if (window.File && window.FileReader && window.FileList && window.Blob) { 
    console.log(' Great success! All the File APIs are supported.'); 
} else { 
    alert('The File APIs are not fully supported in this browser.'); 
} 
    document.querySelector('.readBytesButtons').addEventListener('click', function(evt) { 
    if (evt.target.tagName.toLowerCase() == 'button') { 
     readChunk(); 
    } 
    }, false); 

Vous pouvez vérifier cet exemple dans ce Fiddle