【发布时间】:2011-08-14 04:46:30
【问题描述】:
在 node.js 中,如何生成唯一的临时文件名,例如 mkstemp(3)?我想用fs.rename原子地写一个文件。
【问题讨论】:
-
这不是工具推荐。这是一个API是否存在的问题。我的意思是什么鬼,90% 的 SO 问题都是关于是否存在一些 API 来做某事。全部关闭或不关闭。
标签: node.js
在 node.js 中,如何生成唯一的临时文件名,例如 mkstemp(3)?我想用fs.rename原子地写一个文件。
【问题讨论】:
标签: node.js
另一个流行的包是tmp。
【讨论】:
也许您在此期间已经找到node-temp。
【讨论】:
不使用任何额外的插件:
var crypto = require('crypto');
var fs = require('fs');
var filename = 'foo'+crypto.randomBytes(4).readUInt32LE(0)+'bar';
fs.writeFileSync(filename, 'baz');
编辑:读取 cmets。
【讨论】:
foo1492796329bar 带有随机盐的 SHA1 会更好
crypto.randomBytes(16).toString('base64').replace(/\//,'_')。根据我的经验,mktemp 存在严重的跨平台问题以及可能的挂起/中断问题。
试试这个功能,安全无漏洞。节点 8.x LTS
function tempFile (name = 'temp_file', data = '', encoding = 'utf8') {
const fs = require('fs');
const os = require('os');
const path = require('path');
return new Promise((resolve, reject) => {
const tempPath = path.join(os.tmpdir(), 'foobar-');
fs.mkdtemp(tempPath, (err, folder) => {
if (err)
return reject(err)
const file_name = path.join(folder, name);
fs.writeFile(file_name, data, encoding, error_file => {
if (error_file)
return reject(error_file);
resolve(file_name)
})
})
})
}
解析临时文件的路径,拒绝 mkdtemp 或 writeFile 错误
// C:\Users\MYPC\AppData\Local\Temp\foobar-3HmKod\temp_file
// /temp/Temp/foobar-3HmKod/temp_file
tempFile().then(path => console.log(path)).catch(e => console.log("error", e)) //or
// C:\Users\MYPC\AppData\Local\Temp\foobar-9KHuxg\hola.txt
// /temp/Temp/foobar-9KHuxg/hola.txt
tempFile('hola.txt', 'hello there').then(path => console.log(path)).catch(e => console.log("e", e))
【讨论】:
在 node 和 python 中创建临时文件会受到涉及权限更改和跨平台问题的竞争条件的影响,尤其是在测试 ACL 具有挑战性的 Windows 上。
结果是它可以直接挂起您的机器,以许多现代语言请求临时文件。 (如果节点无权访问临时目录,取决于 ACL,它可以获得 EEXIST,即使文件不存在 - 结果可能是无限循环。
最简单的解决方案是使用足够的熵以使冲突的可能性可以忽略不计(在密码学意义上)。
这还具有使临时文件创建在所有平台上的安全性的副作用,而无需大量审查源代码。只要您的随机数是安全的,就无法预测将用于篡夺权限或访问的文件。
它有助于需要传递文件名而不是文件句柄的程序。
const crypto = require('crypto');
const os = require('os');
const path = require('path');
function tmpFile(prefix, suffix, tmpdir) {
prefix = (typeof prefix !== 'undefined') ? prefix : 'tmp.';
suffix = (typeof suffix !== 'undefined') ? suffix : '';
tmpdir = tmpdir ? tmpdir : os.tmpdir();
return path.join(tmpdir, prefix + crypto.randomBytes(16).toString('hex') + suffix);
}
唯一的缺点是这在 FAT 格式的分区上不起作用,这在 USB 记忆棒上仍然很常见。
【讨论】:
类似于kinematic's answer,但有 2 个字节的额外熵和字母而不是数字:
import Crypto from 'crypto';
import {tmpdir} from 'os';
import Path from 'path';
function tmpFile(ext) {
return Path.join(tmpdir(),`archive.${Crypto.randomBytes(6).readUIntLE(0,6).toString(36)}.${ext}`);
}
用法:
const file = tmpFile('tar.gz'); // "/tmp/archive.1scpz5ew5d.tar.gz"
我正在创建档案,所以我选择“档案”作为基本名称,但您可以根据需要更改它。
【讨论】:
readBigInt64LE)。看起来他们还没有添加任意长度的 bigint 方法,但是如果你想要 128 位,你可以分 2 块来做。
crypto.randomBytes(16).toString('hex')
Path.join(tmpdir(),`${prefix}${Crypto.randomBytes(16).toString('hex')}${suffix}`);}
使用 npm 包tempfile
import tempfile from 'tempfile';
或者
let tempfile = "";
import('tempfile').then(a => {
tempfile = a.default;
});
然后:
let filename = tempfile() //e,g: /tmp/5fc8a50f-e9cd-4420-b62a-e365b3ef2c2a
let imagefilename = tempfile(".jpeg") // e,g: /tmp/5a6dea08-a704-4fa8-9d0a-8ffa5e134543.jpeg
【讨论】: