Creando un archivo solo si no existe en Node.js
(5)
¿Qué hay de usar la opción a?
Según here''s :
''a +'' - Abrir archivo para leer y anexar. El archivo se crea si no existe.
Parece funcionar perfectamente con createWriteStream
Tenemos un búfer que nos gustaría escribir en un archivo. Si el archivo ya existe, necesitamos incrementar un índice en él e intentarlo de nuevo. ¿Hay una manera de crear un archivo solo si no existe, o solo debería hacer una estadística de los archivos hasta que aparezca un error para encontrar uno que aún no existe?
Por ejemplo, tengo los archivos a_1.jpg
y a_2.jpg
. Me gustaría mi método para intentar crear a_1.jpg
y a_2.jpg
, y fallar, y finalmente crear con éxito a_3.jpg
.
El método ideal sería algo como esto:
fs.writeFile(path, data, { overwrite: false }, function (err) {
if (err) throw err;
console.log(''It/'s saved!'');
});
o así:
fs.createWriteStream(path, { overwrite: false });
¿Existe algo como esto en la biblioteca fs
de node?
EDITAR : Mi pregunta no es si hay una función separada que verifica la existencia. Es esta: ¿hay una manera de crear un archivo si no existe, en una sola llamada al sistema de archivos?
Aquí hay algunas opciones:
1) Tener 2 llamadas "fs" . La primera es la llamada " fs.exists ", y la segunda es " fs.write / read, etc"
//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) O crea un archivo vacío primero:
--- Sincronización:
//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) O use " toque ": https://github.com/isaacs/node-touch
Como su intuición adivinó correctamente, la solución ingenua con un par de llamadas exists / writeFile
es incorrecta. El código asíncrono se ejecuta de forma impredecible. Y en un caso dado es
- ¿Hay un archivo
a.txt
? - No. - (El archivo
a.txt
es creado por otro programa) - Escribe a
a.txt
si es posible. - Bueno.
Pero sí, podemos hacerlo en una sola llamada. Estamos trabajando con el sistema de archivos, así que es una buena idea leer el manual del desarrollador en fs
. Y oye, here''s una parte interesante.
''w'' - Abrir archivo para escribir. El archivo se crea (si no existe) o se trunca (si existe).
''wx'' - Me gusta ''w'' pero falla si existe una ruta.
Así que todo lo que tenemos que hacer es simplemente agregar wx
a la llamada fs.open
. Pero oye, no nos gusta fopen
como IO. Vamos a leer en fs.writeFile
un poco más.
fs.readFile (nombre de archivo [, opciones], devolución de llamada) #
cadena de nombre de archivo
opciones de objeto
cadena de codificación | Nulo por defecto = nulo
bandera Cadena por defecto = ''r''
Función de devolución de llamada
Ese options.flag
parece prometedor. Así que intentamos
fs.writeFile(path, data, { flag: ''wx'' }, function (err) {
if (err) throw err;
console.log("It''s saved!");
});
Y funciona perfectamente para una sola escritura. Supongo que este código fallará de alguna manera más extraña si intentas resolver tu tarea con él. Tiene una operación "compruebe la existencia de a_#.jpg
y escriba allí si está vacía", pero el resto del estado no está bloqueado, y el archivo a_1.jpg
puede desaparecer espontáneamente mientras ya verifica a_5.jpg
. La mayoría de los sistemas de archivos * no son bases de datos ACID , y el hecho de que pueda hacer al menos algunas operaciones atómicas es milagroso. Es muy probable que el código wx
no funcione en alguna plataforma. Entonces, por el bien de tu cordura, usa la base de datos, finalmente .
Un poco más de información para el sufrimiento.
Imagine que estamos escribiendo algo como memoize-fs
que almacena en caché los resultados de las llamadas de funciones al sistema de archivos para ahorrarnos algo de tiempo de red / CPU. ¿Podríamos abrir el archivo para leerlo si existe, y para escribirlo si no existe, todo en la única llamada? Echemos un vistazo divertido en esas banderas. Después de un rato de ejercicios mentales, podemos ver que a+
hace lo que queremos: si el archivo no existe, crea uno y lo abre para leer y escribir, y si el archivo existe, lo hace sin borrar el archivo (como w+
haría). Pero ahora no podemos usarlo ni en el (smth)File
, ni en las funciones de create(Smth)Stream
. Y eso parece una característica que falta.
Así que siéntase libre de archivarlo como una solicitud de característica (o incluso un error) a Node.js github, ya que la falta de API de sistema de archivos asíncrono atómico es un inconveniente de Node. Aunque no esperes cambios en el corto plazo.
Puedes hacer algo como esto:
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);
}
});
}
Todo esto en una sola llamada al sistema puede usar el módulo fs-extra
npm. Después de esto, el archivo se habrá creado, así como el directorio en el que se colocará.
const fs = require(''fs-extra'');
const file = ''/tmp/this/path/does/not/exist/file.txt''
fs.ensureFile(file, err => {
console.log(err) // => null
});
Otra forma es utilizar ensureFileSync que hará lo mismo pero sincrónico.
const fs = require(''fs-extra'');
const file = ''/tmp/this/path/does/not/exist/file.txt''
fs.ensureFileSync(file)