nodejs高级编程-核心模块

news2025/1/12 7:57:07

一、path

1 获取路径中的基础名称

const path = require('path')

// console.log(__filename) // /Users/liuchongyang/Desktop/分享/网页读取本地文件/node.js

// 1 获取路径中的基础名称 
/**
 * 01 返回的就是接收路径当中的最后一部分 
 * 02 第二个参数表示扩展名,如果说没有设置则返回完整的文件名称带后缀
 * 03 第二个参数做为后缀时,如果没有在当前路径中被匹配到,那么就会忽略
 * 04 处理目录路径的时候如果说,结尾处有路径分割符,则也会被忽略掉
 */
 console.log(path.basename(__filename)) // node.js
console.log(path.basename(__filename, '.js')) // node
console.log(path.basename(__filename, '.css')) // node.js
console.log(path.basename('/a/b/c')) //c 
console.log(path.basename('/a/b/c/'))  // c

2 获取路径目录名 (路径)

// 2 获取路径目录名 (路径)
/**
 * 01 返回路径中最后一个部分的上一层目录所在路径
 */
console.log(path.dirname(__filename)) // /Users/liuchongyang/Desktop/分享/网页读取本地文件
console.log(path.dirname('/a/b/c')) // /a/b

3 获取路径的扩展名

/**
 * 01 返回 path路径中相应文件的后缀名
 * 02 如果 path 路径当中存在多个点,它匹配的是最后一个点,到结尾的内容
 */
console.log(path.extname(__filename)) // .js
console.log(path.extname('/a/b')) // ''
console.log(path.extname('/a/b/index.html.js.css')) // .css
console.log(path.extname('/a/b/index.html.js.')) // .

4 解析路径

/**
 * 01 接收一个路径,返回一个对象,包含不同的信息
 * 02 root dir base ext name
 */
const obj = path.parse('/a/b/c/index.html')
const obj = path.parse('/a/b/c/')
const obj = path.parse('./a/b/c/')
console.log(obj.name)

在这里插入图片描述

5 序列化路径

// 5 序列化路径
/* const obj = path.parse('./a/b/c/')
console.log(path.format(obj)) */

在这里插入图片描述

6 判断当前路径是否为绝对

/* console.log(path.isAbsolute('foo'))
console.log(path.isAbsolute('/foo'))
console.log(path.isAbsolute('///foo'))
console.log(path.isAbsolute(''))
console.log(path.isAbsolute('.'))
console.log(path.isAbsolute('../bar')) */

在这里插入图片描述

7 拼接路径

console.log(path.join('a/b', 'c', 'index.html')) // a/b/c/index.html
console.log(path.join('/a/b', 'c', 'index.html')) // /a/b/c/index.html
console.log(path.join('/a/b', 'c', '../', 'index.html')) // /a/b/index.html
console.log(path.join('/a/b', 'c', './', 'index.html')) // /a/b/c/index.html
console.log(path.join('/a/b', 'c', '', 'index.html')) // /a/b/c/index.html
console.log(path.join('')) // .

8 规范化路径

// 8 规范化路径
console.log(path.normalize(''))
console.log(path.normalize('a/b/c/d'))
console.log(path.normalize('a///b/c../d'))
console.log(path.normalize('a//\\/b/c\\/d'))
console.log(path.normalize('a//\b/c\\/d'))

在这里插入图片描述

9 绝对路径

// console.log(path.resolve())
/**
 * resolve([from], to)
 */
// console.log(path.resolve('/a', '../b'))
console.log(path.resolve('index.html')) // /Users/liuchongyang/Desktop/分享/网页读取本地文件/index.html

二、全局变量之Buffer

在这里插入图片描述
在这里插入图片描述

const b1 = Buffer.alloc(10) // 创建一个长度10的空buffer
const b2 = Buffer.allocUnsafe(10) // 方法创建一个指定大小的新缓冲区对象

console.log(b1) // <Buffer 00 00 00 00 00 00 00 00 00 00>
console.log(b2) // <Buffer c0 ff 83 0d 01 00 00 00 f0 a9>

// from 
const b1 = Buffer.from('中') // 创建一个buffer
console.log(b1) // <Buffer e4 b8 ad>

const b1 = Buffer.from([0xe4, 0xb8, 0xad])
console.log(b1) // <Buffer e4 b8 ad>
console.log(b1.toString())  // '中'


 const b1 = Buffer.from('中')
console.log(b1) // <Buffer e4 b8 ad>
console.log(b1.toString())  // '中'

const b1 = Buffer.alloc(3)
const b2 = Buffer.from(b1)

console.log(b1) // <Buffer 00 00 00>
console.log(b2) //<Buffer 00 00 00>

b1[0] = 1
console.log(b1) // <Buffer 01 00 00>
console.log(b2) // <Buffer 00 00 00>
let buf = Buffer.alloc(6)

// fill
 buf.fill(123)
console.log(buf) // <Buffer 7b 7b 7b 7b 7b 7b>
console.log(buf.toString()) // {{{{{{

// write 
 buf.write('123', 1, 4)
console.log(buf) // <Buffer 00 31 32 33 00 00>
console.log(buf.toString()) // '123'

// toString
buf = Buffer.from('你好')
console.log(buf) // <Buffer e4 bd a0 e5 a5 bd>
console.log(buf.toString('utf-8', 3, 9)) // 好

// slice 
 buf = Buffer.from('教育')
let b1 = buf.slice(-3)
console.log(b1) // <Buffer e8 82 b2>
console.log(b1.toString()) // 育

// indexOf
buf = Buffer.from('zce爱前端,爱、教育,爱大家,我爱所有')
console.log(buf)
console.log(buf.indexOf('爱qc', 4)) // -1

// copy 
let b1 = Buffer.alloc(6)
let b2 = Buffer.from('11')

b2.copy(b1, 3, 3, 6)
console.log(b1.toString())
console.log(b2.toString())

/* let b1 = Buffer.from('11')
let b2 = Buffer.from('教育')

let b = Buffer.concat([b1, b2], 9)
console.log(b)
console.log(b.toString()) */

// isBuffer
let b1 = '123'
console.log(Buffer.isBuffer(b1))

buffer split方法封装


ArrayBuffer.prototype.split = function (sep) {
  let len = Buffer.from(sep).length
  let ret = []
  let start = 0
  let offset = 0

  while( offset = this.indexOf(sep, start) !== -1) {
    ret.push(this.slice(start, offset))
    start = offset + len
  }
  ret.push(this.slice(start))
  return ret
}

let buf = 'zce吃馒头,吃面条,我吃所有吃'
let bufArr = buf.split('吃')
console.log(bufArr) // [ 'zce', '馒头,', '面条,我', '所有', '' ]

三、文件操作api

const fs = require('fs')
const path = require('path')

// readFile 
/* fs.readFile(path.resolve('data1.txt'), 'utf-8', (err, data) => {
  console.log(err) 
  if (!null) {
    console.log(data)
  }
}) */

// writeFile 
/* fs.writeFile('data.txt', '123', {
  mode: 438,
  flag: 'w+',
  encoding: 'utf-8'
}, (err) => {
  if (!err) {
    fs.readFile('data.txt', 'utf-8', (err, data) => {
      console.log(data)
    })
  }
}) */

// appendFile
/* fs.appendFile('data.txt', 'hello node.js',{},  (err) => {
  console.log('写入成功')
}) */

// copyFile
/* fs.copyFile('data.txt', 'test.txt', () => {
  console.log('拷贝成功')
}) */

// watchFile
fs.watchFile('data.txt', {interval: 20}, (curr, prev) => {
  if (curr.mtime !== prev.mtime) {
    console.log('文件被修改了')
    fs.unwatchFile('data.txt')
  }
})

四、md转html实现

md-to-html.js

const fs = require('fs')
const path = require('path')
const marked = require('marked')
const browserSync = require('browser-sync')

/**
 * 01 读取 md 和 css 内容
 * 02 将上述读取出来的内容替换占位符,生成一个最终需要展的 Html 字符串 
 * 03 将上述的 Html 字符写入到指定的 Html 文件中
 * 04 监听 md 文档内容的变经,然后更新 html 内容 
 * 05 使用 browser-sync 来实时显示 Html 内容
 */

let mdPath = path.join(__dirname, process.argv[2])
let cssPath = path.resolve('github.css')
let htmlPath = mdPath.replace(path.extname(mdPath), '.html')

fs.watchFile(mdPath, (curr, prev) => {
  if (curr.mtime !== prev.mtime) {
    fs.readFile(mdPath, 'utf-8', (err, data) => {
      // 将 md--》html
      let htmlStr = marked(data)
      fs.readFile(cssPath, 'utf-8', (err, data) => {
        let retHtml = temp.replace('{{content}}', htmlStr).replace('{{style}}', data)
        // 将上述的内容写入到指定的 html 文件中,用于在浏览器里进行展示
        fs.writeFile(htmlPath, retHtml, (err) => {
          console.log('html 生成成功了')
        })
      })
    })
  }
})

browserSync.init({
  browser: '',
  server: __dirname,
  watch: true,
  index: path.basename(htmlPath)
})

const temp = `
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            .markdown-body {
                box-sizing: border-box;
                min-width: 200px;
                max-width: 1000px;
                margin: 0 auto;
                padding: 45px;
            }
            @media (max-width: 750px) {
                .markdown-body {
                    padding: 15px;
                }
            }
            {{style}}
        </style>
    </head>
    <body>
        <div class="markdown-body">
            {{content}}
        </div>
    </body>
    </html>
`

五、文件打开与关闭

const fs = require('fs')
const path = require('path')

// open 
/* fs.open(path.resolve('data.txt'), 'r', (err, fd) => {
  console.log(fd)
}) */

// close
fs.open('data.txt', 'r', (err, fd) => {
  console.log(fd)
  fs.close(fd, err => {
    console.log('关闭成功')
  })
})

六、大文件读写操作

在这里插入图片描述

const fs = require('fs')

// read : 所谓的读操作就是将数据从磁盘文件中写入到 buffer 中
let buf = Buffer.alloc(10)

/**
 * fd 定位当前被打开的文件 
 * buf 用于表示当前缓冲区
 * offset 表示当前从 buf 的哪个位置开始执行写入
 * length 表示当前次写入的长度
 * position 表示当前从文件的哪个位置开始读取
 */
/* fs.open('data.txt', 'r', (err, rfd) => {
  console.log(rfd)
  fs.read(rfd, buf, 1, 4, 3, (err, readBytes, data) => {
    console.log(readBytes)
    console.log(data)
    console.log(data.toString())
  })
}) */

// write 将缓冲区里的内容写入到磁盘文件中
buf = Buffer.from('1234567890')
fs.open('b.txt', 'w', (err, wfd) => {
  fs.write(wfd, buf, 2, 4, 0, (err, written, buffer) => {
    console.log(written, '----')
    fs.close(wfd)
  })
})

七、大文件拷贝自定义实现

const fs = require('fs')

/**
 * 01 打开 a 文件,利用 read 将数据保存到 buffer 暂存起来
 * 02 打开 b 文件,利用 write 将 buffer 中数据写入到 b 文件中
 */
let buf = Buffer.alloc(10)

// 01 打开指定的文件
/* fs.open('a.txt', 'r', (err, rfd) => {
  // 03 打开 b 文件,用于执行数据写入操作
  fs.open('b.txt', 'w', (err, wfd) => {
    // 02 从打开的文件中读取数据
    fs.read(rfd, buf, 0, 10, 0, (err, readBytes) => {
      // 04 将 buffer 中的数据写入到 b.txt 当中
      fs.write(wfd, buf, 0, 10, 0, (err, written) => {
        console.log('写入成功')
      })
    })
  })
}) */

// 02 数据的完全拷贝
/* fs.open('a.txt', 'r', (err, rfd) => {
  fs.open('b.txt', 'a+', (err, wfd) => {
    fs.read(rfd, buf, 0, 10, 0, (err, readBytes) => {
      fs.write(wfd, buf, 0, 10, 0, (err, written) => {
        fs.read(rfd, buf, 0, 5, 10, (err, readBytes) => {
          fs.write(wfd, buf, 0, 5, 10, (err, written) => {
            console.log('写入成功')
          })
        })
      })
    })
  })
}) */

const BUFFER_SIZE = buf.length
let readOffset = 0

fs.open('a.txt', 'r', (err, rfd) => {
  fs.open('b.txt', 'w', (err, wfd) => {
    function next () {
      fs.read(rfd, buf, 0, BUFFER_SIZE, readOffset, (err, readBytes) => {
        if (!readBytes) {
          // 如果条件成立,说明内容已经读取完毕
          fs.close(rfd, ()=> {})
          fs.close(wfd, ()=> {})
          console.log('拷贝完成')
          return
        }
        readOffset += readBytes
        fs.write(wfd, buf, 0, readBytes, (err, written) => {
          next()
        })
      })
    }
    next()
  })
})

八、目录操作api

const fs = require('fs')

// 一、access 
/* fs.access('a.txt', (err) => {
  if (err) {
    console.log(err)
  } else {
    console.log('有操作权限')
  }
}) */

// 二、stat 
/* fs.stat('a.txt', (err, statObj) => {
  console.log(statObj.size)
  console.log(statObj.isFile()) // 是不是文件
  console.log(statObj.isDirectory()) // 是不是目录
}) */

// 三、mkdir 
/* fs.mkdir('a/b/c', {recursive: true}, (err) => {
  if (!err) {
    console.log('创建成功')
  }else{
    console.log(err)
  }
}) */

// 四、rmdir
fs.rmdir('a', {recursive: true}, (err) => { // 删除目录
  if (!err) {
    console.log('删除成功')
  } else {
    console.log(err)
  }
})

// 五、readdir 
/* fs.readdir('a/b', (err, files) => {
  console.log(files)
}) */

// 六、unlink
/* fs.unlink('a/a.txt', (err) => { // 删除文件
  if (!err) {
    console.log('删除成功')
  }
}) */

九、commonJs规范

  • 任意一个文件就是一个模块,具有独立作用域
  • 使用require导入其他模块
  • 将模块id传入require实现目标模块定位

module属性

  • 任意js文件就是一个模块,可以直接使用module属性
  • id:返回模块标识符,一般是一个绝对路径
  • filename:返回文件模块的绝对路径
  • loaded:返回布尔值,表示模块是否完全完成加载
  • parent:返回对象存放调用当前模块的模块
  • children:返回数组,存放当前模块调用的其他模块
  • exports:返回当前模块需要暴露的内容
  • paths:返回数组,存放不同目录下的node_modules位置

module.exports与exports区别

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

十、VM模块使用

内置模块

创建独立运行的沙箱环境

const fs = require('fs')
const vm = require('vm')

let age = 33
let content = fs.readFileSync('test.txt', 'utf-8')

// eval
// eval(content) // 可以运行代码

// new Function
/* console.log(age)
let fn = new Function('age', "return age + 1") // 可以运行,但逻辑复杂
console.log(fn(age)) */

vm.runInThisContext(content) // 互相隔离

console.log(age)

十一、事件模块

const EventEmitter = require('events')

const ev = new EventEmitter()

// on 
/* ev.on('事件1', () => {
  console.log('事件1执行了---2')
})

ev.on('事件1', () => {
  console.log('事件1执行了')
})

// emit
ev.emit('事件1')
ev.emit('事件1') */

// once 
/* ev.once('事件1', () => {
  console.log('事件1执行了')
})
ev.once('事件1', () => {
  console.log('事件1执行了--2')
})

ev.emit('事件1')
ev.emit('事件1') */

// off
/* let cbFn = (...args) => {
  console.log(args)
}
ev.on('事件1', cbFn) */

/* ev.emit('事件1')
ev.off('事件1', cbFn) */
// ev.emit('事件1', 1, 2, 3)

/* ev.on('事件1', function () {
  console.log(this)
})
ev.on('事件1', function () {
  console.log(2222)
})

ev.on('事件2', function () {
  console.log(333)
})

ev.emit('事件1') */

const fs = require('fs')

const crt = fs.createReadStream()
crt.on('data')

十二、发布订阅

class PubSub{
  constructor() {
    this._events = {}
  }

  // 注册
  subscribe(event, callback) {
    if (this._events[event]) {
      // 如果当前 event 存在,所以我们只需要往后添加当前次监听操作
      this._events[event].push(callback)
    } else {
      // 之前没有订阅过此事件
      this._events[event] = [callback]
    }
  }

  // 发布
  publish(event, ...args) {
    const items = this._events[event]
    if (items && items.length) {
      items.forEach(function (callback) {
        callback.call(this, ...args)
      })
    }
  }
}

let ps = new PubSub()
ps.subscribe('事件1', () => {
  console.log('事件1执行了')
})
ps.subscribe('事件1', () => {
  console.log('事件1执行了---2')
})

ps.publish('事件1')
ps.publish('事件1')

十三、nodejs事件循环机制

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
**注意:**nextTick优先级高于promise

在这里插入图片描述
微任务优先级

  • 浏览器事件循环中,微任务存放在事件队列,先进先出
  • Nodejs中process.nextTick先于promise.then

十四、nodejs事件环常见问题

多次快速执行之后,有时会出现下面问题

// 复现
setTimeout(() => {
  console.log('timeout')
}, 0)

setImmediate(() => {
  console.log('immdieate')
})

在这里插入图片描述


const fs = require('fs')

fs.readFile('./eventEmitter.js', () => {
  setTimeout(() => {
    console.log('timeout')
  }, 0)
  
  setImmediate(() => {
    console.log('immdieate')
  })
})

在这里插入图片描述
这样会正常

十五、核心模块之stream

如果我们读取一个G的电影
这里会有下面问题

在这里插入图片描述
使用流操作会有下面优势
在这里插入图片描述

nodejs中流的分类

在这里插入图片描述
在这里插入图片描述

十六、自定义可读流

const {Readable} = require('stream')

// 模拟底层数据
let source = ['lg', 'zce', 'syy']

// 自定义类继承 Readable
class MyReadable extends Readable{
  constructor(source) {
    super()
    this.source = source
  }
  _read() {
    let data = this.source.shift() || null 
    this.push(data)
  }
}

// 实例化
let myReadable = new MyReadable(source)

/* myReadable.on('readable', () => {
  let data = null 
  while((data = myReadable.read(2)) != null) {
    console.log(data.toString())
  }
}) */

myReadable.on('data', (chunk) => {
  console.log(chunk.toString())
})

十七、自定义可写流

const {Writable} = require('stream')

class MyWriteable extends Writable{
  constructor() {
    super()
  }
  _write(chunk, en, done) {
    process.stdout.write(chunk.toString() + '<----')
    process.nextTick(done)
  }
}

let myWriteable = new MyWriteable()

myWriteable.write('11教育', 'utf-8', () => {
  console.log('end')
})

十八、stream之双工和转换流

Duplex是双工流,即能生产优能消费

stream-duplex.js

let {Duplex} = require('stream')

class MyDuplex extends Duplex{
  constructor(source) {
    super()
    this.source = source
  }
  _read() {
    let data = this.source.shift() || null 
    this.push(data)
  }
  _write(chunk, en, next) {
    process.stdout.write(chunk)
    process.nextTick(next)
  }
}

let source = ['a', 'b', 'c']
let myDuplex = new MyDuplex(source)

/* myDuplex.on('data', (chunk) => {
  console.log(chunk.toString())
}) */
myDuplex.write('11教育', () => {
  console.log(1111)
})

stream-transform.js

let {Duplex} = require('stream')

class MyDuplex extends Duplex{
  constructor(source) {
    super()
    this.source = source
  }
  _read() {
    let data = this.source.shift() || null 
    this.push(data)
  }
  _write(chunk, en, next) {
    process.stdout.write(chunk)
    process.nextTick(next)
  }
}

let source = ['a', 'b', 'c']
let myDuplex = new MyDuplex(source)

/* myDuplex.on('data', (chunk) => {
  console.log(chunk.toString())
}) */
myDuplex.write('11', () => {
  console.log(1111)
})

十九、文件可读流事件与应用

const fs = require('fs')

let rs = fs.createReadStream('test.txt', {
  flags: 'r',
  encoding: null, 
  fd: null,
  mode: 438,
  autoClose: true, 
  start: 0,
  // end: 3,
  highWaterMark: 4
})

/* rs.on('data', (chunk) => {
  console.log(chunk.toString())
  rs.pause()
  setTimeout(() => {
    rs.resume()
  }, 1000)
}) */

/* rs.on('readable', () => {
  let data = rs.read()
  console.log(data)
  let data
  while((data = rs.read(1)) !== null) {
    console.log(data.toString())
    console.log('----------', rs._readableState.length)
  }
}) */

rs.on('open', (fd) => {
  console.log(fd, '文件打开了')
})

rs.on('close', () => {
  console.log('文件关闭了')
})
let bufferArr = []
rs.on('data', (chunk) => {
  bufferArr.push(chunk)
})

rs.on('end', () => {
  console.log(Buffer.concat(bufferArr).toString())
  console.log('当数据被清空之后')
})

rs.on('error', (err) => {
  console.log('出错了')
})

二十、文件可写流

const fs = require('fs')

const ws = fs.createWriteStream('test.txt', {
  flags: 'w', 
  mode: 438,
  fd: null,
  encoding: "utf-8",
  start: 0,
  highWaterMark: 3
})

let buf = Buffer.from('abc')

// 字符串 或者  buffer ===》 fs rs
/* ws.write(buf, () => {
  console.log('ok2')
}) */

/* ws.write('11', () => {
  console.log('ok1')
}) */

/* ws.on('open', (fd) => {
  console.log('open', fd)
}) */

ws.write("2")

// close 是在数据写入操作全部完成之后再执行
/* ws.on('close', () => {
  console.log('文件关闭了')
}) */

// end 执行之后就意味着数据写入操作完成
ws.end('11')


// error
ws.on('error', (err) => {
  console.log('出错了')
})


二十一、write执行流程

const fs = require('fs')

let ws = fs.createWriteStream('test.txt', {
  highWaterMark: 3
})

let flag = ws.write('1')
console.log(flag)

flag = ws.write('2')
console.log(flag)

// 如果 flag 为 false 并不是说明当前数据不能被执行写入
// 

ws.on('drain', () => {
  console.log('11')
})
  1. 第一次调用write方法时是将数据直接写入到文件中
  2. 第二次开始write方法就是将数据写入至缓存
  3. 生产速度和消费速度是不一样的,一般情况下生产速度要比消费速度快快很多
  4. 当flag为false之后并不意味着当前次的数据不能被写入了 但是我们应该告知数据的生产者,当前的消费速度已经跟不上生产速度了,所以这个时候,我们一般将可读流模块修改为暂停模式。
  5. 当数据生产者暂停之后,消费者会慢慢的消化它内部缓存中的数据,直到可以再次被执行写入操作。
  6. 当缓存区可以继续写入数据时如何让生产者知道?drain事件

二十二、控制写入速度

/**
 * 需求:“11” 写入指定的文件
 * 01 一次性写入
 * 02 分批写入
 * 对比:
 */
let fs = require('fs')

let ws = fs.createWriteStream('test.txt', {
  highWaterMark: 3
})

// ws.write('11')
let source = "11".split('')
let num = 0
let flag = true

function executeWrite () {
  flag = true
  while(num !== 4 && flag) {
    flag = ws.write(source[num])
    num++
  }
}

executeWrite()

ws.on('drain', () => {
  console.log('drain 执行了')
  executeWrite()
})

// pipe

二十三、背压机制

node.js的stream已实现了背压机制

在这里插入图片描述
内存溢出、GC频繁调用、其他进程变慢

在这里插入图片描述

let fs = require('fs')

let rs = fs.createReadStream('test.txt', {
  highWaterMark: 4
})

let ws = fs.createWriteStream('test1.txt', {
  highWaterMark: 1
})

let flag = true

/* rs.on('data', (chunk) => {
  flag = ws.write(chunk, () => {
    console.log('写完了')
  })
  if (!flag) {
    rs.pause()
  }
})

ws.on('drain', () => {
  rs.resume()
}) */

rs.pipe(ws)

二十四、链表结构

为什么不采用数组存储数据?

数组缺点

  • 数组存储数据的长度具有上限
  • 数组存在塌陷问题

在这里插入图片描述

二十五、pipe方法使用

const fs = require('fs')
const myReadStream = require('./ReadStream')

// const rs = fs.createReadStream('./f9.txt', {
//   highWaterMark: 4
// })

const rs = new myReadStream('./f9.txt')

const ws = fs.createWriteStream('./f10.txt')

rs.pipe(ws)

// data 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/739965.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手把手教-单片机stm32基于w25q128使用文件系统

一、开发测试环境 ①野火stm32f407开发板 ②rtthread操作系统 W25Q128的电路原理图&#xff1a; 二、开发步骤 ①使能spi驱动。 ②使能spi bus/device 驱动&#xff0c;选择sfud驱动。 ③开启dfs功能&#xff0c;选择elm文件系统。 ④保存&#xff0c;重新生成工程。 ⑤下载到…

VueCli 脚手架使用

VueCli 脚手架 到目前为止&#xff0c;已经会了Vue基本使用&#xff08;去创建vue实例&#xff0c;创建之后再去挂载&#xff0c;挂载之后就去使用各种功能&#xff0c;挂载之后就可以使用其各种功能&#xff0c;data methods compute 以及各个生命周期&#xff0c;常用的属性以…

779. 最长公共字符串后缀

题面&#xff1a; 给出若干个字符串&#xff0c;输出这些字符串的最长公共后缀。 输入格式 由若干组输入组成。 每组输入的第一行是一个整数 NN。 NN 为 00 时表示输入结束&#xff0c;否则后面会继续有 NN 行输入&#xff0c;每行是一个字符串&#xff08;字符串内不含空白符&…

Redis深入 —— 持久化和事务

前言 最近的学习中&#xff0c;荔枝深入了解了Redis的持久化、Redis事务相关的知识点并整理相应的学习笔记&#xff0c;在这篇文章中荔枝也主要梳理了相应的笔记和基本知识&#xff0c;小伙伴们如果需要的话可以看看哈。 文章目录 前言 一、Redis持久化 1.1 RDB 1.1.1 Redi…

掌握驱动之道:L298N模块多方式驱动电机的优劣分析

L298N模块是一种常用的直流电机驱动模块&#xff0c;它可以通过控制输入端口来实现对电机的速度和方向的控制。L298N模块有3个输入端口&#xff1a;IN1、IN2和EN。 方法一&#xff1a;使用高级定时器输出通道和互补输出通道控制电机 将模块的IN1和IN2分别连接到STM32高级定时器…

Python GUI编程利器:Tkinker中的事件处理(11)

​ 小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 和猫妹学Python&#xff0c;一起趣味学编程。 今日目标 学习下事件处理的相关知识点&#xff1a; 事件处理四要素 事件序列 事件绑定 今天要实现如下效果&#xff1…

Java在Excel中进行数据分析

摘要&#xff1a;本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前一段时间淘宝出了一个“淘宝人生”的模块&#xff0c;可以看从注册淘宝账号至今的消…

k8s实战3-使用Helm在AKS上发布应用

AKS(Azure Kubenetes Service)是微软云azure上的K8s服务。 主要分为三步 1 连接到AKS 2 用kubectl发布应用 3 用Helm发布应用 1 登录 az login 2 连接dp-npr-dsm-aks&#xff08;Dsm项目的AKS&#xff09; az account set --subscription {{subID}} az aks get-credent…

指针的进阶(一)

目录 1. 字符指针 方法一 方法二 字符指针面试题 2. 指针数组 3. 数组指针 3.1 数组指针的定义 3.2 &数组名VS数组名 3.3 数组指针的使用 4. 数组传参和指针传参 4.1 一维数组传参 4.2 二维数组传参 4.3 一级指针传参 4.4 二级指针传参 5. 函数指针 代码一 代…

Windows用户怎么取消访问共享文件夹的密码

许多Windows系统用户在访问共享文件夹的时候却提示需要输入密码才可访问。这一步给很多人造成了困扰&#xff0c;其实我们可以取消访问共享文件夹密码。请看下面的两个方法。 方法一&#xff1a; 搜索 网络和共享中心。点击 更改高级共享设置。在最底下密码保护的共享那项&…

用C#写汉诺塔问题

假设要将n个圆盘从A->C&#xff0c;中间可以借助B&#xff0c;那么递归思路是这样的&#xff0c;我们先将除最大的一个圆盘外的其它n-1个圆盘从A->B,借助C&#xff0c;然后将最大的一个圆盘搬到C&#xff0c;最后将刚才的n-1个盘子&#xff0c;从B->C借助A&#xff0c…

Qt完成闹钟提示

未启动: 启动&#xff1a; .cpp #include "widget.h" #include "ui_widget.h"void Widget::btn1_slots() {//点击启动开始定时event_timer this->startTimer(1000);btn1->setEnabled(false);btn2->setEnabled(true);edit2->setEnabled(false…

一个月学通Python(十三):高级Python必须掌握的进阶知识点

专栏介绍 结合自身经验和内部资料总结的Python教程,每天3章,1个月就能全方位的完成Python的学习并进行实战开发。加油吧!卷起来! 全部文章请访问专栏:《Python全栈教程(0基础》 文章目录 专栏介绍Python语言进阶1. 数据结构和算法2. 函数的使用方式3. 面向对象相关知识…

Todo-List案例版本五

安装库npm i pubsub-js 消息的订阅与发布 src/App.vue <template><div class"app"><h1>{{ msg }}</h1><School/><Student/></div> </template><script> import Student from ./components/Student import …

微信小程序常用组件的简单使用 view,scroll-view,swiper,swiper-item,text,rich-text,button,image

微信小程序常用组件的简单使用 1. view组件2. scroll-view 组件3. swiper 和 swiper-item 组件3.1. swiper组件中的常用属性 4. text 和 rich-text组件4.1. text组件4.2. rich-text 组件 5. button 组件6. image组件6.1. image的mode属性 1. view组件 view组件就类似于html中的…

问题总结(持续更新,欢迎补充)

文章目录 前言webshell流量特征内存马蜜罐应急响应Windows 事件ID如何是误报还是攻击&#xff08;如何判断是否攻击成功&#xff09;研判的思路渗透测试思路内网渗透相关溯源反制反序列化&#xff08;Shiro、Weblogic、Log4j&#xff09;CDNMySQL5.5版本以上和以下读写权限的区…

linux 系统errno 对应参考及代码

结论 linux下系统errno都有对应的说明描述&#xff0c;发生错误时获取errno即可知道具体问题描述 如下图 代码如下 golang版 package main import ("syscall""strings""fmt" ) func main() {for i : 0; i < 200; i {if !strings.HasPrefi…

【开源项目】自动化运维平台spug

Spug 基本介绍 Spug是面向中小型企业设计的轻量级无Agent的自动化运维平台&#xff0c;整合了主机管理、主机批量执行、主机在线终端、应用发布部署、在线任务计划、配置中心、监控、报警等一系列功能。 批量执行: 主机命令在线批量执行在线终端: 主机支持浏览器在线终端登录…

为什么技术牛逼的人,不能直接提为项目经理?

早上好&#xff0c;我是老原。 很多来私信我职业规划的小友&#xff0c;有很大一部分都是从事了大几年&#xff0c;10年的技术开发大佬…… 到这个层级的大佬&#xff0c;他们最大的困惑是&#xff1a;到我这个年纪/级别还有必要转管理吗&#xff1f; 是否有必要&#xff0c…

X6 基于VUE流程编辑器开发

先看效果图 主要插件X6 x6-vue-shape antv/x6-plugin-dnd 代码太多没有整理出来