Web服务器开发、文件上传

news2024/11/24 0:03:15

1 Stream的读写操作

2 http模块web服务

3 request请求对象

4 response响应对象

5 axios node中使用

6 文件上传的细节分析

前面一篇提到的内容是node对底层的文本操作,还没有涉及到从文本文件获取信息然后传递给客户端和如何响应客户端请求。这里开始了解如何实现Web服务器开发。

stream就是流的意思

一、Stream的读写操作

可读流的基本使用:

const fs = require('fs')

// 1.一次性读取
// 缺点一: 没有办法精准控制从哪里读取, 读取什么位置.
// 缺点二: 读取到某一个位置的, 暂停读取, 恢复读取.
// 缺点三: 文件非常大的时候, 多次读取.
// fs.readFile('./aaa.txt', (err, data) => {
//   console.log(data)
// })

// 2.通过流读取文件
// 2.1. 创建一个可读流
// start: 从什么位置开始读取
// end: 读取到什么位置后结束(包括end位置字节)
const readStream = fs.createReadStream('./aaa.txt', {
// 从第八个字符开始读取
 start: 8,
// 读取到第22个字符
 end: 22,
// 分三次读取
 highWaterMark: 3
})

// 通过event的事件监听来获取流操作的过程
// 这个data事件是来自readStream的
readStream.on('data', (data) => {
  console.log(data.toString())
// 暂停
  readStream.pause()

  setTimeout(() => {
// 解除暂停
    readStream.resume()
  }, 2000)
})


可读流的其他事件:

const fs = require('fs')

// 1.通过流读取文件
const readStream = fs.createReadStream('./aaa.txt', {
// 从第八个字符开始读取
 start: 8,
// 读取到第22个字符
 end: 22,
// 分三次读取
 highWaterMark: 3
})


// 2.监听读取到的数据
readStream.on('data', (data) => {
  console.log(data.toString())
})

// 3.补充其他的事件监听,这里可以获取文件描述符,具体可以去看前一篇的内容
readStream.on('open', (fd) => {
  console.log('通过流将文件打开~', fd)
})

readStream.on('end', () => {
  console.log('已经读取到end位置')
})

readStream.on('close', () => {
  console.log('文件读取结束, 并且被关闭')
})

可写流的使用过程:

写入过程是可以一直写入的,但是关闭需要手动写关闭的代码,不像读操作有自动关闭的功能。

const fs = require('fs')

// 1.一次性写入内容
// fs.writeFile('./bbb.txt', 'hello world', {
//   encoding: 'utf-8',
//   flag: 'a+'
// }, (err) => {
//   console.log('写入文件结果:', err)
// })

// 2.创建一个写入流
const writeStream = fs.createWriteStream('./ccc.txt', {
  flags: 'a'
})

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

writeStream.write('coderwhy')
writeStream.write('aaaa')
writeStream.write('bbbb', (err) => {
  console.log("写入完成:", err)
})

writeStream.on('finish', () => {
  console.log('写入完成了')
})

writeStream.on('close', () => {
  console.log('文件被关闭~')
})

// 3.写入完成时, 需要手动去掉用close方法
// writeStream.close()

// 4.end方法: 
// 操作一: 将最后的内容写入到文件中, 并且关闭文件
// 操作二: 关闭文件
writeStream.end('哈哈哈哈')

文件的拷贝流操作:

const fs = require('fs')

// 1.方式一: 一次性读取和写入文件
// fs.readFile('./foo.txt', (err, data) => {
//   console.log(data)
//   fs.writeFile('./foo_copy01.txt', data, (err) => {
//     console.log('写入文件完成', err)
//   })
// })


// 2.方式二: 创建可读流和可写流
// const readStream = fs.createReadStream('./foo.txt')
// const writeStream = fs.createWriteStream('./foo_copy02.txt')

// readStream.on('data', (data) => {
//   writeStream.write(data)
// })

// readStream.on('end', () => [
//   writeStream.close()
// ])

// 3.在可读流和可写流之间建立一个管道
const readStream = fs.createReadStream('./foo.txt')
const writeStream = fs.createWriteStream('./foo_copy03.txt')

readStream.pipe(writeStream)

可写流的start属性:

const fs = require('fs')

const writeStream = fs.createWriteStream('./ddd.txt', {
  // mac上面是没有问题
  // flags: 'a+',
  // window上面是需要使用r+
  flags: 'r+',
  start: 5
})

writeStream.write('my name is why')
writeStream.close()

二、HTTP模块:

应用http模块或者基于http模块的框架express和koa来制作属于我们的服务器。和java和go做后端差不多,使用node制作服务器是前端比较容易实现的。

http模块是基础和底层的,所以我们会比较多的使用框架express和koa

所以现在说的http模块只是学习使用,具体就去用express和koa框架就好了。

端口主机host参数的知识:当你设置127.0.0.0和localhost的时候,如果是别的电脑需要访问会访问不到。所以,输入0.0.0.0默认是最好的,其他电脑是可以访问的到的。vue的跨域那部分最好也是用0.0.0.0来做代理。

工具一:浏览器访问服务器的时候会发送两次请求,服务器会回复两次(一次是访问内容,另外一次是为了拿到icon),并且浏览器测试不了post的接口,get接口能测试。基于这个原因,我们一般不直接用浏览器来测试我们的http服务器,。转而使用postman就不会出现访问两次的情况。

使用postman的方法:

在collections里面创建一个(举例取名为NodeServer),然后创建文件夹,文件夹里面放request,最后在send的前面一个输入框输入你开启的服务器的ip地址和端口号。

工具二:由于使用node来打开服务器时是不会因为你更新了服务器的代码然后重新刷新开启更新后的服务器的,为了实现上面的能够在服务器代码更新的时候重新开启服务器的功能,我们下载一个包:

npm install nodemon -g

之后想要打开服务器就输入代码来打开,不再使用node xxx.js

nodemon xxx.js

http服务器的基本使用

当运行这个js文件时,是不会自动结束这次运行的。因为服务器就是一直开着的,等待客户端向服务器发送消息。

下面这个代码使用之后,你可以去浏览器输入localhost:8000来访问服务器了, 

const http = require('http')


// 创建一个http对应的服务器
const server = http.createServer((request, response) => {
  // request对象中包含本次客户端请求的所有信息
  // 请求的url
  // 请求的method
  // 请求的headers
  // 请求携带的数据

  // response对象用于给客户端返回结果的
  response.end("Hello World")
})

// 开启对应的服务器, 并且告知需要监听的端口
// 监听端口时, 监听1024以上的端口, 666535以下的端口
// 1025~65535之间的端口
// 2个字节 => 256*256 => 65536 => 0~65535
server.listen(8000, () => {
  console.log('服务器已经开启成功了~')
})

创建多个http的服务器

const http = require('http')

// 1.创建一个服务器
const server1 = http.createServer((req, res) => {
  res.end("2000端口服务器返回的结果~")
})
server1.listen(2000, () => {
  console.log('2000端口对应的服务器启动成功~')
})

// 2.创建第二个服务器
const server2 = http.createServer((req, res) => {
  res.end("3000端口服务器返回的结果~")
})
server2.listen(3000, () => {
  console.log('3000端口对应的服务器启动成功~')
})


// 3.创建第三个服务器
// const server3 = new http.Server()

额外小知识点的补充

工具1、主要是使用postman来测试服务器

工具2、由于使用node来打开服务器时是不会因为你更新了服务器的代码然后重新刷新开启更新后的服务器的,为了实现上面的能够在服务器代码更新的时候重新开启服务器的功能,我们下载一个包:

npm install nodemon -g
const http = require('http')

// 1.创建server服务器
const server = http.createServer((req, res) => {
  console.log('服务器被访问~')

  res.end('hello world aaaa')
})


// 2.开启server服务器
server.listen(8000, () => {
  console.log('服务器开启成功~')
})

http服务器-request对象

const http = require('http')

// 1.创建server服务器
const server = http.createServer((req, res) => {
  // request对象中包含哪些信息?
  // 1.url信息
  console.log(req.url)
  // 2.method信息(请求方式)
  console.log(req.method)
  // 3.headers信息(请求信息)
  console.log(req.headers)

  res.end('hello world aaaa')
})


// 2.开启server服务器
server.listen(8000, () => {
  console.log('服务器开启成功~')
})

从postman这里的url和请求方式、请求头信息。可以知道代码中的req.url的值是/home

req.method的值是POST    reqheaders的值为下图显示的。

http服务器-区分不同url

这里是通过不同url对客户端进行回复信息,比如res.end()在这里就是回复客户端信息。

const http = require('http')

// 1.创建server服务器
const server = http.createServer((req, res) => {
  const url = req.url

  if (url === '/login') {
    res.end('登录成功~')
  } else if (url === '/products') {
    res.end('商品列表~')
  } else if (url === '/lyric') {
    res.end('天空好想下雨, 我好想住你隔壁!')
  }
})


// 2.开启server服务器
server.listen(8000, () => {
  console.log('服务器开启成功~')
})

http服务器-区分不同method

这里是对客户端进行限制使用何种请求方式,比如是get还是post的请求方式。

const http = require('http')

// 1.创建server服务器
const server = http.createServer((req, res) => {
  const url = req.url
  const method = req.method

  if (url === '/login') {
    if (method === 'POST') {
      res.end('登录成功~')
    } else {
      res.end('不支持的请求方式, 请检测你的请求方式~')
    }
  } else if (url === '/products') {
    res.end('商品列表~')
  } else if (url === '/lyric') {
    res.end('天空好想下雨, 我好想住你隔壁!')
  }
})


// 2.开启server服务器
server.listen(8000, () => {
  console.log('服务器开启成功~')
})

request参数解析-query参数

用户一般会发送数据,比如?后面的一串就是发送的参数。

 这里引入了url和querystring来帮助我们快速解析query。先解析url再解析query。

const http = require('http')
const url = require('url')
const qs = require('querystring')

// 1.创建server服务器
const server = http.createServer((req, res) => {
  // 1.参数一: query类型参数
  // /home/list?offset=100&size=20
  // 1.1.解析url
  const urlString = req.url
  const urlInfo = url.parse(urlString)

  // 1.2.解析query: offset=100&size=20
  const queryString = urlInfo.query
  const queryInfo = qs.parse(queryString)
  console.log(queryInfo.offset, queryInfo.size)

  res.end('hello world aaaa bbb')
})


// 2.开启server服务器
server.listen(8000, () => {
  console.log('服务器开启成功~')
})

request参数解析-body参数

这里模拟客户机向服务器发送请求的消息体的内容为一个对象类型,里面有name和password的信息。

const http = require('http')
const url = require('url')
const qs = require('querystring')

// 1.创建server服务器
const server = http.createServer((req, res) => {
  // 获取参数: body参数
  //这里需要设置编码方式才能把buffer的二进制转成真正的消息体内容
  req.setEncoding('utf-8')

  // request对象本质是上一个readable可读流,所以可以通过on拿到数据
  // 这里读取的消息体的内容在data事件里面
  let isLogin = false
  req.on('data', (data) => {
    const dataString = data
  // 把字符串形式转成对象形式
    const loginInfo = JSON.parse(dataString)
    if (loginInfo.name === 'coderwhy' && loginInfo.password === '123456') {
      isLogin = true
    } else {
      isLogin = false
    }
  })

  req.on('end', () => {
    if (isLogin) {
      res.end('登录成功, 欢迎回来~')
    } else {
      res.end('账号或者密码错误, 请检测登录信息~')
    }
  })
})


// 2.开启server服务器
server.listen(8000, () => {
  console.log('服务器开启成功~')
})

request参数解析-headers参数

这里的headers['content-type']可以告诉服务器客户端发送给服务器的消息体是什么类型的,比如:消息体如果是对象类型的,那么值就是

;消息体如果是字符串类型的,那么值就是

同样的,postman客户端怎么发送token?

const http = require('http')
const url = require('url')
const qs = require('querystring')

// 1.创建server服务器
const server = http.createServer((req, res) => {
  console.log(req.headers)
  console.log(req.headers['content-type'])

  // cookie/session/token
  const token = req.headers['authorization']
  console.log(token)

  res.end('查看header的信息~')
})


// 2.开启server服务器
server.listen(8000, () => {
  console.log('服务器开启成功~')
})

response响应对象-响应方式

主要是用end,最好不要用close()来关闭。

const http = require('http')

// 1.创建server服务器
const server = http.createServer((req, res) => {
  // res: response对象 => Writable可写流
  // 1.响应数据方式一: write
  res.write("Hello World")
  res.write("哈哈哈哈")

  // // 2.响应数据方式二: end
  res.end("本次写出已经结束")
})


// 2.开启server服务器
server.listen(8000, () => {
  console.log('服务器开启成功~')
})

response响应对象-响应状态码

const http = require('http')

// 1.创建server服务器
const server = http.createServer((req, res) => {  
  // 响应状态码
  // 1.方式一: statusCode
  // res.statusCode = 403

  // 2.方式二: setHead 响应头
  res.writeHead(401)

  res.end('hello world aaaa')
})


// 2.开启server服务器
server.listen(8000, () => {
  console.log('服务器开启成功~')
})

response响应对象-响应header

这里主要是告诉浏览器以什么编码方式进行解析服务器传递回来的信息。

const http = require('http')

// 1.创建server服务器
const server = http.createServer((req, res) => {

  // 设置header信息: 数据的类型以及数据的编码格式
  // 1.单独设置某一个header
  // res.setHeader('Content-Type', 'text/plain;charset=utf8;')

  // 2.和http status code一起设置
  res.writeHead(200, {
    'Content-Type': 'application/json;charset=utf8;'
  })

  const list = [
    { name: "why", age: 18 },
    { name: "kobe", age: 30 },
  ]
  res.end(JSON.stringify(list))
})


// 2.开启server服务器
server.listen(8000, () => {
  console.log('服务器开启成功~')
})

三、axios node中使用

想要在node里面使用axios就要先下载axios,具体步骤如下:

1、生成package.json文件 npm init

2、下载axios  npm install axios

3、开启一个服务器

在node中发送请求-axios

const axios = require('axios')

axios.get('http://localhost:8000').then(res => {
  console.log(res.data)
})

在node中发送请求-http

const http = require('http')

// 1.使用http模块发送get请求、没有提供post方法
// http.get('http://localhost:8000', (res) => {
//   // 从可读流中获取数据
//   res.on('data', (data) => {
//     const dataString = data.toString()
//     const dataInfo = JSON.parse(dataString)
//     console.log(dataInfo)
//   })
// })

// 2.使用http模块发送post请求
const req = http.request({
  method: 'POST',
  hostname: 'localhost',
  port: 8000
}, (res) => {
  res.on('data', (data) => {
    const dataString = data.toString()
    const dataInfo = JSON.parse(dataString)
    console.log(dataInfo)
  })
})

// 必须调用end, 表示写入内容完成
req.end()

文件上传-错误的做法

一般来说文件上传都是借助其他软件的,一般不是自己手动处理。

文件上传必须是post请求,不可以是get请求。

+ 下面这个错误的上传和存储文件的方法,虽然可以把客户端上传的文件传递到服务器,服务器获取信息并写入到png文件里面,但是,其实根本打不开个png文件,这是因为服务器读取的这个文件内容在写入png的时候还把其他东西写进去了,看图软件打不开这个png文件。

这种写法单上传一个图片都显示不了更别说用户上传的是有其他内容的加上图片的内容。

const http = require("http");
const fs = require('fs')

// 1.创建server服务器
const server = http.createServer((req, res) => {
  // 创建writable的stream
  const writeStream = fs.createWriteStream('./foo.png', {
    flags: 'a+'
  })

  // req.pipe(writeStream)

  // 客户端传递的数据是表单数据(请求体)
  req.on("data", (data) => {
    console.log(data);
    writeStream.write(data)
  });

  req.on("end", () => {
    // console.log("数据传输完成~");
    // writeStream.close()
    res.end("文件上传成功~");
  });
});

// 2.开启server服务器
server.listen(8000, () => {
  console.log("服务器开启成功~");
});

文件上传-正确的做法

通过vscode的debug来打断点查看上传的内容是什么东西

手动处理图片上传太麻烦,后续直接用框架来实现比较方便。

 

 

const http = require("http");
const fs = require('fs')

// 1.创建server服务器
const server = http.createServer((req, res) => {
  req.setEncoding('binary')

  const boundary = req.headers['content-type'].split('; ')[1].replace('boundary=', '')
  console.log(boundary)

  // 客户端传递的数据是表单数据(请求体)
  let formData = ''
  req.on("data", (data) => {
    formData += data
  });

  req.on("end", () => {
    console.log(formData)
    // 1.截图从image/jpeg位置开始后面所有的数据
    const imgType = 'image/jpeg'
    const imageTypePosition = formData.indexOf(imgType) + imgType.length
    let imageData = formData.substring(imageTypePosition)

    // 2.imageData开始位置会有两个空格
    imageData = imageData.replace(/^\s\s*/, '')

    // 3.替换最后的boundary
    imageData = imageData.substring(0, imageData.indexOf(`--${boundary}--`))

    // 4.将imageData的数据存储到文件中
    fs.writeFile('./bar.png', imageData, 'binary', () => {
      console.log('文件存储成功')
      res.end("文件上传成功~");
    })
  });
});

// 2.开启server服务器
server.listen(8000, () => {
  console.log("服务器开启成功~");
});

文件上传-浏览器代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <input type="file">
  <button>上传</button>

  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    // 文件上传的逻辑
    const btnEl = document.querySelector('button')
    btnEl.onclick = function() {
      // 1.创建表单对象
      const formData = new FormData()

      // 2.将选中的图标文件放入表单
      const inputEl = document.querySelector('input')
      formData.set('photo', inputEl.files[0])

      // 3.发送post请求, 将表单数据携带到服务器(axios)
      axios({
        method: 'post',
        url: 'http://localhost:8000',
        data: formData,
        headers: {
          'Content-Type': 'multipart/form-data'
        }
      })
    }
  </script>

</body>
</html>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

相关文章

chatgpt赋能python:Python实现人脸识别的可能性和局限性

Python实现人脸识别的可能性和局限性 随着计算机视觉技术的不断发展&#xff0c;人脸识别技术也得到了广泛应用&#xff0c;其中Python作为一种高效、简洁和易于学习的编程语言&#xff0c;被广泛用于人脸识别算法的开发和实现。 什么是人脸识别&#xff1f; 人脸识别是一种…

chatgpt赋能python:Python如何导入CSV的完全指南

Python如何导入CSV的完全指南 CSV是一种常见的数据格式&#xff0c;在数据分析和处理中使用广泛。使用Python&#xff0c;我们可以轻松地读取、处理和分析CSV文件。在本指南中&#xff0c;我们将介绍如何使用Python导入CSV文件。 什么是CSV文件&#xff1f; CSV文件是按照逗…

chatgpt赋能python:Python如何将内容写进文件:从初学者到高级编程工程师的终极指南

Python如何将内容写进文件&#xff1a;从初学者到高级编程工程师的终极指南 Python是一种流行的编程语言&#xff0c;具有简洁而易于阅读的语法&#xff0c;开发人员可以非常方便地使用它来读取和写入文件。 本文将从基础到高级介绍使用Python将内容写入文件。 基础知识 在P…

论文笔记--Evaluating Large Language Models Trained on Code

论文笔记--Evaluating Large Language Models Trained on Code 1. 文章简介2. 文章概括3 文章重点技术3.1 评估3.2 模型训练--Codex3.3 微调模型--Codex-S3.4 微调模型--Codex-D 4. 文章亮点5. 原文传送门6. References 1. 文章简介 标题&#xff1a;Evaluating Large Languag…

chatgpt赋能python:Python构造函数详解

Python构造函数详解 在Python中&#xff0c;构造函数是一种特殊的函数&#xff0c;用于创建类的实例并初始化其属性。Python构造函数的名称为__init__&#xff0c;它在创建类的实例时自动调用。本篇文章将全面介绍Python构造函数的重要性及其使用方法。 为什么需要构造函数&a…

Python之并发编程协程

一、介绍 基于单线程来实现并发&#xff0c;即只用一个主线程&#xff08;很明显可利用的cpu只有一个&#xff09;情况下实现并发&#xff0c;为此我们需要先回顾下并发的本质&#xff1a;切换保存状态 CPU正在运行一个任务&#xff0c;会在两种情况下切走去执行其他的任务&a…

从零手写操作系统之RVOS抢占式多任务实现-06

从零手写操作系统之RVOS抢占式多任务实现-06 多任务系统的分类抢占式多任务的设计代码任务切换流程分析系统启动任务mepc初始化首个被调度执行的任务任务切换 兼容协作式多任务软件中断编码实现 测试 注意点 本系列参考: 学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春 整理而…

QT QVerticalSpacer 弹簧控件

本文详细的介绍了QVerticalSpacer控件的各种操作&#xff0c;例如&#xff1a;新建界面、控件布局、隐藏控件、设置宽高、添加布局、其它参数、.h源文件、cpp源文件、其它文章等等操作。 实际开发中&#xff0c;一个界面上可能包含十几个控件&#xff0c;手动调整它们的位置既费…

chatgpt赋能python:Python如何优化SEO

Python如何优化SEO SEO是指搜索引擎优化&#xff0c;是提高网站在搜索引擎中排名的技术实践。Python是一种高效、易用、灵活的编程语言&#xff0c;可以被应用于SEO的优化过程中。 关键词优化 关键词是SEO过程中的重要元素&#xff0c;Python可以帮助我们快速优化关键词。以…

chatgpt赋能python:Python拆分:如何有效地拆分Python代码

Python拆分&#xff1a;如何有效地拆分Python代码 Python是一种简洁而优雅的编程语言&#xff0c;它拥有庞大的库&#xff0c;使得它可以轻松处理各种任务。然而&#xff0c;在开发大型项目时&#xff0c;代码可能会变得冗长而难以维护。 通过拆分代码&#xff0c;可以使得代码…

WhatWeb使用教程,图文教程(超详细)

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 WhatWeb 一、扫描网站指纹二、扫描强度三、扫描内网…

Golang每日一练(leetDay0088) 数组的乘积、搜索二维矩阵II

目录 238. 除自身以外数组的乘积 Product of Array Except Self &#x1f31f;&#x1f31f; 240. 搜索二维矩阵 II Search A 2d Matrix ii &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专栏 Python每…

SpringBoot中的增删改查案例

目录 一、案例说明 二、数据库 三、案例源码 3.1、pom文件 3.2、Application.yml 3.3、项目结构 a&#xff09;整体结构 b&#xff09;Java代码部分 c&#xff09;资源文件部分 3.4、业务功能的实现 1&#xff09;配置类 2&#xff09;实体类 3&#xff09;Mapper文…

chatgpt赋能python:Python中如何对数据进行归一化

Python中如何对数据进行归一化 什么是数据归一化&#xff1f; 在数据分析和机器学习中&#xff0c;数据归一化&#xff08;Normalization&#xff09;指的是对数据进行缩放以使其值域范围映射到特定范围内&#xff0c;以便更好地进行处理和分析。通常情况下&#xff0c;数据归…

《Java并发编程实战》课程笔记(十四)

原子类&#xff1a;无锁工具类的典范 对于简单的原子性问题&#xff0c;还有一种无锁方案。Java SDK 并发包将这种无锁方案封装提炼之后&#xff0c;实现了一系列的原子类。无锁方案相对互斥锁方案&#xff0c;最大的好处就是性能。 互斥锁方案为了保证互斥性&#xff0c;需要…

chatgpt赋能python:Python如何处理SEO

Python如何处理SEO Python语言是一种非常流行的编程语言&#xff0c;它可以用于各种类型的应用程序开发&#xff0c;包括网页开发。在网页开发中&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;是至关重要的&#xff0c;因为它决定了搜索引擎是否能够有效地找到和展示您…

chatgpt赋能python:Python如何快速找到函数

Python如何快速找到函数 作为一名有10年Python编程经验的工程师&#xff0c;我深知在Python编程过程中如何快速找到函数是非常重要的。在学习和掌握Python函数之前&#xff0c;首先需要学会如何快速地找到所需的Python函数。这篇文章将介绍一些我在编程中经常使用的方法&#…

RK3588平台开发系列讲解(驱动基础篇)I2C 总线实现 client 设备

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、非设备树实现 i2c二、设备树实现 i2c沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 Linux 中的 I2C 也是按照平台总线模型设计的,既然也是按照平台总线模型设计的,是不是也分为一个device 和一个 driv…

编程比赛 入门 学习路线

内容若有不足与纰漏&#xff0c;请多指教&#xff01; 文章目录 写在前面入门建议掌握的知识点数学思想算法 | 数据结构c STL容器类容器适配器组件迭代器常用算法函数 其他 编程 | 学习学习 | 练题 平台编程笔记 | 题解 比赛相关要点注意赛前赛中赛后 资料分享笔记题解资料PDF&…

JVM栈帧结构及动态链接

1. 栈帧结构 附加信息&#xff08;此处官网未具体说明&#xff0c;可忽略&#xff0c;参考图中结构理解即可&#xff09;&#xff1a;栈帧的高度&#xff0c;虚拟机版本信息 栈帧信息&#xff1a;附加信息动态链接方法的返回地址 局部变量表&#xff1a;方法中定义的局部变量…