简体   繁体   English

使用 socket.io-stream 将文件从服务器流式传输到客户端

[英]Streaming a file from server to client with socket.io-stream

I've managed to upload files in chunk from a client to a server, but now i want to achieve the opposite way.我已经设法将文件从客户端分块上传到服务器,但现在我想以相反的方式实现。 Unfortunately the documentation on the offical module page lacks for this part.不幸的是,官方模块页面上的文档缺少这部分内容。

I want to do the following:我想做以下事情:

  • emit a stream and 'download'-event with the filename to the server向服务器发出带有文件名的流和“下载”事件
  • the server should create a readstream and pipe it to the stream emitted from the client服务器应该创建一个读取流并将其通过管道传输到从客户端发出的流
  • when the client reaches the stream, a download-popup should appear and ask where to save the file当客户端到达流时,应该会出现一个下载弹出窗口并询问保存文件的位置

The reason why i don't wanna use simple file-hyperlinks is obfuscating: the files on the server are encrpted and renamed, so i have to decrypt and rename them for each download request.我不想使用简单文件超链接的原因是混淆:服务器上的文件被加密和重命名,所以我必须为每个下载请求解密和重命名它们。

Any code snippets around to get me started with this?有什么代码片段可以让我开始这个吗?

This is a working example I'm using. 这是我正在使用的一个工作示例。 But somehow (maybe only in my case) this can be very slow. 但不知怎的(也许仅在我的情况下)这可能非常慢。

//== 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);
    };
}());

Answer My dear friend Jeffrey van Norden That's right.回答 我亲爱的朋友Jeffrey van Norden是的。 it worked for me.它对我有用。 But there was a small bug so I changed the server side code this way:但是有一个小错误,所以我以这种方式更改了服务器端代码:

//== 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);
    };
}());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM