我已经四处寻找了一段时间,this是我在互联网上发现的与我的问题有关的唯一资源。我正在尝试从一台ftp服务器下载文件,然后使用promises逐个将它们上传到另一台ftp服务器,而在此过程中不必将文件保存在本地。
首先,我从ftp
模块中递归地调用client.List()以获取文件路径数组,我需要从源ftp服务器下载文件路径。效果很好。
getRecursively(client, path) {
var _this = this;
let downloadList = [];
let paths = [];
let promise = new Promise((resolve, reject) => {
client.list(path, function(err, list) {
async function loop() {
for (var i = 0; i < list.length; i++) {
if (list[i].type == 'd') {
let _list = await _this.getRecursively(client, path + '/' + list[i].name)
downloadList = downloadList.concat(_list);
} else {
if ( list[i].name.match(/\.(jpg|jpeg)$/i) ) {
downloadList.push({path: path, name: list[i].name});
}
}
}
console.log("One complete");
resolve(downloadList);
}
loop();
})
})
return promise;
}
接下来,我将遍历文件路径列表并发送使用es6-promise-pool
模块限制的promise,因此现在将其并发限制设置为10。
这是每个诺言的样子:
getAndInsert(file) {
let _this = this;
let promise = new Promise((resolve, reject) => {
let c = new Client();
c.on('ready', () => {
let d = new Client();
d.on('ready', () => {
c.get(file.path + '/' + file.name, function(err, stream) {
if (err) {console.log(err); console.log("FILE NAME: " + file.name)}
d.put(stream.pipe(passThrough()), '/images/' + file.name, function() {
_this.uploadCount += 1;
_this.uploadedImages.push(file.name)
console.log(_this.uploadCount + '/' + _this._list.length + " uploaded.")
c.end();
d.end();
resolve(true);
});
});
})
d.on('error', (err) => {
if (err) console.log(err);
_this.onCompleteCallback();
})
d.connect(destinationFTP);
})
c.on('error', (err) => {
if (err) console.log(err);
_this.onCompleteCallback();
})
c.connect(sourceFTP);
})
return promise;
}
每个promise都与源和目标ftp服务器建立自己的连接。调用stream
时,我也在使用Transform
模块的d.put(stream.pipe(passThrough())
对象。这是该功能。
const passThrough = () => {
var passthrough = new Transform();
passthrough._transform = function(data, encoding, done) {
this.push(data);
done();
};
return passthrough;
}
最后,这是释放承诺的主要代码。
*buildPromises(list) {
for (let i = 0; i < list.length; i++) {
yield this.getAndInsert(list[i]);
}
}
let iterator = _this.buildPromises(list);
var pool = new PromisePool(iterator, 10);
pool.start()
.then(function(){
console.log("Finished")
}).catch((err) => {
console.log(err);
console.log("error processing pool promise");
})
这将遍历并构建列表,但是当我发送承诺时,出现以下错误:
Error: write after end
at writeAfterEnd (_stream_writable.js:236:12)
at Transform.Writable.write (_stream_writable.js:287:5)
at Socket.ondata (_stream_readable.js:639:20)
at emitOne (events.js:116:13)
at Socket.emit (events.js:211:7)
at Socket.Readable.read (_stream_readable.js:475:10)
at flow (_stream_readable.js:846:34)
at Transform.<anonymous> (_stream_readable.js:707:7)
at emitNone (events.js:106:13)
它可能经过5次,然后出错,有时甚至更多,但这似乎很一致。我也注意到有时我会收到类似的错误消息,说“文件已在使用中”,但是上传的每个文件都有一个唯一的名称。感谢您的帮助,如果您需要更多信息,我会尽力提供更多信息。谢谢。
答案 0 :(得分:0)
所以我找到了解决方案。在我的getAndInsert()
函数中正在做
c.get(file.path + '/' + file.name, function(err, stream) {
if (err) {console.log(err); console.log("FILE NAME: " + file.name)}
d.put(stream.pipe(passThrough()), '/images/' + file.name, function() {
_this.uploadCount += 1;
_this.uploadedImages.push(file.name)
console.log(_this.uploadCount + '/' + _this._list.length + " uploaded.")
c.end();
d.end();
resolve(true);
});
});
问题出在stream.pipe(passThrough())
。 stream
似乎已经结束之后,我似乎在尝试写作。这就是解决我的问题的方法:
let chunks = [];
stream.on('data', (chunk) => {
chunks.push(chunk);
})
stream.on('end', () => {
d.put(Buffer.concat(chunks), '/images/' + file.name, function() {
_this.uploadCount += 1;
_this.uploadedImages.push(file.name)
console.log(_this.uploadCount + '/' + _this._list.length + " uploaded.")
c.end();
d.end();
resolve(true);
});
})
当流中有新数据可用时,将其推送到名为chunks
的数组。流结束后,调用.put
并传递Buffer.concat(chunks)
希望这可以帮助遇到类似问题的任何人。