littlefs文件系统的移植和测试

news2024/11/16 22:43:31

简介

LittleFS 由ARM官方发布,ARM mbedOS的官方推荐文件系统,具有轻量级,掉电安全的特性。主要用在微控制器和flash上

  • 掉电恢复,在写入时即使复位或者掉电也可以恢复到上一个正确的状态。

  • 擦写均衡,有效延长flash的使用寿命。例如W25QXX系列的spi接口的flash,擦写次数大概在10万次,如果是操作flash比较频繁那么这10万次很快就会到达上限从而导致芯片废掉。

  • 有限的RAM/ROM,相对于FATFS节省ROM和RAM空间

  • 缺点:不兼容windows。

  • LFS_NO_MALLOC:决定使用动态内存还是静态内存,这个宏可以不定义

  • LFS_NO_ASSERT:决定是否使用断言

  • LFS_YES_TRACE:决定是否使用LFS函数调用跟踪,调试时候可以打开

  • LFS_NO_DEBUG:决定是否使用调试信息输出

  • LFS_NO_ERROR:决定是否使用错误信息输出

  • LFS_NO_WARN:决定是否使用警告信息输出

    参考链接:https://blog.csdn.net/qq153471503/article/details/120303225

核心数据结构

// Configuration provided during initialization of the littlefs
struct lfs_config {
    //用户提供的上下文,可用于将信息传递给块设备操作
    void *context;
    // 读块接口,用于从块内读取一个块数据
    int (*read)(const struct lfs_config *c, lfs_block_t block,
            lfs_off_t off, void *buffer, lfs_size_t size);
    // 写块接口,用于将一段数据写入到块中,这个块必须是已经被擦除的
    int (*prog)(const struct lfs_config *c, lfs_block_t block,
            lfs_off_t off, const void *buffer, lfs_size_t size);
    // 擦块接口,用于擦除一个块
    int (*erase)(const struct lfs_config *c, lfs_block_t block);
    // 有的块设备有缓存需要进行同步操作才能将缓存里的内容写出
    int (*sync)(const struct lfs_config *c);
#ifdef LFS_THREADSAFE //多线程使用
    // 加锁
    int (*lock)(const struct lfs_config *c);
     // 解锁
    int (*unlock)(const struct lfs_config *c);
#endif
    //读取的块的最小大小(以字节为单位)。所有读取操作都将是这个值的倍数。
    lfs_size_t read_size;
    // 每次写入的字节数,可以比物理写单元大以改善性能,这个数值决定了写缓存的大小,必须是read_size的整数倍,但值太大会带来更多的内存消耗.
    lfs_size_t prog_size;
    // 每个擦除块的字节数,可以比物理擦除单元大,但此数值应尽可能小因为每个文件至少会占用一个块。必须是prog_size的整数倍.
    lfs_size_t block_size;
    // 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小
    lfs_size_t block_count;
    // littlefs清除元数据日志和移动之前的擦除周期数
//将元数据转移到另一个块。建议值在100-1000的范围内,较大的值以较低的成本获得更好的性能
//磨损分布不太一致。
//
//设置为-1可禁用块级磨损水平.
    int32_t block_cycles;
    // 块缓存大小.
    lfs_size_t cache_size;
    // 先行缓存大小.
    lfs_size_t lookahead_size;
    lfs_size_t compact_thresh;
    // 可选参数,用于静态分配读缓存,这个缓存的大小应该等于read_size
    void *read_buffer;
    // 可选参数,用于静态分配写缓存,这个缓存的大小应该等于prog_size.
    void *prog_buffer;
    // 可选参数,用于静态分配预测缓存,这个缓存的大小应该等于预测深度lookahead/8,因为每个bit表示一个块
    void *lookahead_buffer;

    // 文件名长度(以字节为单位)的可选上限。没有缺点
//较大的名称,但信息结构体的大小由控制
//LFS_NAME_MAX定义。默认为存储在上的LFS_NAME_MAX或NAME_MAX
//磁盘为零。

    lfs_size_t name_max;

    lfs_size_t file_max;

    lfs_size_t attr_max;

    lfs_size_t metadata_max;

    lfs_size_t inline_max;

#ifdef LFS_MULTIVERSION
 
    uint32_t disk_version;
#endif
};

lfs_config结构体

结构体成员变量说明
void *context用于给底层块设备传参,比如:要写入的文件信息、位置、大小、是否有坏块等。该参数的数据结构由底层块设备驱动来定义。如果不需要传参的话可以不赋值
int (*read)块设备读取函数指针
int (*prog)块设备写入函数指针,写入前必须保证该写入块已经被擦除过
int (*erase)块设备擦除函数指针
int (*sync)块设备同步函数指针,若块设备不需要同步操作,可以直接返回成功
lfs_size_t read_size最小读取字节数,所有的读取操作字节数必须是它的整数倍
lfs_size_t prog_size最小写入字节数,所有的写入操作字节数必须是它的整数倍
lfs_size_t block_size擦除块操作的字节数,该选项不影响 RAM 消耗,可以比物理擦除尺寸大,但是每个文件至少占用一个块,必须是读取和写入操作字节数的整数倍
lfs_size_t block_count设备上可擦除块的数量,block_size x block_count = 块设备容量
int32_t block_cycleslittlefs 系统删除元数据日志并将元数据移动到另一个块之前的擦除周期数。建议取值范围为 100 ~ 1000,较大数值有较好的性能但是会导致磨损分布不一致,若取值 -1 的话,即为禁用块级磨损均衡
lfs_size_t cache_size块缓存大小,每个缓存都会在 RAM 中缓冲一部分块数据,littlefs 系统需要一个读取缓存、一个写入缓存,每个文件还需要一个额外的缓存。更大的缓存可以通过存储更多的数据并降低磁盘访问数量等手段来提高性能
lfs_size_t lookahead_size先行缓冲大小,更大的先行缓冲可以提高分配操作中可被发现的块数量。即分配块时每次分配多少个块,16就表示每次分配16个块。先行缓冲以 bit 位形式来存储,故 RAM 中的一个字节对应8个块。该值必须是8的整数倍
int (*lock)块设备加锁函数指针,需定义 LFS_THREADSAFE 宏才可用,若不需要多线程操作可不赋值
int (*unlock)块设备解锁函数指针,需定义 LFS_THREADSAFE 宏才可用,若不需要多线程操作可不赋值
void *read_buffer可选参数。读取静态缓冲区指针。若目标MCU不支持动态分配堆内存的话,就需要定义这个参数,本人建议静态分配时手动指定一个内存空间,大小是cache_size
void *prog_buffer可选参数。写入静态缓冲区指针。若目标MCU不支持动态分配堆内存的话,就需要定义这个参数,本人建议静态分配时手动指定一个内存空间,大小是cache_size
void *lookahead_buffer可选参数。先行分配静态缓冲区指针,需要32bit对齐。若目标MCU不支持动态分配堆内存的话,就需要定义这个参数,本人建议静态分配时手动指定一个内存空间,,大小是lookahead_size

注意事项

  • 在创建文件的时候,如果该文件已经创建过了,你再次创建同样的名字,没有加LFS_O_EXCL属性,文件同样会创建成功,但是不会返回文件已存在的错误码,创建的次数越多,后面文件系统内存会出现泄漏,最后导致写入文件都会报内存不足的问题,需要注意

  • 内外文件系统需要自己注意函数的调用,不要混乱使用。

  • lfs_config配置表看自己的需要的大小适配,不过如果配置不对,很容易报错,推荐用的我的配置表。

  • 挂载文件系统时候,如果没有实现read、erase和write的操作,会出现错误码:-84;

  • 没有挂载成功,调用卸载函数会导致代码卡死

  • 在lfs_util.h中有两个函数lfs_malloc和lfs_free,虽然可以用宏定义定义LFS_NO_MALLOC不使用动态内存,但是在文件系统中打开文件时仍然调用了这个两个函数,在不使用动态内存时需要自己定义一个cache_size大小数组在lfs_malloc中返回这个数组,在不使用动态内存的情况下只能打开一个文件进行读写。

参考链接:https://blog.csdn.net/weixin_43908815/article/details/130179573

参考链接:https://blog.csdn.net/weixin_45270358/article/details/126306342

移植

1.下载文件

文件内容如下:

在这里插入图片描述

2.将这4个文件添加到工程中,并添加头文件路径

3.添加lfs_port.c文件和lfs_user_cfg.h文件

在这里插入图片描述

4.在lfs_port.c文件中添加flash操作接口函数

flash接口

这里使用了sfud开源的nor flash组件

#include <lfs.h>
#include <sfud.h>

/**
 * @description: 块读取函数
 * @param {lfs_config} *c 文件系统提供的上下文操作句柄
 * @param {lfs_block_t} block 第几块,也就是块的编号
 * @param {lfs_off_t} off  这一块的偏移
 * @param {void} *buffer 读取数据存放的地址
 * @param {lfs_size_t} size 读取数据的大小,以字节为单位
 * @return {*}
 */
static int user_provided_block_device_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
{

    sfud_err result = SFUD_SUCCESS;
    const sfud_flash *flash = sfud_get_device_table() + 0;
    result = sfud_read(flash, c->block_size * block + off, size, buffer);
    return LFS_ERR_OK;
}
/**
 * @description: 块写/编程函数--前提是已经擦除的位置
 * @param {lfs_config} *c 文件系统提供的上下文操作句柄
 * @param {lfs_block_t} block 第几块,也就是块的编号
 * @param {lfs_off_t} off  这一块的偏移
 * @param {void} *buffer 读取数据存放的地址
 * @param {lfs_size_t} size 读取数据的大小,以字节为单位
 * @return {*} 编程完成返回LFS_ERR_OK ;编程失败返回其他
 */
static int user_provided_block_device_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
{
    sfud_err result = SFUD_SUCCESS;
    const sfud_flash *flash = sfud_get_device_table() + 0;
    result = sfud_write(flash, c->block_size * block + off, size, buffer);
    return LFS_ERR_OK;
}
/**
 * @description: 块擦除函数
 * @param {lfs_config} *c 文件系统提供的上下文操作句柄
 * @param {lfs_block_t} block 第几块,也就是块的编号
 * @return {*}
 */
static int user_provided_block_device_erase(const struct lfs_config *c, lfs_block_t block)
{
    sfud_err result = SFUD_SUCCESS;
    const sfud_flash *flash = sfud_get_device_table() + 0;

    result = sfud_erase(flash, c->block_size * block, c->block_size);
    return LFS_ERR_OK;
}
/**
 * @description: 数据同步函数,将缓存数据写入硬盘,这里没有缓存直接返回 LFS_ERR_OK
 * @param {lfs_config} *c
 * @return {*}
 */
static int user_provided_block_device_sync(const struct lfs_config *c)
{
    return LFS_ERR_OK;
}

5.构造结构对象lfs_config

#define CHACE_SIZE 16
#define LOOKAHEAD_SIZE 16
static uint8_t _read_buff[CHACE_SIZE];
static uint8_t _write_buff[CHACE_SIZE];
static uint8_t _lookahead_buff[CHACE_SIZE];
// configuration of the filesystem is provided by this struct
const struct lfs_config cfg = {
    // block device operations
    .read = user_provided_block_device_read,
    .prog = user_provided_block_device_prog,
    .erase = user_provided_block_device_erase,
    .sync = user_provided_block_device_sync,

    // block device configuration
    .read_size = 16,                     // 最小读取数量
    .prog_size = 16,                     // 最小写入数量
    .block_size = 4096,                  // 一个擦除块的大小
    .block_count = 128,                  // 一共有多少个块
    .cache_size = CHACE_SIZE,            // 块的缓存大小
    .lookahead_size = 16,                // 现行缓存大小
    .block_cycles = 500,                 // 这里是一个均衡磨损的参数
    .read_buffer = _read_buff,           // 读缓存
    .prog_buffer = _write_buff,          // 写缓存
    .lookahead_buffer = _lookahead_buff, // 先行分配静态缓冲区

};

在lfs_user_cfg.h添加配置

/*
 * @Author: car12
 * @Date: 2024-07-01 17:14:23
 * @LastEditors: 
 * @LastEditTime: 2024-07-25 23:38:01
 * @Description: 请填写简介
 */
/*
 * lfs utility functions
 *
 * Copyright (c) 2022, The littlefs authors.
 * Copyright (c) 2017, Arm Limited. All rights reserved.
 * SPDX-License-Identifier: BSD-3-Clause
 */
#ifndef LFS_USER_CFG_H
#define LFS_USER_CFG_H

// 断言
#define LFS_NO_ASSERT 1

// 调试宏
#define LFS_NO_DEBUG 1

//线程安全  打开需要定义加锁,解锁函数
// #define LFS_THREADSAFE 1

// 没有动态分配内存
// #define LFS_NO_MALLOC 1
#endif

测试程序1

测试开机次数

void testlfs(void)
{
    lfs_t lfs;
    lfs_file_t file;
    // mount the filesystem
    int err = lfs_mount(&lfs, &cfg);

    // reformat if we can't mount the filesystem
    // this should only happen on the first boot
    if (err)
    {
        lfs_format(&lfs, &cfg);
        lfs_mount(&lfs, &cfg);
    }

    // read current count
    uint32_t boot_count = 0;
    lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
    lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));

    // update boot count
    boot_count += 1;
    lfs_file_rewind(&lfs, &file);
    lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));

    // remember the storage is not updated until the file is closed successfully
    lfs_file_close(&lfs, &file);

    // release any resources we were using
    lfs_unmount(&lfs);

    // print the boot count
    printf("boot_count: %d\n", boot_count);
}

测试函数2

测试文件各种读写和文件夹操作

int test2(void)
{
    lfs_t lfs;
    lfs_file_t file;
    lfs_dir_t dir;
    struct lfs_info info;
    int err;
    err = lfs_mount(&lfs, &cfg); // 第一步要挂载文件系统
    if (err < 0)
    {
        lfs_format(&lfs, &cfg);
        lfs_mount(&lfs, &cfg);
    }
    // 以下操作都为假设操作成功
    // 创建一个名为test的文件向文件中写入"1234"4个字节数据
    lfs_file_open(&lfs, &file, "test", LFS_O_CREAT | LFS_O_RDWR);
    lfs_file_write(&lfs, &file, "1234", 4);
    lfs_file_close(&lfs, &file);

    // 这时虽然打开文件时也使用了LFS_O_CREAT标志但是并不会创建一个新的文件也不会报错,在加入LFS_O_EXCL标志后才会报错
    // LFS_O_RDONLY 标志表示以只读打开文件
    // LFS_O_WRONLY 标志表示以只写打开文件
    // LFS_O_RDWR 标志表示以可读可写打开文件,等价于 LFS_O_RDONLY | LFS_O_WRONLY
    // LFS_O_CREAT 打开文件时如果文件不存在就创建新文件并打开,如果存在将读写指针定位到文件开头打开文件
    // LFS_O_EXCL  打开文件时如果文件不存在就创建新文件并打开,如果存在就报错
    // LFS_O_TRUNC 打开一个已有文件并将文件大小设置为0
    // LFS_O_APPEND 打开一个已有文件并将文件的读写指针设置到文件最后
    lfs_file_open(&lfs, &file, "test", LFS_O_CREAT | LFS_O_RDWR);
    lfs_file_write(&lfs, &file, "abc", 3);
    lfs_file_sync(&lfs, &file); // 这时会见内存中的缓存数据写入到Flash中,这时文件内容为"abc4"
    // LFS_SEEK_SET 用绝对位置设置文件的读写指针(用相对用文件开头的位置设置读写指针)
    // LFS_SEEK_CUR 用相对于当前的位置位置设置读写指针
    // LFS_SEEK_END 用相对用文件末尾的位置设置读写指针
    lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET); // 文件指针返回到文件开头
    lfs_file_write(&lfs, &file, "1", 1);
    lfs_file_sync(&lfs, &file); // 这时文件内容为"1bc4"

    lfs_file_seek(&lfs, &file, 0, LFS_SEEK_END); // 文件指针设置到文件最后
    lfs_file_write(&lfs, &file, "5", 1);
    lfs_file_sync(&lfs, &file); // 这时文件内容为"1bc45"

    // 文件指针设置到相对于当前位置-2,1bc45| --> 1bc|45
    lfs_file_seek(&lfs, &file, -2, LFS_SEEK_CUR);
    lfs_file_write(&lfs, &file, "d", 1);
    lfs_file_sync(&lfs, &file); // 这时文件内容为"1bcd5"
    lfs_file_close(&lfs, &file);

// 对test文件设置一个时间和一个日期的自定义属性,在删除文件时也会删除
#define FILE_TIME_TYPE 1
#define FILE_DATE_TYPE 2
    lfs_setattr(&lfs, "test", FILE_TIME_TYPE, "12:00:00", 8);
    lfs_setattr(&lfs, "test", FILE_DATE_TYPE, "2023-1-1", 8);

    // 在根目录下创建了一个名为abc的目录
    // 在abc目录下创建了一个名为test的文件,当前有两个test文件一个在根目录一个在abc目录中
    lfs_mkdir(&lfs, "abc");
    lfs_dir_open(&lfs, &dir, "abc");
    lfs_file_open(&lfs, &file, "test",LFS_O_CREAT | LFS_O_RDWR);
    lfs_file_close(&lfs, &file);
    lfs_dir_close(&lfs, &dir);

    // 遍历根目录下的内容,会递归遍历根目录下的目录里的内容
    // 同时每个目录都会遍历到一个"."和一个".."的文件夹表示当前文件夹和返回上一个文件夹的路径
    lfs_dir_open(&lfs, &dir, ".");
    while (1)
    {
        err = lfs_dir_read(&lfs, &dir, &info);
        if (err < 0)
            break;
    }
    lfs_dir_close(&lfs, &dir);

    lfs_unmount(&lfs);
}

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

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

相关文章

微软蓝屏事件:网络安全的多维挑战与应对策略

一、引言 1. 事件概述&#xff1a;微软蓝屏事件的影响与范围 微软蓝屏事件&#xff0c;这一近期震动全球科技界的重大事件&#xff0c;起因于一次看似平常的软件更新。美国电脑安全技术公司“众击”发布的更新包中隐藏着一个致命的“缺陷”&#xff0c;这个缺陷如同潜伏的病毒…

goland设置Gin框架中tmpl模板的语法提示的方法

goland设置Gin框架中tmpl模板的语法提示的方法 前言 在Gin中&#xff0c;我们要使用 .tmpl 结尾的模板文件&#xff0c;但是我们在new的时候&#xff0c;发现没有对应的文件&#xff0c;所以它就会被当成普通的文件来进行解析&#xff0c;因此也没有提示&#xff0c;这对我们…

MySQL --- 表的操作

在对表进行操作时&#xff0c;需要先选定操作的表所在的数据库&#xff0c;即先执行 use 数据库名; 一、创建表 create table 表名( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎 ; 说明&#xff1a…

个性化音频生成GPT-SoVits部署使用和API调用

一、训练自己的音色模型步骤 1、准备好要训练的数据&#xff0c;放在Data文件夹中&#xff0c;按照文件模板中的结构进行存放数据 2、双击打开go-webui.bat文件&#xff0c;等待页面跳转 3、页面打开后&#xff0c;开始训练自己的模型 &#xff08;1&#xff09;、人声伴奏分…

Mac文件拷贝到移动硬盘怎么做Mac拷贝之后Win电脑里看不到

在日常使用mac电脑的过程中&#xff0c;我们经常需要将一些重要的文件备份到外部硬盘上&#xff0c;以防止数据丢失或电脑故障。传输文件到硬盘可以通过多种方法实现&#xff0c;比如拖拽或者复制至移动硬盘&#xff0c;但有时也会遇到移动硬盘无法粘贴&#xff0c;或拷贝后无法…

FastAPI(七十五)实战开发《在线课程学习系统》接口开发-- 创建课程

源码见&#xff1a;"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 上次我们分享了&#xff0c;FastAPI&#xff08;七十四&#xff09;实战开发《在线课程学习系统》接口开发-- 删除留言 从本篇文章开始&#xff0c;…

DVWA中命令执行漏洞细说

在攻击中&#xff0c;命令注入是比较常见的方式&#xff0c;今天我们细说在软件开发中如何避免命令执行漏洞 我们通过DVWA中不同的安全等级来细说命令执行漏洞 1、先调整DVWA的安全等级为Lower,调整等级在DVWA Security页面调整 2、在Command Injection页面输入127.0.0.1&…

Gitlab以及分支管理

一、概述 Git 是一个分布式版本控制系统&#xff0c;用于跟踪文件的变化&#xff0c;尤其是源代码的变化。它由 Linus Torvalds 于 2005 年开发&#xff0c;旨在帮助管理大型软件项目的开发过程。 二、Git 的功能特性 Git 是关注于文件数据整体的变化&#xff0c;直接会将文件…

视频去水印免费电脑版 pdf压缩在线免费网页版 pdf压缩在线免费 简单工具软件详细方法步骤分享

消除视频中的恼人水印&#xff0c;是许多视频编辑爱好者的常见需求。在这篇文章中&#xff0c;我们将探讨几种视频去水印的技巧&#xff0c;在数字化时代&#xff0c;视频和图片的传播越来越方便&#xff0c;但随之而来的水印问题也让人头疼。本文将为您详细介绍视频剪辑去水印…

CTF-Web习题:[GXYCTF2019]Ping Ping Ping

题目链接&#xff1a;[GXYCTF2019]Ping Ping Ping 解题思路 访问靶机&#xff0c;得到如下页面&#xff0c;类似于URL参数 尝试用HackBar构造url传输过去看看 发现返回了ping命令的执行结果&#xff0c;可以猜测php脚本命令是ping -c 4 $ip&#xff0c;暂时不知道执行的函数…

JavaScript(15)——操作表单元素属性和自定义属性

操作表单元素属性 表单很多情况&#xff0c;也需要修改属性&#xff0c;比如点击眼睛可以看到密码&#xff0c;本质是把表单类型转换为文本框正常的有属性有取值的&#xff0c;跟其他的标签属性没有任何区别 获取&#xff1a;DOM对象.属性名 设置&#xff1a;DOM对象.属性名…

【OpenCV C++20 学习笔记】操作图片

操作图片 概述图片的导入和保存对导入的图片的操作获取像素值Point类型和图片像素 内存管理和引用计数一些简便操作图片可视化更精确的类型转换 概述 在本专栏的第一篇文章中就介绍了一个用OpenCV处理图片的实例&#xff08;《图片处理基础》&#xff09;&#xff0c;这篇文章…

【LeetCode】141.环形链表、142. 环形链表 II(算法 + 图解)

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;数据结构 &#x1f4da;本系列文章为个人学…

基于PyCharm在Windows系统上远程连接Linux服务器中Docker容器进行Python项目开发与部署

文章目录 摘要项目结构项目开发项目上线参考文章 摘要 本文介绍了如何在Windows 10系统上使用PyCharm专业版2024.1&#xff0c;通过Docker容器在阿里云CentOS 7.9服务器上进行Python项目的开发和生产部署。文章详细阐述了项目结构的搭建、PyCharm的使用技巧、以及如何将开发项…

C#/WinFrom TCP通信+ 网线插拔检测+客服端异常掉线检测

Winfor Tcp通信(服务端) 今天给大家讲一下C# 关于Tcp 通信部分&#xff0c;这一块的教程网上一大堆&#xff0c;不过关于掉网&#xff0c;异常断开连接的这部分到是到是没有多少说明&#xff0c;有方法 不过基本上最多的两种方式&#xff08;1.设置一个超时时间&#xff0c;2.…

Python爬虫技术 第13节 HTML和CSS选择器

在爬虫技术中&#xff0c;解析和提取网页数据是核心部分。HTML 和 CSS 选择器被广泛用于定位网页中的特定元素。下面将详细介绍这些选择器如何在 Python 中使用&#xff0c;特别是在使用像 Beautiful Soup 或 Scrapy 这样的库时。 HTML 选择器 HTML 选择器基于 HTML 元素的属性…

Llama 3.1和xAI超集群加速AI军备竞赛

LLama 3.1 先来看看LLama 3.1 405B的效果&#xff0c;例如输入生成上海印象的四连图&#xff0c;然后一键再生成短视频&#xff0c;整体还是可圈可点。 从下面的各项基准而言&#xff0c;LLama3.1系列在同等量级中均有不俗的表现&#xff0c;尤其是405B已经和闭源的GPT-4o不分…

内网横向:PTHPTKPTT

1.PHT横向 2.PTK横向 3.PTT横向 1.PHT横向&#xff1a; 条件&#xff1a;有管理员的NTLM Hash 并且目标机器开 放445端口 在工作组环境中&#xff1a; Windows Vista 之前的机器&#xff0c;可以使用本地管理员组内用户进行攻击。 WindowsVista 之后的机器&#xff0c;只能是…

【iOS】—— Block总结

Block总结 1. Block的使用规范2. __block修饰符__block修饰符的底层原理 3. Block的类型NSGlobalBlockNSStackBlockNSMallocBlock 4. Block的实现及本质初始化部分调用部分本质 5. Block的捕获与内存管理捕获变量捕获对象内存管理 6. 循环引用什么是循环引用循环引用解决方法1.…

抓包工具Charles

1、抓包的目的 遇到问题需要进行分析 发现bug需要定位 检查数据传输的安全性 接口测试时&#xff0c;开发给的需求文档不详细 在弱网环境下APP的测试 2、Charles是java语言编写的程序&#xff0c;本质是一个代理服务器&#xff0c;通过拦截服务端和客户端的http请求&#xff0…