Подтвердить что ты не робот

Создание файла только в том случае, если он не существует в Node.js

У нас есть буфер, который мы хотели бы записать в файл. Если файл уже существует, нам нужно увеличить индекс на нем и повторить попытку. Есть ли способ создать файл только в том случае, если он не существует, или я должен просто ставить файлы, пока не получу ошибку, чтобы найти тот, который еще не существует?

Например, у меня есть файлы a_1.jpg и a_2.jpg. Я хочу, чтобы мой метод попытался создать a_1.jpg и a_2.jpg, и завершился сбой, и, наконец, успешно создал a_3.jpg.

Идеальный метод будет выглядеть примерно так:

fs.writeFile(path, data, { overwrite: false }, function (err) {
  if (err) throw err;
  console.log('It\ saved!');
});

или вот так:

fs.createWriteStream(path, { overwrite: false });

Есть ли что-нибудь подобное в библиотеке node fs?

EDIT: Мой вопрос не в том, есть ли отдельная функция, которая проверяет существование. Это так: есть ли способ создать файл, если он не существует, в одном системном вызове?

4b9b3361

Ответ 1

Как правильно догадалась ваша интуиция, наивное решение с помощью пары вызовов exists / writeFile неверно. Асинхронный код работает непредсказуемым образом. И в данном случае это

  • Есть ли файл a.txt? - Нет.
  • (Файл a.txt создается другой программой)
  • Напишите a.txt, если это возможно. - Хорошо.

Но да, мы можем сделать это за один раз. Мы работаем с файловой системой, поэтому рекомендуется прочитать инструкцию по эксплуатации на fs. И эй, здесь интересная часть.

'w' - открыть файл для записи. Файл создается (если он не существует) или усечено (если оно существует).

'wx' - Как и 'w', но не работает, если существует путь.

Итак, все, что нам нужно сделать, это просто добавить wx в вызов fs.open. Но, эй, нам не нравится fopen -like IO. Давайте немного почитаем fs.writeFile.

fs.readFile(имя файла [, опции], обратный вызов) #

filename String

options Объект

кодировка String | Null default = null

     

flag String default = 'r'

функция обратного вызова

Это options.flag выглядит многообещающим. Поэтому мы стараемся

fs.writeFile(path, data, { flag: 'wx' }, function (err) {
    if (err) throw err;
    console.log("It saved!");
});

И он отлично работает для одной записи. Я предполагаю, что этот код не сработает еще более причудливыми способами, но если вы попытаетесь решить свою задачу с ним. У вас есть атомарная проверка на существование a_#.jpg и запись там, если она пуста ", но все остальные состояния fs не заблокированы, а файл a_1.jpg может спонтанно исчезнуть, пока вы уже проверяете a_5.jpg, Большинство файловых систем * не являются ACID, и тот факт, что вы можете выполнять хотя бы некоторые атомные операции, чудесен. Очень вероятно, что код wx не будет работать на какой-либо платформе. Поэтому, ради вашего здравомыслия, используйте базу данных, наконец.

Дополнительная информация о страданиях

Представьте, что мы пишем что-то вроде memoize-fs, которое кэширует результаты вызовов функций в файловой системе, чтобы сэкономить нам время сети/процессора, Можем ли мы открыть файл для чтения, если он существует, и для записи, если это не так, все в одном вызове? Позвольте взглянуть на эти флаги смешно. Через некоторое время умственные упражнения мы видим, что a+ делает то, что мы хотим: если файл не существует, он создает один и открывает его как для чтения, так и для записи, и если файл существует, он делает это, не очищая файл (как w+). Но теперь мы не можем использовать его ни в (smth)File, ни в функциях create(Smth)Stream. И это кажется недостающей особенностью.

Поэтому не стесняйтесь записывать его как запрос функции (или даже ошибку) в Node.js github, так как отсутствие асинхронной API асинхронной файловой системы является недостатком Node. Хотя не ожидает изменений в ближайшее время.

Ответ 2

Что об использовании a вариант?

Согласно документам:

'a+' - Открыть файл для чтения и добавления. Файл создается, если он не существует.

Кажется, отлично работает с createWriteStream

Ответ 3

Этот метод больше не рекомендуется. fs.exists устарела. Смотрите комментарии.

Вот несколько вариантов:

1) Иметь 2 "фс" звонка. Первый - это вызов " fs.exists ", а второй - " fs.write/read и т.д."

//checks if the file exists. 
//If it does, it just calls back.
//If it doesn't, then the file is created.
function checkForFile(fileName,callback)
{
    fs.exists(fileName, function (exists) {
        if(exists)
        {
            callback();
        }else
        {
            fs.writeFile(fileName, {flag: 'wx'}, function (err, data) 
            { 
                callback();
            })
        }
    });
}

function writeToFile()
{
    checkForFile("file.dat",function()
    {
       //It is now safe to write/read to file.dat
       fs.readFile("file.dat", function (err,data) 
       {
          //do stuff
       });
    });
}

2) Или сначала создайте пустой файл:

--- Синхронизация:

//If you want to force the file to be empty then you want to use the 'w' flag:

var fd = fs.openSync(filepath, 'w');

//That will truncate the file if it exists and create it if it doesn't.

//Wrap it in an fs.closeSync call if you don't need the file descriptor it returns.

fs.closeSync(fs.openSync(filepath, 'w'));

--- ASync:

var fs = require("fs");
fs.open(path, "wx", function (err, fd) {
    // handle error
    fs.close(fd, function (err) {
        // handle error
    });
});

3) Или используйте " touch ": https://github.com/isaacs/node-touch

Ответ 4

В этом случае в одном системном вызове вы можете использовать модуль fs-extra npm. После этого будет создан файл, а также каталог, в который он будет помещен.

const fs = require('fs-extra');
const file = '/tmp/this/path/does/not/exist/file.txt'
fs.ensureFile(file, err => {
    console.log(err) // => null
});

Другой способ - использовать secureFileSync, который будет делать то же самое, но синхронно.

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

Ответ 5

Вы можете сделать что-то вроде этого:

function writeFile(i){
    var i = i || 0;
    var fileName = 'a_' + i + '.jpg';
    fs.exists(fileName, function (exists) {
        if(exists){
            writeFile(++i);
        } else {
            fs.writeFile(fileName);
        }
    });
}