NodeJs中关于文件的操作

使用path

一、关于node运行时的路径问题

![在这里插入图片描述](https://img-blog.csdnimg.cn/0cd6882ec15343ca9d0fb6fb34a24f90.png
如上图,在Code文件夹下的终端用node命令运行demo3.js文件是成功的。但是当我们换一种写法:
在这里插入图片描述
已经报错了。原因就是我们此时的终端是运行在桌面的,虽然我们的本意是用node运行桌面下的Code文件夹中的demo3.js文件,但是始终应该注意的是终端的打开位置,当我们用相对路径指定了file1.txt后,node会将终端打开的路径,即桌面的路径,与指定的相对路径动态拼接起来,此时报错是必然的。
解决方法是使用绝对路径,但绝对路径的拼接极易出错,在这不再赘述。此时path模块成了另一个解决方案。

二、 path

  1. 路径的拼接
	const path = require('path')
	console.log(__direname) // C:\Users\86153\Desktop\code 即当前文件所处的目录
	console.log(path.join(__dirname, './file1.txt')) // C:\Users\86153\Desktop\code\file1.txt
	console.log(path.join(__dirname, '/file1.txt')) // C:\Users\86153\Desktop\code\file1.txt
	console.log(path.join(__dirname,'/file1.txt','../')) // C:\Users\86153\Desktop\code\

如上面代码所示,path的join方法可以把多个路径字符串拼接起来,而使用 . . / 可以回退到上一级目录下

  1. 文件名和文件扩展名
	const filePath = 'file1.txt'
	console.log(path.extname(filePath)) // .txt
	console.log(path.basename(filePath, '.txt')) // file1
	// filePath如果是C:\\Users\\86153\\Desktop\\code\\file1.txt得到的结果也相同

文件

写在最前:对文件(夹)的操作方法,尽量选择异步的写法。因为Js是一门单线程的语言,在服务端如果使用同步的写法,若待操作的文件过大,很可能会阻塞服务器。

一、获取文件(夹)的详情信息以及文件(夹)重命名

  1. stat,此方法可以对文件或者文件夹进行操作。
fs.stat('./file1.txt', (err, data) => {
  console.log(data) // 文件(夹)信息,包含创建时间等信息
  console.log(data.isFile()) // 是文件返回true,文件夹返回false
  console.log(data.isDirectory()) // 是文件返回false,是文件夹返回true
})
  1. rename,此方法可以对文件或者文件夹进行重命名。
// 对文件:
fs.rename('./test1.txt', './test2.txt', (err) => {
  console.log(err)
})
// 对文件夹不需要加上后缀名,代码省略

二、读

// 异步的写法
fs.readFile('./file1.txt', 'utf-8', function (err, dataStr) {
  if (err) {
    console.log(err)
  }
  console.log(dataStr) // 输出file1.txt中的内容
})
// 同步的写法
fs.readFileSync('./file1.txt', 'utf-8')

三、写

// 异步的写法
fs.writeFile('./file1.txt', '待写入的内容', (err) => {
  if (err) {
    console.log(err)
  }
})
// 同步的写法
fs.writeFileSync('./file1.txt', '待写入的内容')

注意,以上两个方法是在覆盖待操作文件原有内容的基础上进行写入的。想要在待操作文件原有内容的基础上追加写入新内容应该使用appendFile。

// 异步
fs.appendFile('./file1.txt', '追加写入的内容', err => console.log(err))
// 同步
fs.appendFileSync('./file1.txt', '追加写入的内容')

四、创建

在使用writeFile或者writeFileSync方法时如果待操作的文件不存在,会自动创建,因此可以使用此特征来创建文件。

fs.writeFile('./file2.txt', '', (err) => {
  if (err) {
    console.log(err.message)
  }
  console.log('file2.txt成功创建')
})

五、删除

// 异步
fs.unlink(path.join(__dirname, './file3.docx'), err => console.log(err))
// 同步
fs.unlinkSync('./file2.txt')

在读写大文件时,使用的更多的是stream,原因同样是因为Js是单线程语言,防止代码阻塞。stream是nodejs提供的一个仅在服务端可用的模块,目的是支持“流”这种数据结构。

一、读

const rs = fs.createReadStream('./file1.txt', 'utf-8')  // 创建一个文件流
// 事件绑定
rs.on('data', chunk => {
  // data事件有可能被触发多次, 因为chunk代表了整个文件流中的一小部分
  console.log(chunk)
})
rs.on('end', () => {
  console.log('ok')
})
rs.on('error', (err) => {
  console.log('err:' + err)
})

二、写

const ws = fs.createWriteStream('./file2.txt', 'utf-8')
ws.write('bsd\n')
ws.write('bsd\n')
ws.write('bsd\n')
ws.write('bsd\n')
ws.write('bsd\n')

注意,当对一个创建了一个新的写文件流的时候,写文件流所操作的文件的内容会被覆盖,但是写文件流的write方法是对待操作文件进行追加写入。

三、管道

pipe常用于大文件之间的复制,也常见于在前后端交互中使用。

const ws = fs.createWriteStream('./file2.txt')
const rs = fs.createReadStream('./file1.txt')
rs.pipe(ws) // 把file1的内容写到file2里面

文件夹

一、读

fs.readdir('./files', (err, data) => {
  console.log(data)
  // data是一个数组,里面包含了files文件夹下的文件的文件名
})

二、创建

fs.mkdir('./files',(err) => {
  if(err){
    console.log(err)
  }
})
// 会在当前js文件所在的目录下创建files文件夹

三、删除

fs.rmdir('./files', err => console.log(err))

但是如果待删除的文件夹不为空则会报错,应该先删除里面的文件:

fs.readdir('./files', (err, data) => {
  data.forEach(item => {
  	fs.unlink('./files/' + item, err => { console.log(err) })
  })
})
fs.rmdir('./files', err => console.log(err))

前后端交互


此处前端使用Vue3,后端使用Egg.js,实现了用户头像更新的功能,经供参考
前端代码:

// 注意请求头的Content-Type的值应为multipart/form-data
function changePic() {
  const fileInput = document.getElementById("file-input");
  fileInput.click(); // 触发点击事件
}
function submitPic(e) {
  if (e.target.files.length === 0) {
    return;
  }
  const formData = new FormData();
  formData.append("file", e.target.files[0]); //传递给后端的参数
  // 与后端对接的接口,此处使用了Axios
  userPicUpdate(formData, $store.userID).then(() => {
    const userImg = document.getElementById("user-img");
    const reader = new FileReader();
    reader.onload = function () {
      userImg.src = reader.result; // 现在前端渲染用户更新的头像,减少网络请求的次数
    };
    reader.readAsDataURL(e.target.files[0]);
    ElMessage({
      showClose: true,
      message: "头像更新成功。",
      type: "success",
    });
    mySwitch.value = false;
  });
}

后端代码:
很丑陋的代码,毫无逻辑性可言。

  async changeUserPic() {
    const { ctx } = this;
    const oldPicStatic = await ctx.service.user.getUserPic(ctx.body.userID);
    const newPic = './app/public/user-images/' + ctx.body.userID + '.jpg';
    const file = ctx.request.files[0];
    if (oldPicStatic !== 'http://127.0.0.1:7002/public/user-images/default.jpg') {
      fs.unlink(newPic, err => {
        if (err) throw err;
        console.log('File has been deleted!');
      });
    } else {
      const staticPicPath = 'http://127.0.0.1:7002/public/user-images/' + ctx.body.userID + '.jpg';
      await ctx.service.user.changePic(ctx.body.userID, staticPicPath);
    }
    fs.writeFile(newPic, '', err => {
      if (err) throw err;
    });
    // 关键点!
    const readStream = fs.createReadStream(file.filepath);
    const writeStream = fs.createWriteStream(newPic);
    readStream.pipe(writeStream);
    ctx.body = {
      status: 200,
      msg: 'ok',
    };
  }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值