Làm thế nào để ghi tệp nếu thư mục mẹ không tồn tại?


93

Tôi cần ghi tệp vào đường dẫn sau:

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

Nhưng '/folder1/folder2'đường dẫn có thể không tồn tại. Vì vậy, tôi nhận được lỗi sau:

message = ENOENT, mở /folder1/folder2/file.txt

Làm cách nào để viết nội dung vào đường dẫn đó?


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

Câu trả lời:


127

Sử dụng mkdirp kết hợp với path.dirnameđầu tiên.

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);
  });
}

Nếu toàn bộ đường dẫn đã tồn tại, mkdirplà một noop. Nếu không, nó tạo ra tất cả các thư mục bị thiếu cho bạn.

Mô-đun này thực hiện những gì bạn muốn: https://npmjs.org/package/writefile . Đã hiểu khi googling cho "writefile mkdirp". Mô-đun này trả về một lời hứa thay vì thực hiện cuộc gọi lại, vì vậy hãy nhớ đọc một số phần giới thiệu về các lời hứa trước. Nó thực sự có thể làm phức tạp mọi thứ cho bạn.

Chức năng tôi đã đưa ra hoạt động trong mọi trường hợp.


Vì vậy, nếu chúng ta muốn đợi nó hoàn thành, chúng ta phải đưa mọi thứ sau nó vào callback? Có một số cách khác?
pete

@pete nếu bạn sử dụng babel, bạn có thể đi với async / chờ đợi như ý chính sau: gist.github.com/lucasreppewelander/...
Lucas Reppe Welander

11
Sử dụng đệ quy:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
Offenso

27

Tôi thấy rằng cách dễ nhất để làm điều này là sử dụng phương thức outputFile () từ mô-đun fs-extra .

Gần giống như writeFile (tức là nó ghi đè lên), ngoại trừ việc nếu thư mục mẹ không tồn tại, nó sẽ được tạo. các tùy chọn là những gì bạn chuyển đến fs.writeFile ().

Thí dụ:

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!
    });
});

Nó cũng có hỗ trợ hứa hẹn ra khỏi hộp những ngày này !.


19

Có lẽ đơn giản nhất, bạn chỉ có thể sử dụng mô-đun fs-path npm.

Mã của bạn sau đó sẽ giống như sau:

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');
  }
});

18

Biên tập

Phiên bản NodeJS 10.12.0đã thêm một hỗ trợ riêng cho cả hai mkdirmkdirSyncđể tạo trình giám đốc cha một cách đệ quy với recursive: truetùy chọn như sau:

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

Và nếu bạn thích fs Promises API, bạn có thể viết

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

Câu trả lời gốc

Tạo các thư mục mẹ một cách đệ quy nếu chúng không tồn tại! ( Không phụ thuộc )

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);
}

Sử dụng

// 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');

Bản giới thiệu

Thử nó!

Giải thích

  • [UPDATE] lỗi xử lý giải pháp nền tảng cụ thể này giống như EISDIRcho Mac và EPERMEACCEScho Windows.
  • Giải pháp này xử lý cả đường dẫn tương đốituyệt đối .
  • Trong trường hợp đường dẫn tương đối, các thư mục đích sẽ được tạo (giải quyết) trong thư mục làm việc hiện tại. Để giải quyết chúng liên quan đến dir script hiện tại, hãy vượt qua {isRelativeToScript: true}.
  • Sử dụng path.seppath.resolve(), không chỉ /nối, để tránh các vấn đề đa nền tảng.
  • Sử dụng fs.mkdirSyncvà xử lý các lỗi với try/catchnếu ném để xử lý điều kiện chủng tộc: quá trình khác có thể thêm các tập tin giữa các cuộc gọi đến fs.existsSync()fs.mkdirSync()và gây ra một ngoại lệ.
    • Cách khác để đạt được điều đó có thể là kiểm tra xem tệp có tồn tại hay không rồi tạo tệp đó, tức là if (!fs.existsSync(curDir) fs.mkdirSync(curDir);,. Nhưng đây là một mẫu chống khiến mã dễ bị ảnh hưởng bởi các điều kiện chủng tộc.
  • Yêu cầu Node v6 và mới hơn để hỗ trợ hủy cấu trúc. (Nếu bạn gặp vấn đề khi triển khai giải pháp này với các phiên bản Node cũ, hãy để lại nhận xét cho tôi)

3

Bạn có thể dùng

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

statslà một fs.Statsloại đối tượng, bạn có thể kiểm tra stats.isDirectory(). Tùy thuộc vào việc kiểm tra errstatsbạn có thể làm gì đó, fs.mkdir( ... )hoặc mắc lỗi.

Tài liệu tham khảo

Cập nhật: Đã sửa lỗi dấu phẩy trong mã.


Vì vậy, tôi không thể ghi tệp bằng cách sử dụng lệnh sibgle trong nodejs?
Erik

2

Đây là hàm tùy chỉnh của tôi để tạo các thư mục một cách đệ quy (không có phụ thuộc bên ngoài):

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

Đây là hàm của tôi hoạt động trong Node 10.12.0. Hy vọng điều này sẽ giúp ích.

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!');
        });
    }

2

Với node-fs-extra, bạn có thể làm điều đó một cách dễ dàng.

Cài đặt nó

npm install --save fs-extra

Sau đó sử dụng phương thức outputFile thay vì 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!');
  }
})

0

Đây là một phần câu trả lời của Myrne Stol được chia thành một câu trả lời riêng:

Mô-đun này thực hiện những gì bạn muốn: https://npmjs.org/package/writefile . Đã hiểu khi googling cho "writefile mkdirp". Mô-đun này trả về một lời hứa thay vì thực hiện cuộc gọi lại, vì vậy hãy nhớ đọc một số phần giới thiệu về các lời hứa trước. Nó thực sự có thể làm phức tạp mọi thứ cho bạn.


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);
      });
    });
  }
);

Các câu trả lời chỉ có mã được coi là chất lượng thấp: hãy đảm bảo cung cấp lời giải thích mã của bạn hoạt động như thế nào và cách nó giải quyết vấn đề. Nó sẽ giúp ích cho cả người hỏi và người đọc trong tương lai nếu bạn có thể bổ sung thêm thông tin trong bài đăng của mình. Xem Giải thích các câu trả lời hoàn toàn dựa trên mã
Calos
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.