Filereader和Socket.io上传器:后续上传包括以前的上传

时间:2013-12-15 23:42:36

标签: javascript jquery html5 node.js filereader

我正在尝试在html5 / js中实现一个文件上传器,以及以块的形式上传大文件的节点。它适用于单个上传。但是当我尝试再次在同一页面上传时,它会进入无限循环,看起来它正在尝试重新上载上一次上传和新文件。

Client.js

$('input').change(function() {
  var file = this.files[0]
  var fileSize = file.size
  var fileName = file.name
  // file size gate:
  var fileSizeLimit = 15000000 // ~15mb
  if (fileSize <= fileSizeLimit) {
    // get preview blob
    var windowURL = window.URL || window.webkitURL
    var blobURL = windowURL.createObjectURL(this.files[0])
    // render preview image
    // render status progress
    // set progress to 0

    // read the file to server:
    var reader = new FileReader()
    console.log('new filereader init')
    socket.emit('startSend', fileName, fileSize, entryID)
    console.log('startSend emitted now for ' + fileName) 

    reader.onload = function(event) {
      var data = event.target.result
      console.log('reader onload for ' + fileName)
      socket.emit('sendPiece', data, fileName, fileSize, entryID)
    }

    socket.on('morePlease', function (place, entryID, percent){
      progressUpdate(percent)
      var chunkSize = 262144
      var startPlace = place * chunkSize // The newBlock's Starting Position
      var newBlock = file.slice(startPlace, startPlace + Math.min(chunkSize, (fileSize-startPlace)))
      reader.readAsBinaryString(newBlock) // triggers reader onload
    })

    function progressUpdate(percent){
      console.log('current percent is: ' + percent + '%')
      $('.sendfile .progress').val(percent).text(percent + '%')
    }

    socket.on('sendSuccessful', function(entryID){
      console.log('sendSuccessful triggered for ' + entryID + '. File should be in temp folder.')
      $('.status .sendfile').addClass('hidden')
      $('.status .savetext').removeClass('hidden')
      $('.status .saved').removeClass('hidden')
      $('.sendfile .progress').val(0).text('0%')
    })

  } else { 
    // file size is too big
  }

}) // close input onchange event

Server.js

  // start file upload
  var chunkSize = 262144

  socket.on('startSend', function(fileName, fileSize, entryID) {
    var files = {}
    console.log('startSend hit for ' + fileName)
    files[fileName] = { // create new entry in files {}
      fileSize : fileSize,
      data : '',
      downloaded : 0
    }
    var fileWriting = files[fileName]
    var tempPath = 'temp/' +  entryID + '-' + fileName
    var place = 0 // stores where in the file we are up to
    console.log('place: in startSend, the place for ' + fileName + ' is ' + place) //

    try{
      var stat = fs.statSync(tempPath)
      if(stat.isFile())
      {
        fileWriting['downloaded'] = stat.size
        place = stat.size / chunkSize; // we're passing data in 1/4 mb increments
        console.log('downloaded: ' + stat.size)
      }
    }
    catch(er){} // it's a new file
    fs.open(tempPath, "a", 0755, function(err, fd){
      if(err)
      {
        console.log(err)
      }
      else // requesting
      {
        fileWriting['handler'] = fd //We store the file handler so we can write to it later
        var percent = 0
        socket.emit('morePlease', place, entryID, percent) // requesting more file pieces
      }
    })

    // processing the file pieces from client
    socket.on('sendPiece', function(data, fileName, fileSize, entryID) {
      console.log('sendPiece hit for ' + entryID + ' ' + fileName) 
      fileWriting['downloaded'] += data.length
      fileWriting['data'] += data
      if(fileWriting['downloaded'] == fileWriting['fileSize']) { // If File is Fully Uploaded
        fs.write(fileWriting['handler'], fileWriting['data'], null, 'Binary', function(err, Writen){
          console.log('file ' + entryID + 'has been written to temp folder: ' + fileName)
          socket.emit('sendSuccessful', entryID)
        })
      }
      else if(fileWriting['data'].length > 10485760){ //If the Data Buffer reaches 10MB
        fs.write(fileWriting['handler'], fileWriting['data'], null, 'Binary', function(err, Writen){
          fileWriting['data'] = ""; //Reset The Buffer
          var place = fileWriting['downloaded'] / chunkSize
          var percent = (fileWriting['downloaded'] / fileWriting['fileSize']) * 100
          socket.emit('MorePlease', place, entryID, percent) // requesting more file pieces
        })
      }
      else { // need more file pieces
        var place = fileWriting['downloaded'] / chunkSize
        console.log('MorePlease: ' + fileName + ' pieces needed at place ' + place + ' and percent ' + percent)
        var percent = (fileWriting['downloaded'] / fileWriting['fileSize']) * 100
          socket.emit('morePlease', place, entryID, percent) // requesting more file pieces
      }
    })
  }) // close startSend

服务器日志:这是基于分散在各处的console.logs的节点日志:

上传第一个文件很好:

startSend hit for file1.jpeg
place: in startSend, the place for file1.jpeg is 0
sendPiece hit for 52a530f8649b5db8b2000001 file1.jpeg
file 52a530f8649b5db8b2000001has been written to temp folder: file1.jpeg

以及后续文件:

startSend hit for file2.JPG
place: in startSend, the place for file2.JPG is 0
sendPiece hit for 52a530f8649b5db8b2000001 file1.jpeg
MorePlease: file1.jpeg pieces needed at place 1.9332275390625 and percent undefined
sendPiece hit for 52a530f8649b5db8b2000001 file1.jpeg
MorePlease: file1.jpeg pieces needed at place 0.96661376953125 and percent undefined
sendPiece hit for 52a530f8649b5db8b2000001 file2.JPG
MorePlease: file2.JPG pieces needed at place 2.6120567321777344 and percent undefined

......无限循环。


webinspector消息:

reader onload for file1.jpeg (client.js, line 260)
reader onload for file2.JPG (client.js, line 260)
current percent is: 270.227552566774% (client.js, line 273, x2)
current percent is: 242.3942545981759% (client.js, line 273)
InvalidStateError: DOM Exception 11: An attempt was made to use an object that is not, or is no longer, usable.

......无限循环


我已经花了好几个小时在脑子里绞尽脑汁,试图自己逐步完成代码。我不是贸易开发商,所以任何帮助都会受到超级赞赏!

1 个答案:

答案 0 :(得分:0)

我从未使用Socket通过Node.js上传文件。基本上,http做得很好。这是示例代码:

var http = require('http'),
    fs = require('fs');

var server = http.createServer();
server.listen(8080);
console.log('Start is started on port 8080');

server.on('request', function(req, res) {
    var file = fs.createWriteStream('sample.jpg');
    var fileSize = req.headers['content-length'];
    var uploadedSize = 0;

    req.on('data', function (chunk) {
        uploadedSize += chunk.length;
        var buffer = file.write(chunk);
        if(buffer == false)
            req.pause();
    });

    file.on('drain', function() {
        req.resume();
    });

    req.on('end', function() {
        res.write('File uploading is completed!!');
        res.end();
    });
});

如果您想通知客户有关上传进度的信息,可以在data事件中添加一些逻辑。

顺便说一句,我发现有人已经问了同样的问题并得到答案。答案发布了指向教程的链接。我已经检查并认为它是您正在寻找的解决方案。检查此Node.js file upload capabilities: Large Video Files Uploading with support for interruption