使用 socket.io-stream 将文件从服务器流式传输到客户端
Streaming a file from server to client with socket.io-stream
我已经设法将文件从客户端分块上传到服务器,但现在我想以相反的方式实现。不幸的是,官方模块页面上缺少这部分的文档。
我想做以下事情:
- 向服务器发送一个流和 'download'-带有文件名的事件
- 服务器应该创建一个读取流并将其通过管道传输到从客户端发出的流
- 当客户端到达流时,应该会出现下载弹出窗口并询问文件的保存位置
我不想使用简单的文件超链接的原因是混淆:服务器上的文件被加密和重命名,所以我必须为每个下载请求解密和重命名它们。
是否有任何代码片段可以让我开始使用它?
这是我正在使用的一个工作示例。但是不知何故(也许只对我而言)这可能非常慢。
//== Server Side
ss(socket).on('filedownload', function (stream, name, callback) {
//== Do stuff to find your file
callback({
name : "filename",
size : 500
});
var MyFileStream = fs.createReadStream(name);
MyFileStream.pipe(stream);
});
//== Client Side
/** Download a file from the object store
* @param {string} name Name of the file to download
* @param {string} originalFilename Overrules the file's originalFilename
* @returns {$.Deferred}
*/
function downloadFile(name, originalFilename) {
var deferred = $.Deferred();
//== Create stream for file to be streamed to and buffer to save chunks
var stream = ss.createStream(),
fileBuffer = [],
fileLength = 0;
//== Emit/Request
ss(mysocket).emit('filedownload', stream, name, function (fileError, fileInfo) {
if (fileError) {
deferred.reject(fileError);
} else {
console.log(['File Found!', fileInfo]);
//== Receive data
stream.on('data', function (chunk) {
fileLength += chunk.length;
var progress = Math.floor((fileLength / fileInfo.size) * 100);
progress = Math.max(progress - 2, 1);
deferred.notify(progress);
fileBuffer.push(chunk);
});
stream.on('end', function () {
var filedata = new Uint8Array(fileLength),
i = 0;
//== Loop to fill the final array
fileBuffer.forEach(function (buff) {
for (var j = 0; j < buff.length; j++) {
filedata[i] = buff[j];
i++;
}
});
deferred.notify(100);
//== Download file in browser
downloadFileFromBlob([filedata], originalFilename);
deferred.resolve();
});
}
});
//== Return
return deferred;
}
var downloadFileFromBlob = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
var blob = new Blob(data, {
type : "octet/stream"
}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
回答我亲爱的朋友Jeffrey van Norden是的。它对我有用。但是有一个小错误所以我这样更改了服务器端代码:
//== Server Side
ss(socket).on('filedownload', function (stream, name, callback) {
//== Do stuff to find your file
try {
let stats = fs.statSync(name);
let size = stats.size;
callback(false,{
name: name,
size: size
});
let MyFileStream = fs.createReadStream(name);
MyFileStream.pipe(stream);
}
catch (e){
callback(true,{});
}
});
//== Client Side
/** Download a file from the object store
* @param {string} name Name of the file to download
* @param {string} originalFilename Overrules the file's originalFilename
* @returns {$.Deferred}
*/
function downloadFile(name, originalFilename) {
var deferred = $.Deferred();
//== Create stream for file to be streamed to and buffer to save chunks
var stream = ss.createStream(),
fileBuffer = [],
fileLength = 0;
//== Emit/Request
ss(mysocket).emit('filedownload', stream, name, function (fileError, fileInfo) {
if (fileError) {
deferred.reject(fileError);
} else {
console.log(['File Found!', fileInfo]);
//== Receive data
stream.on('data', function (chunk) {
fileLength += chunk.length;
var progress = Math.floor((fileLength / fileInfo.size) * 100);
progress = Math.max(progress - 2, 1);
deferred.notify(progress);
fileBuffer.push(chunk);
});
stream.on('end', function () {
var filedata = new Uint8Array(fileLength),
i = 0;
//== Loop to fill the final array
fileBuffer.forEach(function (buff) {
for (var j = 0; j < buff.length; j++) {
filedata[i] = buff[j];
i++;
}
});
deferred.notify(100);
//== Download file in browser
downloadFileFromBlob([filedata], originalFilename);
deferred.resolve();
});
}
});
//== Return
return deferred;
}
var downloadFileFromBlob = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
var blob = new Blob(data, {
type : "octet/stream"
}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
我已经设法将文件从客户端分块上传到服务器,但现在我想以相反的方式实现。不幸的是,官方模块页面上缺少这部分的文档。
我想做以下事情:
- 向服务器发送一个流和 'download'-带有文件名的事件
- 服务器应该创建一个读取流并将其通过管道传输到从客户端发出的流
- 当客户端到达流时,应该会出现下载弹出窗口并询问文件的保存位置
我不想使用简单的文件超链接的原因是混淆:服务器上的文件被加密和重命名,所以我必须为每个下载请求解密和重命名它们。
是否有任何代码片段可以让我开始使用它?
这是我正在使用的一个工作示例。但是不知何故(也许只对我而言)这可能非常慢。
//== Server Side
ss(socket).on('filedownload', function (stream, name, callback) {
//== Do stuff to find your file
callback({
name : "filename",
size : 500
});
var MyFileStream = fs.createReadStream(name);
MyFileStream.pipe(stream);
});
//== Client Side
/** Download a file from the object store
* @param {string} name Name of the file to download
* @param {string} originalFilename Overrules the file's originalFilename
* @returns {$.Deferred}
*/
function downloadFile(name, originalFilename) {
var deferred = $.Deferred();
//== Create stream for file to be streamed to and buffer to save chunks
var stream = ss.createStream(),
fileBuffer = [],
fileLength = 0;
//== Emit/Request
ss(mysocket).emit('filedownload', stream, name, function (fileError, fileInfo) {
if (fileError) {
deferred.reject(fileError);
} else {
console.log(['File Found!', fileInfo]);
//== Receive data
stream.on('data', function (chunk) {
fileLength += chunk.length;
var progress = Math.floor((fileLength / fileInfo.size) * 100);
progress = Math.max(progress - 2, 1);
deferred.notify(progress);
fileBuffer.push(chunk);
});
stream.on('end', function () {
var filedata = new Uint8Array(fileLength),
i = 0;
//== Loop to fill the final array
fileBuffer.forEach(function (buff) {
for (var j = 0; j < buff.length; j++) {
filedata[i] = buff[j];
i++;
}
});
deferred.notify(100);
//== Download file in browser
downloadFileFromBlob([filedata], originalFilename);
deferred.resolve();
});
}
});
//== Return
return deferred;
}
var downloadFileFromBlob = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
var blob = new Blob(data, {
type : "octet/stream"
}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
回答我亲爱的朋友Jeffrey van Norden是的。它对我有用。但是有一个小错误所以我这样更改了服务器端代码:
//== Server Side
ss(socket).on('filedownload', function (stream, name, callback) {
//== Do stuff to find your file
try {
let stats = fs.statSync(name);
let size = stats.size;
callback(false,{
name: name,
size: size
});
let MyFileStream = fs.createReadStream(name);
MyFileStream.pipe(stream);
}
catch (e){
callback(true,{});
}
});
//== Client Side
/** Download a file from the object store
* @param {string} name Name of the file to download
* @param {string} originalFilename Overrules the file's originalFilename
* @returns {$.Deferred}
*/
function downloadFile(name, originalFilename) {
var deferred = $.Deferred();
//== Create stream for file to be streamed to and buffer to save chunks
var stream = ss.createStream(),
fileBuffer = [],
fileLength = 0;
//== Emit/Request
ss(mysocket).emit('filedownload', stream, name, function (fileError, fileInfo) {
if (fileError) {
deferred.reject(fileError);
} else {
console.log(['File Found!', fileInfo]);
//== Receive data
stream.on('data', function (chunk) {
fileLength += chunk.length;
var progress = Math.floor((fileLength / fileInfo.size) * 100);
progress = Math.max(progress - 2, 1);
deferred.notify(progress);
fileBuffer.push(chunk);
});
stream.on('end', function () {
var filedata = new Uint8Array(fileLength),
i = 0;
//== Loop to fill the final array
fileBuffer.forEach(function (buff) {
for (var j = 0; j < buff.length; j++) {
filedata[i] = buff[j];
i++;
}
});
deferred.notify(100);
//== Download file in browser
downloadFileFromBlob([filedata], originalFilename);
deferred.resolve();
});
}
});
//== Return
return deferred;
}
var downloadFileFromBlob = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
var blob = new Blob(data, {
type : "octet/stream"
}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());