Я пытаюсь реализовать загрузчик файлов в 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 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 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
server log: Здесь журнал узлов основан на 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.
... бесконечная петля
Я много часов ломал голову над этим, пытаясь самостоятельно выполнить код. Я не разработчик по профессии, поэтому любая помощь будет оценена очень высоко!
Я никогда не использую 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: Загрузка больших видеофайлов с поддержкой прерывания !