9.stream流
-- 未经授权禁止转载 --

为什么使用Stream?

     流(Stream)是一种处理数据的方式

     对于比较大的文件,流可以逐步处理数据,而不是一次性将整个文件加载到内存中,

     这样可以节省内存资源,避免内存溢出问题

import fs from 'fs'

//创建目录
const createDir = async (path) => {
  try {
    await fs.promises.mkdir(path, { recursive: true }) // recursive: true 允许递归创建多级目录
    console.log("目录创建成功")
  } catch (err) {
    //ENOENT(Error NO ENTry) - no such file or directory (文件或目录不存在)
    console.error(`目录创建失败: ${err}`)
  }
}

let dir = "DR/log/"
createDir(dir) //创建多级目录


//写入文件
/*
const writeFile = async (path, content) => {
  try {
    await fs.promises.writeFile(path, content)
    console.log("文件写入成功")
  } catch (err) {
    console.error(`文件写入失败: ${err}`)
  }
}
*/
const writeFile = (path, content) => {
  const writeStream = fs.createWriteStream(path)
  
  writeStream.on('error', err => {  
    console.error(`文件写入失败: ${err}`)
    writeStream.close() // 出错时关闭流
  })
  
  writeStream.on('finish', () => {  
    console.log("文件写入成功")
  })
  
  writeStream.write(content, 'utf8')
  writeStream.end()
}

let name = "web.txt"
let path = dir + name // DR/log/web.txt
let content = "dengruicode.com"
//writeFile(path, content)


//追加文件
/*
const appendFile = async (path, content) => {
  try {
    await fs.promises.appendFile(path, content)
    console.log("追加写入成功")
  } catch (err) {
    console.error(`追加写入失败: ${err}`)
  }
}
*/
const appendFile = (path, content) => {
  const appendStream = fs.createWriteStream(path, { flags: 'a' })
  
  appendStream.on('error', err => {  
    console.error(`追加写入失败 ${err}`)
    writeStream.close() // 出错时关闭流
  })
  
  appendStream.on('finish', () => {  
    console.log("追加写入成功")
  })
  
  appendStream.write(content, 'utf8')
  appendStream.end()
}

let appendContent  = "\n邓瑞编程"
//appendFile(path, appendContent)


//读取文件
/*
const readFile = async (path) => {
  try {
    const data = await fs.promises.readFile(path)
    console.log(String(data))
  } catch (err) {
    console.error(`文件读取失败: ${err}`)
  }
}
*/
const readFile = (path) => {
  const readStream = fs.createReadStream(path)
  
  let content = ''
  readStream.on('data', chunk => {
    console.log(chunk) //chunk是指在流中传输的数据块
    content += chunk.toString('utf8') //将Buffer转换为UTF-8编码的字符串
  })
  
  readStream.on('end', () => {  
    console.log(content)
  })
  
  readStream.on('error', err => {
    console.error(`文件读取失败: ${err}`)
  })
}

//readFile(path)


//检测文件或目录是否存在
/*
  fs.promises.constants.F_OK 检查文件是否存在
  fs.promises.constants.R_OK 检查文件是否可读
  fs.promises.constants.W_OK 检查文件是否可写
  fs.promises.constants.X_OK 检查文件是否可执行

  ENOENT(Error NO ENTry) - no such file or directory (文件或目录不存在)
  EEXIST - file already exists (文件已存在)
  EACCES - permission denied (没有足够的权限)
*/
const fileOrDirExist = async (path) => {
  try {
    await fs.promises.access(path, fs.promises.constants.F_OK)
    console.error("文件或目录存在")
  } catch (err) {
    console.error(`文件或目录不存在: ${err}`)
  }
}

//fileOrDirExist("DR/log")
//fileOrDirExist("DR/log/web.txt")


//获取文件或目录详细信息
const fileOrDirStats = async (path) => {
  try {
    let stats = await fs.promises.stat(path)
    //console.log(stats)

    // 检查是否是一个文件  
    if (stats.isFile()) {  
      console.log(`${path} 是文件`)
      return 
    }

    // 检查是否是一个目录  
    if (stats.isDirectory()) {  
      console.log(`${path} 是目录`)
      return
    }
  } catch (err) {
    console.error(`获取文件或目录详细信息时出错: ${err}`)
  }
}

//fileOrDirStats("DR/log")
//fileOrDirStats("DR/log/web.txt")


//文件或目录重命名
const fileOrDirRename = async (oldPath, newPath) => {
  try {
    await fs.promises.rename(oldPath, newPath)
    console.log("文件或目录重命名成功")
  } catch (err) {
    console.error(`文件或目录重命名失败: ${err}`)
  }
}

//fileOrDirRename("DR/log", "DR/newLog")
//fileOrDirRename("DR/newLog/web.txt", "DR/newLog/newWeb.txt")


//删除文件
const deleteFile = async (path) => {
  try {
    await fs.promises.unlink(path)
    console.log("文件删除成功")
  } catch (err) {
    console.error(`文件删除失败: ${err}`)
  }
}

//deleteFile("DR/newLog/newWeb.txt")


//删除目录
const deleteDir = async (path) => {
  try {
    await fs.promises.rm(path, { recursive: true }) // recursive: true 允许递归删除多级目录
    console.log("目录删除成功")
  } catch (err) {
    console.error(`目录删除失败: ${err}`)
  }
}

//deleteDir("DR")