2017-11-17 3 views
2

アップロードされたファイルを整理する必要があるアプリケーションを開発しています。このIDを取得するにはexpress-request-idを使用します)。Node.jsのfs.rename()をループ内で実行しているときにエラーが発生しました

問題は、1つ以上のファイルがあるたびに「移動」プロセスが失敗し、修正できないように見えることです。

let request_folder = path.resolve(tmp_folder + "/" + req.id); 

/* Checking if the folder exists */ 
fs.access(request_folder, fs.constants.F_OK, function(error) { 
    if(error) { // it doesn't 
     /* Trying to create it */ 
     fs.mkdir(request_folder, function(error) { 
      if(error) { 
       console.log("Error: Couldn't create the directory."); 
       console.log(error); 
      } 
     }); 
    } 
}); 

/* Moving uploaded files to their respective request folder */ 
req.files.forEach(function(file) { 
    let new_file_path = path.resolve(request_folder + "/" + file.filename); 
    fs.rename(file.path, new_file_path, function(error) { 
     if(error) { 
      console.log("Error: Couldn't move " + file.filename + "."); 
      console.log(error); 
     } 
    }); 
}); 

私は私が手に一度に2つのファイルを移動しようとすると、フォルダやファイルの両方が存在するが、私百パーセント確信している:

Error: Couldn't move Desert.jpg. 
{ Error: ENOENT: no such file or directory, rename 'C:\Users\telmo.silva\csc-links\public\tmp\Desert.jpg' -> 'C:\Users\telmo.silva\csc-links\public\tmp\d2abf375-d09f-440c-a5ba-adf4f5725a73 
\Desert.jpg' 
    errno: -4058, 
    code: 'ENOENT', 
    syscall: 'rename', 
    path: 'C:\\Users\\telmo.silva\\csc-links\\public\\tmp\\Desert.jpg', 
    dest: 'C:\\Users\\telmo.silva\\csc-links\\public\\tmp\\d2abf375-d09f-440c-a5ba-adf4f5725a73\\Desert.jpg' } 
Error: Couldn't move Chrysanthemum.jpg. 
{ Error: ENOENT: no such file or directory, rename 'C:\Users\telmo.silva\csc-links\public\tmp\Chrysanthemum.jpg' -> 'C:\Users\telmo.silva\csc-links\public\tmp\d2abf375-d09f-440c-a5ba-adf4f 
5725a73\Chrysanthemum.jpg' 
    errno: -4058, 
    code: 'ENOENT', 
    syscall: 'rename', 
    path: 'C:\\Users\\telmo.silva\\csc-links\\public\\tmp\\Chrysanthemum.jpg', 
    dest: 'C:\\Users\\telmo.silva\\csc-links\\public\\tmp\\d2abf375-d09f-440c-a5ba-adf4f5725a73\\Chrysanthemum.jpg' } 

誰もが私が間違っているのか知っています?ありがとう!

答えて

3

使用している操作は非同期であり、どのような順序でも実行できます。

あなたのループは、ノードにフォルダを作成し、基本的に同時にファイルを移動するよう要求します。言い換えれば、すべてのfsアクションを同時にディスパッチする同期ループを実行します。実際に最初に何が実行されるかを保証していないということを意味します。

すべてのファイルを移動する前にフォルダを作成してみてください:

const access = util.promisify(fs.access); 
const mkdir = util.promisify(fs.mkdir); 
const rename = util.promisify(fs.rename); 

access(request_folder, fs.constants.F_OK) 
    .then(moveFiles, makeDirAndMoveFiles) 
    .catch(console.error); 

function moveFiles() { 
    return Promise.all(
    req.files.map(file => { 
     const new_file_path = path.resolve(request_folder + "/" + file.filename); 
     return rename(file.path, new_file_path); 
    }) 
) 
} 

function makeDirAndMoveFiles() { 
    return mkdir(request_folder).then(moveFiles); 
} 
+1

両方の機能が非同期であるため、操作順序が反転する可能性があります。コールバックと約束の両方でそれを修正する方法を示すので、私はあなたの答えを選んだ。 –

1

あなたが前であっても、ファイルを移動しようとしている可能です:このビットクリーナーになるかもしれない約束を使用して

fs.access(request_folder, fs.constants.F_OK, function(error) { 
    if(error) { 
     return fs.mkdir(request_folder, function(error) { 
      if(error) { 
       return; 
      } 
      moveFiles(); 
     }); 
    } 
    moveFiles(); 
}); 

function moveFiles() { 
    req.files.forEach(function(file) { 
    // ... 
    }); 
} 

宛先フォルダが存在します。

コードを構造化するために新しいawaitキーワードを試してください。

const {promisify} = require('util'); 

const fs = require('fs'); 
const accessFileAsync = promisify(fs.access); 
const mkdirFileAsync = promisify(fs.mkdir); 
const renameFileAsync = promisify(fs.rename); 
try{ 
    await accessFileAsync(request_folder, fs.constants.F_OK); 
} 
catch(ex) 
{ 
    await mkdirFileAsync(request_folder); 
} 
req.files.forEach(function(file) { 
    let new_file_path = path.resolve(request_folder + "/" + file.filename); 
    try{ 
     await renameFileAsync(file.path, new_file_path); 
    } 
    catch(ex) 
    { 
     console.log(ex); 
    } 
}); 
+0

'await'は' async'関数内でしか使用できません – nem035

+0

あなたの答えをありがとう、本当に私は優先順位を保証せずに2つの非同期関数を使用しています。私はコールバックと約束の両方をコード化する方法を示すので、私は他の答えを受け入れることになった。 –

+0

上記のように、非同期関数内でのみawaitを使用できます。 – Ankur

関連する問題