จะเขียนไฟล์ได้อย่างไรหากไม่มีโฟลเดอร์หลัก


96

ฉันต้องการเขียนไฟล์ไปยังเส้นทางต่อไปนี้:

fs.writeFile('/folder1/folder2/file.txt', 'content', function () {…});

แต่'/folder1/folder2'เส้นทางอาจไม่มีอยู่จริง ดังนั้นฉันจึงได้รับข้อผิดพลาดต่อไปนี้:

ข้อความ = ENOENT เปิด /folder1/folder2/file.txt

ฉันจะเขียนเนื้อหาในเส้นทางนั้นได้อย่างไร


2
fs.promises.mkdir(path.dirname('/folder1/folder2/file.txt'), {recursive: true}).then(x => fs.promises.writeFile('/folder1/folder2/file.txt', 'content'))
Offenso

คำตอบ:


135

ใช้mkdirpร่วมกับpath.dirnameครั้งแรก

var mkdirp = require('mkdirp');
var fs = require('fs');
var getDirName = require('path').dirname;

function writeFile(path, contents, cb) {
  mkdirp(getDirName(path), function (err) {
    if (err) return cb(err);

    fs.writeFile(path, contents, cb);
  });
}

หากเส้นทางทั้งหมดมีอยู่แล้วmkdirpก็คือ noop มิฉะนั้นจะสร้างไดเรกทอรีที่ขาดหายไปทั้งหมดสำหรับคุณ

โมดูลนี้ทำสิ่งที่คุณต้องการ: https://npmjs.org/package/writefile https://npmjs.org/package/writefileเข้าใจแล้วเมื่อ googling สำหรับ "writefile mkdirp" โมดูลนี้ส่งคืนคำสัญญาแทนการโทรกลับดังนั้นอย่าลืมอ่านบทนำเกี่ยวกับสัญญาก่อน จริงๆแล้วมันอาจทำให้คุณยุ่งยาก

ฟังก์ชั่นที่ฉันให้ใช้งานได้ในทุกกรณี


ดังนั้นถ้าเราต้องการรอให้มันเสร็จสมบูรณ์เราต้องใส่ทุกอย่างหลังจากนั้นลงใน callback? มีวิธีอื่นอีกไหม?
pete

@pete ถ้าคุณใช้ babel คุณสามารถใช้ async / รอเช่นนี้ส่วนสำคัญ: gist.github.com/lucasreppewelander/…
Lucas Reppe Welander

12
ใช้การเรียกซ้ำ:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
Offenso

27

ฉันพบว่าวิธีที่ง่ายที่สุดในการทำเช่นนี้คือใช้เมธอด outputFile () จากโมดูลfs-extra

เกือบจะเหมือนกับ writeFile (กล่าวคือเขียนทับ) ยกเว้นว่าถ้าไม่มีไดเร็กทอรีหลักจะถูกสร้างขึ้น ตัวเลือกคือสิ่งที่คุณส่งไปยัง fs.writeFile ()

ตัวอย่าง:

var fs = require('fs-extra');
var file = '/tmp/this/path/does/not/exist/file.txt'

fs.outputFile(file, 'hello!', function (err) {
    console.log(err); // => null

    fs.readFile(file, 'utf8', function (err, data) {
        console.log(data); // => hello!
    });
});

วันนี้ยังมีสัญญาสนับสนุนนอกกรอบอีกด้วย!


21

แก้ไข

เวอร์ชัน NodeJS 10.12.0ได้เพิ่มการสนับสนุนเนทีฟสำหรับทั้งสองอย่างmkdirและmkdirSyncเพื่อสร้างพาเรนต์ไดเร็กทอรีแบบวนซ้ำโดยมีrecursive: trueอ็อพชันดังต่อไปนี้:

fs.mkdirSync(targetDir, { recursive: true });

และถ้าคุณต้องการfs Promises APIคุณสามารถเขียน

fs.promises.mkdir(targetDir, { recursive: true });

คำตอบเดิม

สร้างไดเร็กทอรีพาเรนต์แบบวนซ้ำหากไม่มีอยู่! ( ศูนย์การพึ่งพา )

const fs = require('fs');
const path = require('path');

function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) {
  const sep = path.sep;
  const initDir = path.isAbsolute(targetDir) ? sep : '';
  const baseDir = isRelativeToScript ? __dirname : '.';

  return targetDir.split(sep).reduce((parentDir, childDir) => {
    const curDir = path.resolve(baseDir, parentDir, childDir);
    try {
      fs.mkdirSync(curDir);
    } catch (err) {
      if (err.code === 'EEXIST') { // curDir already exists!
        return curDir;
      }

      // To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
      if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
        throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
      }

      const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
      if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
        throw err; // Throw if it's just the last created dir.
      }
    }

    return curDir;
  }, initDir);
}

การใช้งาน

// Default, make directories relative to current working directory.
mkDirByPathSync('path/to/dir');

// Make directories relative to the current script.
mkDirByPathSync('path/to/dir', {isRelativeToScript: true});

// Make directories with an absolute path.
mkDirByPathSync('/path/to/dir');

การสาธิต

ลองมัน!

คำอธิบาย

  • [อัปเดต]โซลูชันนี้จัดการข้อผิดพลาดเฉพาะแพลตฟอร์มเช่นEISDIRสำหรับ Mac EPERMและEACCESสำหรับ Windows
  • โซลูชันนี้จัดการทั้งเส้นทางสัมพัทธ์และเส้นทางสัมบูรณ์
  • ในกรณีของพา ธ สัมพัทธ์ไดเร็กทอรีเป้าหมายจะถูกสร้าง (แก้ไข) ในไดเร็กทอรีการทำงานปัจจุบัน หากต้องการแก้ไขให้สัมพันธ์กับ dir สคริปต์ปัจจุบันให้ส่งผ่าน{isRelativeToScript: true}สคริปต์ปัจจุบันผ่าน
  • การใช้path.sepและpath.resolve()ไม่ใช่แค่/ต่อเพื่อหลีกเลี่ยงปัญหาข้ามแพลตฟอร์ม
  • การใช้fs.mkdirSyncและจัดการข้อผิดพลาดด้วยtry/catchif throw เพื่อจัดการกับเงื่อนไขการแข่งขัน: กระบวนการอื่นอาจเพิ่มไฟล์ระหว่างการโทรไปยังfs.existsSync()และfs.mkdirSync()และทำให้เกิดข้อยกเว้น
    • อีกวิธีหนึ่งในการบรรลุเป้าหมายนั้นคือการตรวจสอบว่ามีไฟล์อยู่หรือไม่จากนั้นจึงสร้างไฟล์ขึ้นมาif (!fs.existsSync(curDir) fs.mkdirSync(curDir);เช่น แต่นี่เป็นการต่อต้านรูปแบบที่ทำให้โค้ดเสี่ยงต่อสภาวะการแข่งขัน
  • ต้องการNode v6และใหม่กว่าเพื่อรองรับการทำลายโครงสร้าง (หากคุณมีปัญหาในการใช้งานโซลูชันนี้กับ Node เวอร์ชันเก่าเพียงแค่แสดงความคิดเห็น)

19

บางทีง่ายที่สุดคุณสามารถใช้โมดูล npm fs-path

รหัสของคุณจะมีลักษณะดังนี้:

var fsPath = require('fs-path');

fsPath.writeFile('/folder1/folder2/file.txt', 'content', function(err){
  if(err) {
    throw err;
  } else {
    console.log('wrote a file like DaVinci drew machines');
  }
});

3

คุณสามารถใช้ได้

fs.stat('/folder1/folder2', function(err, stats){ ... });

statsเป็นfs.Statsวัตถุประเภทหนึ่งคุณสามารถตรวจสอบstats.isDirectory()ได้ ขึ้นอยู่กับการตรวจสอบerrและstatsคุณสามารถทำบางสิ่งบางอย่างfs.mkdir( ... )หรือโยนข้อผิดพลาด

ข้อมูลอ้างอิง

อัปเดต: แก้ไขเครื่องหมายจุลภาคในรหัส


ดังนั้นฉันจึงไม่สามารถเขียนไฟล์โดยใช้คำสั่ง sibgle ใน nodejs?
Erik

3

ด้วย node-fs-extra คุณสามารถทำได้อย่างง่ายดาย

ติดตั้ง

npm install --save fs-extra

จากนั้นใช้เมธอดoutputFileแทนwriteFileSync

const fs = require('fs-extra');

fs.outputFile('tmp/test.txt', 'Hey there!', err => {
  if(err) {
    console.log(err);
  } else {
    console.log('The file was saved!');
  }
})

2

นี่คือฟังก์ชั่นที่กำหนดเองของฉันเพื่อสร้างไดเรกทอรีซ้ำ ๆ (โดยไม่มีการอ้างอิงภายนอก):

var fs = require('fs');
var path = require('path');

var myMkdirSync = function(dir){
    if (fs.existsSync(dir)){
        return
    }

    try{
        fs.mkdirSync(dir)
    }catch(err){
        if(err.code == 'ENOENT'){
            myMkdirSync(path.dirname(dir)) //create parent dir
            myMkdirSync(dir) //create dir
        }
    }
}

myMkdirSync(path.dirname(filePath));
var file = fs.createWriteStream(filePath);

2

นี่คือฟังก์ชั่นของฉันที่ใช้งานได้ในโหนด 10.12.0 หวังว่านี่จะช่วยได้

const fs = require('fs');
function(dir,filename,content){
        fs.promises.mkdir(dir, { recursive: true }).catch(error => { console.error('caught exception : ', error.message); });
        fs.writeFile(dir+filename, content, function (err) {
            if (err) throw err;
            console.info('file saved!');
        });
    }

0
let name = "./new_folder/" + file_name + ".png";
await driver.takeScreenshot().then(
  function(image, err) {
    require('mkdirp')(require('path').dirname(name), (err) => {
      require('fs').writeFile(name, image, 'base64', function(err) {
        console.log(err);
      });
    });
  }
);

คำตอบที่ใช้โค้ดอย่างเดียวถือว่ามีคุณภาพต่ำ: อย่าลืมให้คำอธิบายว่าโค้ดของคุณใช้ทำอะไรและแก้ไขปัญหาได้อย่างไร จะช่วยให้ผู้ถามและผู้อ่านในอนาคตทั้งสองอย่างหากคุณสามารถเพิ่มข้อมูลเพิ่มเติมในโพสต์ของคุณได้ ดูการอธิบายคำตอบที่ใช้รหัสทั้งหมด
Calos

-1

นี่คือส่วนหนึ่งของคำตอบของ Myrne Stol แยกออกเป็นคำตอบแยกต่างหาก:

โมดูลนี้จะทำในสิ่งที่คุณต้องการ: https://npmjs.org/package/writefile เข้าใจแล้วเมื่อ googling สำหรับ "writefile mkdirp" โมดูลนี้ส่งคืนคำสัญญาแทนการโทรกลับดังนั้นอย่าลืมอ่านบทนำเกี่ยวกับคำสัญญาก่อน มันอาจจะทำให้คุณยุ่งยาก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.