首页 > 解决方案 > 引用变量时 renameSync 不起作用

问题描述

我创建了一个脚本来将文件从 gridfs 迁移到新的本地 C: 驱动器,然后重命名文件,因为我无法使用带有 writeFileSync 的变量来动态命名包含扩展名的文件。

我遇到的问题是,当我在位置路径变量中使用任何变量时,它会返回一个错误,没有这样的文件或目录。当我明确写出字符串并且不使用变量时,它会毫无问题地找到它并正确重命名文件。相同的路径,只是创建路径的两种不同方法。可能是javascript的引用传递和值传递引起的问题?在这一点上没有想法。

我正在通过控制台记录所有路径进行调试,以确认最终目标字符串是否正确,并且已经验证使用引用变量时它与专门编写为单个字符串时完全相同。

fs.writeFileSync(__dirname + `/../public/uploads/${tempFile.metadata.parent}/${tempId}/tempfile`, data);


unprocessedPath1 = (__dirname + `/../public/uploads/${tempFile.metadata.parent}/${tempId}/tempfile`); //DOES NOT WORK
unprocessedPath2 = (__dirname + `/../public/uploads/${tempFile.metadata.parent}/${tempId}/${tempFile.filename}`); //DOES NOT WORK
//RETURNS: C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\tempfile
//RETURNS: C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\tempfile1

// unprocessedPath1 = `C:/Sites/CRM/public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60/tempfile`; // WORKS
// unprocessedPath2 = `C:/Sites/CRM/public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60/tempfile1`; // WORKS
//RETURNS: C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\tempfile
//RETURNS: C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\tempfile1

var correctPath1 = path.normalize(unprocessedPath1);
var correctPath2 = path.normalize(unprocessedPath2);

fs.renameSync(correctPath1, correctPath2, function(err) {
    if ( err ) console.log('RENAME ERROR: ' + err);
});


RENAME ERROR: Error: ENOENT: no such file or directory, rename 'C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\tempfile' -> 'C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\2019-08-16T10:50.wav'

编辑:在重命名尝试之前确认文件存在于目的地。在重命名之前添加了console.log(fs.existsSync(correctPath1))一行。

true
RENAME ERROR: Error: ENOENT: no such file or directory, rename 'C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\tempfile' -> 'C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\2019-08-16T10:50.wav'

编辑:这是整个请求。

//DOWNLOAD GRIDFS DATABASE'S OLD FILES AND SAVE TO LOCAL DRIVE
router.get('/export/gridfs', middleware.isLoggedIn, (req, res) => {
gfs = Grid(conn.db, mongoose.mongo);
gfs.collection('uploads').find().toArray((err, files) => {

    console.log("OPENING FILES OBJECT: ");    
    console.log(util.inspect(files, false, null, true /* enable colors */));

    files.forEach(file => {
        console.log("FOR EACH FILE");
        tempFile = file;

        console.log("CREATING FILE PRE SAVE");
        File.create(tempFile, function(err, file){
            console.log("FILE PRE CREATED");
            if(err){
                console.log("ERROR OCCURED: " + err);
                console.log("SKIPPING FILE");
            } else {
                console.log("NO ERROR");
                console.log(util.inspect(file, false, null, true /* enable colors */))
                console.log(util.inspect(tempFile, false, null, true /* enable colors */))
                console.log("MAKING NEW FOLDER IN LEAD ID USING FILE ID");
                console.log('public/uploads/' + tempFile.metadata.parent +"/"+ file._id);
                mkdirp('public/uploads/' + tempFile.metadata.parent +"/"+ file._id, function() {});
                console.log("FOLDER CREATED");

                console.log("File Before");
                console.log(file);

                console.log("OPENING file OBJECT: ");
                console.log(util.inspect(file, {showHidden: false, depth: null}))
                console.log("OPENING tempfile OBJECT: ");
                console.log(util.inspect(tempFile, false, null, true /* enable colors */))

                file.filename = tempFile.filename;
                file.contentType = tempFile.mimetype;
                file.fileLocation = `/public/uploads/${tempFile.metadata.parent}/${file._id}/${tempFile.filename}`;                    
                file.metadata = { parent: tempFile.metadata.parent };
                file.createdAt = tempFile.uploadDate;
                console.log("filename: " + file.filename);
                console.log("contentType" + file.contentType);
                console.log("fileLocation" + file.fileLocation);
                console.log("metadata: " + file.metadata);

                console.log("File After");
                console.log("FILE: " + file);
                console.log("tempFile: " + tempFile);


                console.log(tempFile.newFileName);
                console.log(tempFile.originalname);
                console.log(tempFile.mimetype);
                console.log(tempFile.contentType);

                console.log("File After");
                console.log(file);

                //save note
                file.save();
                console.log("File Saved");

                const tempId = file._id; 
                console.log("tempId: " + tempId);

                console.log("OPENING tempId OBJECT: ");
                console.log(util.inspect(tempId, false, null, true /* enable colors */));


                console.log("PROCESSING FILE");
                console.log(util.inspect(file, false, null, true /* enable colors */));

                console.log("Starting gridfs stream");

                gfs.files.find({ _id: new ObjectId(file._id) }, (err, file) => {
                    // Check if file
                    console.log("CHECKING FOR FILE ENTRY");
                    if (!file || file.length === 0) {
                        return res.status(404).json({
                            err: 'No file exists'
                        });
                    }

                    console.log("FILE ENTRY FOUND");

                    let data = [];
                    let readstream = gfs.createReadStream({
                        filename: tempFile.filename
                    });

                    console.log("Creating read stream");
                    readstream.on('data', function(chunk) {
                        console.log("PUSHING CHUNK");
                        console.log(chunk);
                        data.push(chunk);
                        console.log("PUSHED CHUNK");
                    });

                    readstream.on('end', function() {
                        console.log("ENDING STREAM");
                        data = Buffer.concat(data);
                        console.log("WRITING TO LOCAL DRIVE");

                        var fileExt = path.extname(tempFile.filename);
                        console.log(fileExt)


                        fs.writeFileSync(__dirname + `/../public/uploads/${tempFile.metadata.parent}/${tempId}/tempfile`, data);
                        console.log("RETURNING FILE TO CLIENT");

                        console.log("RENAMING FILE AT LOCATION WITH EXTENSION");

                        var unprocessedPath1 = (__dirname + `/../public/uploads/${tempFile.metadata.parent}/${tempId}/tempfile`);
                        var unprocessedPath1String = `C:/Sites/CRM/public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60/tempfile`; //works
                        console.log("Path1: " + unprocessedPath1);
                        console.log("Path1String: " + unprocessedPath1String);

                        var unprocessedPath2 = (__dirname + `/../public/uploads/${tempFile.metadata.parent}/${tempId}/${tempFile.filename}`);
                        // unprocessedPath2 = `C:/Sites/CRM/public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60/tempfile1`; //works
                        console.log("Path2: " + unprocessedPath2);

                        var correctPath1 = path.normalize(unprocessedPath1);
                        console.log("NORMALIZED Path1: "+ correctPath1);
                        var correctPath2 = path.normalize(unprocessedPath2);
                        console.log("NORMALIZED Path2: " + correctPath2);

                        // correctPath1 = String(correctPath1);
                        // correctPath2 = String(correctPath2);

                        console.log(fs.existsSync(correctPath1))
                        console.log(fs.existsSync(unprocessedPath1String))

                        fs.rename(correctPath1, correctPath2, function(err) {
                            if ( err ) console.log('RENAME ERROR: ' + err);
                            console.log("RENAME COMPLETE");
                        });

                    });

                    readstream.on('error', function(err) {
                        console.log('An error occured!', err);
                        throw err;
                    });


                    res.send("EXPORTED");

                });

            }
        });

    });
});
});

编辑:这是日志。

OPENING FILES OBJECT: 
[ { _id: 5d56ece48f6b3b09f0068f60,
    length: 221228,
    chunkSize: 261120,
    uploadDate: 2019-08-16T17:50:30.212Z,
    filename: '2019-08-16T10:50.wav',
    md5: '47fbec41801f73efc53d7e8f73b4e596',
    contentType: 'audio/wav',
    metadata: { parent: '5d56ebd88f6b3b09f0068f5c' } } ]
FOR EACH FILE
CREATING FILE PRE SAVE
FILE PRE CREATED
NO ERROR
{ _id: 5d56ece48f6b3b09f0068f60,
  filename: '2019-08-16T10:50.wav',
  contentType: 'audio/wav',
  metadata: { parent: '5d56ebd88f6b3b09f0068f5c' },
  createdAt: 2019-08-22T02:50:55.594Z,
  __v: 0 }
{ _id: 5d56ece48f6b3b09f0068f60,
  length: 221228,
  chunkSize: 261120,
  uploadDate: 2019-08-16T17:50:30.212Z,
  filename: '2019-08-16T10:50.wav',
  md5: '47fbec41801f73efc53d7e8f73b4e596',
  contentType: 'audio/wav',
  metadata: { parent: '5d56ebd88f6b3b09f0068f5c' } }
MAKING NEW FOLDER IN LEAD ID USING FILE ID
public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60
FOLDER CREATED
File Before
{ _id: 5d56ece48f6b3b09f0068f60,
  filename: '2019-08-16T10:50.wav',
  contentType: 'audio/wav',
  metadata: { parent: '5d56ebd88f6b3b09f0068f5c' },
  createdAt: 2019-08-22T02:50:55.594Z,
  __v: 0 }
OPENING file OBJECT: 
{ _id: 5d56ece48f6b3b09f0068f60,
  filename: '2019-08-16T10:50.wav',
  contentType: 'audio/wav',
  metadata: { parent: '5d56ebd88f6b3b09f0068f5c' },
  createdAt: 2019-08-22T02:50:55.594Z,
  __v: 0 }
OPENING tempfile OBJECT: 
{ _id: 5d56ece48f6b3b09f0068f60,
  length: 221228,
  chunkSize: 261120,
  uploadDate: 2019-08-16T17:50:30.212Z,
  filename: '2019-08-16T10:50.wav',
  md5: '47fbec41801f73efc53d7e8f73b4e596',
  contentType: 'audio/wav',
  metadata: { parent: '5d56ebd88f6b3b09f0068f5c' } }
filename: 2019-08-16T10:50.wav
contentTypeundefined
fileLocation/public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60/2019-08-16T10:50.wav
metadata: { parent: '5d56ebd88f6b3b09f0068f5c' }
File After
FILE: { _id: 5d56ece48f6b3b09f0068f60,
  filename: '2019-08-16T10:50.wav',
  metadata: { parent: '5d56ebd88f6b3b09f0068f5c' },
  createdAt: 2019-08-16T17:50:30.212Z,
  __v: 0,
  fileLocation: '/public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60/2019-08-16T10:50.wav' }
tempFile: [object Object]
undefined
undefined
undefined
audio/wav
File After
{ _id: 5d56ece48f6b3b09f0068f60,
  filename: '2019-08-16T10:50.wav',
  metadata: { parent: '5d56ebd88f6b3b09f0068f5c' },
  createdAt: 2019-08-16T17:50:30.212Z,
  __v: 0,
  fileLocation: '/public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60/2019-08-16T10:50.wav' }
File Saved
tempId: 5d56ece48f6b3b09f0068f60
OPENING tempId OBJECT:
5d56ece48f6b3b09f0068f60
PROCESSING FILE
{ _id: 5d56ece48f6b3b09f0068f60,
  filename: '2019-08-16T10:50.wav',
  metadata: { parent: '5d56ebd88f6b3b09f0068f5c' },
  createdAt: 2019-08-16T17:50:30.212Z,
  __v: 0,
  fileLocation: '/public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60/2019-08-16T10:50.wav' }
Starting gridfs stream
CHECKING FOR FILE ENTRY
FILE ENTRY FOUND
Creating read stream
(node:3008) DeprecationWarning: GridStore is deprecated, and will be removed in a future version. Please use GridFSBucket instead
PUSHING CHUNK
<Buffer 52 49 46 46 24 60 03 00 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 01 00 80 bb 00 00 00 ee 02 00 02 00 10 00 64 61 74 61 00 60 03 00 00 00 00 00 00 00 ... >
PUSHED CHUNK
(node:3008) DeprecationWarning: GridStore is deprecated, and will be removed in a future version. Please use GridFSBucket instead
PUSHING CHUNK
<Buffer 52 49 46 46 24 60 03 00 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 01 00 80 bb 00 00 00 ee 02 00 02 00 10 00 64 61 74 61 00 60 03 00 00 00 00 00 00 00 ... >
PUSHED CHUNK
PUSHING CHUNK
<Buffer 52 49 46 46 24 60 03 00 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 01 00 80 bb 00 00 00 ee 02 00 02 00 10 00 64 61 74 61 00 60 03 00 00 00 00 00 00 00 ... >
PUSHED CHUNK
ENDING STREAM
WRITING TO LOCAL DRIVE
.wav
RETURNING FILE TO CLIENT
RENAMING FILE AT LOCATION WITH EXTENSION
Path1: C:\Sites\CRM\routes/../public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60/tempfile
Path1String: C:/Sites/CRM/public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60/tempfile
Path2: C:\Sites\CRM\routes/../public/uploads/5d56ebd88f6b3b09f0068f5c/5d56ece48f6b3b09f0068f60/2019-08-16T10:50.wav
NORMALIZED Path1: C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\tempfile
NORMALIZED Path2: C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\2019-08-16T10:50.wav
true
true
RENAME ERROR: Error: ENOENT: no such file or directory, rename 'C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\tempfile' -> 'C:\Sites\CRM\public\uploads\5d56ebd88f6b3b09f0068f5c\5d56ece48f6b3b09f0068f60\2019-08-16T10:50.wav'
RENAME COMPLETE

标签: javascriptnode.jsexpresspath

解决方案


刚刚看到您添加的新代码。

在我看来,这就像使用异步操作的循环内的共享变量。

您的循环将与自身发生冲突。.forEach()不会等待您的异步操作完成,因此您将运行循环的多次迭代并尝试使用相同的变量。您可以通过停止循环中操作的并行运行或通过非常仔细地定义变量来修复,let以便它们对循环的每次迭代都是唯一的,并且不使用曾经修改过的共享变量。

分配给变量时出现问题的原因是该变量位于共享范围内,并且循环的所有迭代都试图使用相同的变量,其中一些相互冲突。

在内部修改的所有变量都.forEach()需要在内部声明,.forEach()因此它们对于循环的每次迭代都是唯一且独立的。它们都不应该在更高的范围内声明。

变量tempFile是问题的一部分。.forEach()在您的一些异步操作尝试使用它之前,它将被循环的后续迭代覆盖。你有这么多嵌套的异步操作,我没有研究异步回调中使用的每一个变量,看看哪些其他变量可能有同样的问题。

所以,你这样做的地方:

var unprocessedPath1 = (__dirname + `/../public/uploads/${tempFile.metadata.parent}/${tempId}/tempfile`);

tempfile很可能已经被循环的下一次迭代覆盖,因为这发生在深度嵌套的异步回调中,这些回调将在.forEach()循环已经完成并且其他值可能被写入之后被调用tempfile

仅供参考,您根本没有为tempFile变量显示任何声明,因此它可能是在更高范围内声明的,或者是意外的模块级变量。只需将其声明为:

let tempFile = file;

在您的.forEach()回调顶部将给循环的每次调用它自己的该变量的副本,并将至少解决第一个问题。


作为问题的简化示例,运行以下代码段:

const data = [1,2,3,4];
const base = "base";
let tempFile;

data.forEach(function(num) {
    tempFile = base + num;
    setTimeout(function() {
       console.log(tempFile);
    }, 1);
});

为简单起见,我setTimeout()在这里将其用作简单的异步回调,但您的代码中的问题是相同的,因为您tempFile在每次调用循环时都分配给它,然后在异步回调中引用它。

console.log(tempFile);没有显示所需的值,因为.forEach()循环在调用单个异步回调之前运行完成(node.js 事件循环的产物以及异步操作如何使用它)。


然而,如果您将声明移动tempFile到循环本身,则该变量的单独副本对于循环的每次迭代都是唯一的,您将获得所需的输出:

const data = [1,2,3,4];
const base = "base";

data.forEach(function(num) {
    let tempFile = base + num;
    setTimeout(function() {
       console.log(tempFile);
    }, 1);
});


推荐阅读