Можно ли изменить часть файла в NodeJS без перезаписи всего файла? [Дубликат]

function get_json(txt)
{  var data

   try     {  data = eval('('+txt+')'); }
   catch(e){  data = false;             }

   return data;
}

Если есть ошибки, верните false.

Если ошибок нет, верните данные json

96
задан Andreas Köberle 6 January 2013 в 00:28
поделиться

8 ответов

Вы можете использовать простое регулярное выражение:

var result = fileAsString.replace(/string to be replaced/g, 'replacement');

Итак ...

var fs = require('fs')
fs.readFile(someFile, 'utf8', function (err,data) {
  if (err) {
    return console.log(err);
  }
  var result = data.replace(/string to be replaced/g, 'replacement');

  fs.writeFile(someFile, result, 'utf8', function (err) {
     if (err) return console.log(err);
  });
});
183
ответ дан Jonathan Lin 19 August 2018 в 03:57
поделиться
  • 1
    Конечно, но мне нужно прочитать файл, чтобы заменить текст, а затем снова записать файл, или есть более простой способ, извините, что я больше сторонник. – Andreas Köberle 6 January 2013 в 14:50
  • 2
    Возможно, для этого есть модуль узла, но я не знаю об этом. Добавлен полный пример кстати. – asgoth 6 January 2013 в 22:40
  • 3
    небольшая ошибка, замените в строке 6 'someFile' на "data" – Zax 10 May 2013 в 12:49
  • 4
    @Zax: Спасибо, я удивлен, что эта ошибка может так долго выжить;) – asgoth 10 May 2013 в 21:20
  • 5
    извините, я знаю, что utf-8 поддерживает многие языки, такие как: vietnamese, chinese ... – vuhung3990 19 October 2016 в 02:24

Поскольку замена не работала для меня, я создал простой пакет npm replace-in-file , чтобы быстро заменить текст в одном или нескольких файлах. Это частично основано на ответе @ asgoth.

Edit (3 октября 2016 г.): пакет теперь поддерживает обещания и глобусы, а инструкции по использованию были обновлены, чтобы отразить это.

Изменить ( 16 марта 2018 г.): этот пакет собрал более 100 тыс. Ежемесячных загрузок и был расширен дополнительными функциями, а также инструментом CLI.

Установка:

npm install replace-in-file

Требовать модуль

const replace = require('replace-in-file');

Укажите опции замены

const options = {

  //Single file
  files: 'path/to/file',

  //Multiple files
  files: [
    'path/to/file',
    'path/to/other/file',
  ],

  //Glob(s) 
  files: [
    'path/to/files/*.html',
    'another/**/*.path',
  ],

  //Replacement to make (string or regex) 
  from: /Find me/g,
  to: 'Replacement',
};

Асинхронная замена с обещаниями:

replace(options)
  .then(changedFiles => {
    console.log('Modified files:', changedFiles.join(', '));
  })
  .catch(error => {
    console.error('Error occurred:', error);
  });

Асинхронная замена с обратным вызовом:

replace(options, (error, changedFiles) => {
  if (error) {
    return console.error('Error occurred:', error);
  }
  console.log('Modified files:', changedFiles.join(', '));
});

Синхронная замена:

try {
  let changedFiles = replace.sync(options);
  console.log('Modified files:', changedFiles.join(', '));
}
catch (error) {
  console.error('Error occurred:', error);
}
29
ответ дан Adam Reis 19 August 2018 в 03:57
поделиться
  • 1
    Отличный и простой в использовании модуль под ключ. Использовал его с async / await и glob над довольно большой папкой, и это было молниеносно – Matt Fletcher 17 May 2018 в 09:07

Возможно, модуль «replace» ( www.npmjs.org/package/replace ) также будет работать для вас. Это не потребует, чтобы вы прочитали и затем записали файл.

Адаптировано из документации:

// install:

npm install replace 

// require:

var replace = require("replace");

// use:

replace({
    regex: "string to be replaced",
    replacement: "replacement string",
    paths: ['path/to/your/file'],
    recursive: true,
    silent: true,
});
27
ответ дан Gabriel 19 August 2018 в 03:57
поделиться
  • 1
    Знаете ли вы, как фильтровать по расширению файла в путях? что-то вроде путей: ['путь / в / ваш / файл / *. js'] - & gt; он не работает – Kalamarico 24 June 2015 в 07:44
  • 2
    Вы можете использовать node-glob для расширения шаблонов glob для массива путей, а затем итерации по ним. – RobW 31 August 2015 в 17:55
  • 3
    Это хорошо, но он оставлен. См. stackoverflow.com/a/31040890/1825390 для поддерживаемого пакета, если вы хотите готовое решение. – xavdid 24 August 2016 в 08:40
  • 4
    Существует также поддерживаемая версия, называемая node-replace ; однако, не глядя на базу кода, ни замену в файле на самом деле заменить текст в файле, они используют readFile() и writeFile() так же, как и принятый ответ. – c1moore 8 February 2018 в 16:19

ES2017 / 8 для узла 7.6+ с временным файлом записи для замены атома.

const Promise = require('bluebird')
const fs = Promise.promisifyAll(require('fs'))

async function replaceRegexInFile(file, search, replace){
  let contents = await fs.readFileAsync(file, 'utf8')
  let replaced_contents = contents.replace(search, replace)
  let tmpfile = `${file}.jstmpreplace`
  await fs.writeFileAsync(tmpfile, replaced_contents, 'utf8')
  await fs.renameAsync(tmpfile, file)
  return true
}

Обратите внимание, что только для небольших файлов, поскольку они будут считаны в памяти.

0
ответ дан Matt 19 August 2018 в 03:57
поделиться
  • 1
    Нет необходимости в bluebird, используйте native Promise и util.promisify . – Francisco Mateo 4 December 2017 в 01:50
  • 2
    @FranciscoMateo Правда, но за пределами 1 или 2 функции promisifyAll по-прежнему супер полезно. – Matt 4 December 2017 в 03:33

Вместо этого я бы использовал дуплексный поток. как документировано здесь nodejs doc дуплексные потоки

A Transform stream - это дуплексный поток, где вывод каким-то образом вычисляется с входа.

0
ответ дан pungggi 19 August 2018 в 03:57
поделиться

Вы можете обрабатывать файл во время чтения с использованием потоков. Это похоже на использование буферов, но с более удобным API.

var fs = require('fs');
function searchReplaceFile(regexpFind, replace, cssFileName) {
    var file = fs.createReadStream(cssFileName, 'utf8');
    var newCss = '';

    file.on('data', function (chunk) {
        newCss += chunk.toString().replace(regexpFind, replace);
    });

    file.on('end', function () {
        fs.writeFile(cssFileName, newCss, function(err) {
            if (err) {
                return console.log(err);
            } else {
                console.log('Updated!');
            }
    });
});

searchReplaceFile(/foo/g, 'bar', 'file.txt');
5
ответ дан sanbor 19 August 2018 в 03:57
поделиться
  • 1
    Но ... что, если кусок разбивает строку regexpFind? Разве это не намерение? – Jaakko Karhu 31 October 2017 в 17:05
  • 2
    Это очень хороший момент. Интересно, если, установив bufferSize дольше, чем строка, которую вы заменяете и сохраняете последний кусок и конкатенируя с текущим, вы могли бы избежать этой проблемы. – sanbor 10 January 2018 в 14:46
  • 3
    Вероятно, этот фрагмент также должен быть улучшен путем записи измененного файла непосредственно в файловую систему, а не создания большой переменной, поскольку файл может быть больше доступной памяти. – sanbor 10 January 2018 в 14:48

Вы также можете использовать функцию «sed», которая является частью ShellJS ...

 $ npm install [-g] shelljs


 require('shelljs/global');
 sed('-i', 'search_pattern', 'replace_pattern', file);

Посетите ShellJs.org для получения дополнительных примеров.

24
ответ дан Tony O'Hagan 19 August 2018 в 03:57
поделиться

Я столкнулся с проблемами при замене маленького заполнителя большой строкой кода.

Я делал:

var replaced = original.replace('PLACEHOLDER', largeStringVar);

Я понял, что проблема связана с специальными шаблонами замены JavaScript , описанный здесь здесь . Поскольку код, который я использовал в качестве заменяющей строки, содержал в нем несколько $, он испортил вывод.

Моим решением было использовать опцию замены функции, которая НЕ выполняет никакой специальной замены:

var replaced = original.replace('PLACEHOLDER', function() {
    return largeStringVar;
});
1
ответ дан Vivek Molkar 19 August 2018 в 03:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: