Easyexcel(2-文件读取)

news2024/11/23 18:41:01

相关文章链接:

  1. Easyexcel(1-注解使用)
  2. Easyexcel(2-文件读取)

同步读取

读取单个Sheet

  1. 通过sheet方法指定对应的Sheet名称或下标读取文件信息
  2. 通过doReadSync方法实现同步读取
@Data
public class UserExcel {

    @ExcelIgnore
    private Integer id;

    @ExcelProperty(index = 0, value = "姓名")
    private String name;

    @ExcelProperty(index = 1, value = "年龄")
    private Integer age;

    @DateTimeFormat(value = "yyyy-MM-dd")
    @ExcelProperty(index = 2, value = "出生日期")
    private Date birthday;
}
@RestController
public class Test02Controller {

    /**
     * 上传单个文件, 同步读取excel文件
     */
    @PostMapping("/uploadFile")
    public void uploadFile(MultipartFile file) {
        try (InputStream in = file.getInputStream()) {
            List<UserExcel> userExcelList = EasyExcel.read(in)
                    // 读取第一个sheet
                    .sheet(0)
                    // 如果第一行才是标题,第二行是数据,从第二行开始读取
                    .headRowNumber(1)
                    .head(UserExcel.class)
                    .doReadSync();
            for (UserExcel userExcel : userExcelList) {
                System.out.println(userExcel);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

读取多个Sheet(同一个对象)

使用doReadAllSync方法读取所有Sheet,适用于每个Sheet的对象都一致的情况

@PostMapping("/uploadFile2")
public void uploadFile2(MultipartFile file) {
    try (InputStream in = file.getInputStream()) {
        List<UserExcel> userExcelList = EasyExcel.read(in)
                // 如果第一行才是标题,第二行是数据,从第二行开始读取
                .headRowNumber(1)
                .head(UserExcel.class)
                .doReadAllSync();
        for (UserExcel userExcel : userExcelList) {
            System.out.println(userExcel);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

读取多个Sheet(不同对象)

当每个Sheet的对象不一致的情况下,使用doReadAllSync方法无法指定每个Sheet的对象,可以依次读取Sheet进行解析

注意:依次读取sheet会出现重复读取流对象的情况,而一个流对象只能读取一次,重复使用会导致异常

@PostMapping("/uploadFile4")
public void uploadFile4(MultipartFile file) {
    InputStream in = null;
    try {
        in = file.getInputStream();
        List<UserExcel> userExcelList1 = EasyExcel.read(in)
                // 读取第一个sheet
                .sheet(0)
                // 如果第一行才是标题,第二行是数据,从第二行开始读取
                .headRowNumber(1)
                .head(UserExcel.class)
                .doReadSync();

        // 读取剩余的sheet
        in = file.getInputStream();
        List<UserExcel> userExcelList2 = EasyExcel.read(in)
                .sheet(1)
                // 如果第一行才是标题,第二行是数据,从第二行开始读取
                .headRowNumber(1)
                .head(UserExcel.class)
                .doReadSync();

        List<UserExcel> userExcelList = new ArrayList<>();
        userExcelList.addAll(userExcelList1);
        userExcelList.addAll(userExcelList2);
        for (UserExcel userExcel : userExcelList) {
            System.out.println(userExcel);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (in != null) {
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

异步读取

监听器

查看监听器源码,通过实现ReadListener接口或继承AnalysisEventListener类可以自定义读取Sheet监听器

public interface ReadListener<T> extends Listener {
    
    // 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则继续读取下一行
    default void onException(Exception exception, AnalysisContext context) throws Exception {
        throw exception;
    }

	// 获取表头数据
    default void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {}

	// 一行行读取表格内容
    void invoke(T data, AnalysisContext context);

	// 读取条额外信息:批注、超链接、合并单元格信息等
    default void extra(CellExtra extra, AnalysisContext context) {}

   	// 读取完成后的操作
    void doAfterAllAnalysed(AnalysisContext context);

	// 是否还有数据
    default boolean hasNext(AnalysisContext context) {
        return true;
    }
}
public abstract class AnalysisEventListener<T> implements ReadListener<T> {

    // 解析表头数据
    @Override
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
        invokeHeadMap(ConverterUtils.convertToStringMap(headMap, context), context);
    }

    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {}
}

异常处理

ExcelDateConvertException

表示数据转换异常错误,出现该异常时会继续解析文件信息

@Getter
@Setter
@EqualsAndHashCode
public class ExcelDataConvertException extends ExcelRuntimeException {

    private Integer rowIndex;

    private Integer columnIndex;

    private CellData<?> cellData;

    private ExcelContentProperty excelContentProperty;

    public ExcelDataConvertException(Integer rowIndex, Integer columnIndex, CellData<?> cellData,
        ExcelContentProperty excelContentProperty, String message) {
        super(message);
        this.rowIndex = rowIndex;
        this.columnIndex = columnIndex;
        this.cellData = cellData;
        this.excelContentProperty = excelContentProperty;
    }

    public ExcelDataConvertException(Integer rowIndex, Integer columnIndex, CellData<?> cellData,
        ExcelContentProperty excelContentProperty, String message, Throwable cause) {
        super(message, cause);
        this.rowIndex = rowIndex;
        this.columnIndex = columnIndex;
        this.cellData = cellData;
        this.excelContentProperty = excelContentProperty;
    }
}

ExcelAnalysisStopException

非数据转换异常错误,在onexcetpion中抛出该异常后停止解析

public class ExcelAnalysisStopException extends ExcelAnalysisException {

    public ExcelAnalysisStopException() {}

    public ExcelAnalysisStopException(String message) {
        super(message);
    }

    public ExcelAnalysisStopException(String message, Throwable cause) {
        super(message, cause);
    }

    public ExcelAnalysisStopException(Throwable cause) {
        super(cause);
    }
}

读取单个Sheet(不指定对象)

读取文件时使用doRead方法进行异步操作,同时指定对应的监听器解析文件数据

Map<Integer, String>中的key表示列号、value表示数据

public class UserExcelListener1 extends AnalysisEventListener<Map<Integer, String>> {
    Logger log = LoggerFactory.getLogger(getClass());

    private List<Map<Integer, String>> userExcelList = new ArrayList<>();

    @Override
    public void invoke(Map<Integer, String> map, AnalysisContext analysisContext) {
        log.info("解析到一条数据:{}", JSON.toJSONString(map));
        userExcelList.add(map);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.info("已解析完所有数据!");
        userExcelList.clear();
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException convertException = (ExcelDataConvertException) exception;
            Integer row = convertException.getRowIndex();
            log.error("第{}行数据转换失败,异常信息:{}", row, exception.getMessage());
        } else {
            log.error("导入其他异常信息:{}", exception.getMessage());
        }
    }

    public List<Map<Integer, String>> getUserExcelList() {
        return userExcelList;
    }

    public void setUserExcelList(List<Map<Integer, String>> userExcelList) {
        this.userExcelList = userExcelList;
    }
}
@PostMapping("/uploadFile1")
public void uploadFile1(MultipartFile file) {
    try (InputStream in = file.getInputStream()) {
        UserExcelListener1 listener = new UserExcelListener1();
        EasyExcel.read(in, listener)
                .sheet(0)
                .headRowNumber(1) // 第一行是标题, 从第二行开始读取
                .doRead();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

读取单个Sheet(指定对象)

public class UserExcelListener extends AnalysisEventListener<UserExcel> {
    Logger log = LoggerFactory.getLogger(getClass());

    private List<UserExcel> userExcelList = new ArrayList<>();

    @Override
    public void invoke(UserExcel userExcel, AnalysisContext analysisContext) {
        log.info("解析到一条数据:{}", JSON.toJSONString(userExcel));
        userExcelList.add(userExcel);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.info("已解析完所有数据!");
        userExcelList.clear();
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException convertException = (ExcelDataConvertException) exception;
            Integer row = convertException.getRowIndex();
            log.error("第{}行数据转换失败,异常信息:{}", row, exception.getMessage());
        } else {
            log.error("导入其他异常信息:{}", exception.getMessage());
        }
    }

    public List<UserExcel> getUserExcelList() {
        return userExcelList;
    }

    public void setUserExcelList(List<UserExcel> userExcelList) {
        this.userExcelList = userExcelList;
    }
}
@PostMapping("/uploadFile5")
public void uploadFile5(MultipartFile file) {
    try (InputStream in = file.getInputStream()) {
        UserExcelListener listener = new UserExcelListener();
        EasyExcel.read(in, UserExcel.class, listener)
                .sheet(0)
                .headRowNumber(1) // 第一行是标题, 从第二行开始读取
                .doRead();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

读取多个Sheet

  1. 获取Sheet的总数,通过循环遍历的方式指定每个Sheet的监听器进行解析
  2. 使用构造器的方式传入Sheet对应的下标,在抛出异常时获取SheetNo和对应的行号,方便进行排查
public class UserExcelListener2 extends AnalysisEventListener<UserExcel> {
    
    Logger log = LoggerFactory.getLogger(getClass());

    private Integer sheetNo;
    
    private List<UserExcel> userExcelList = new ArrayList<>();

    public UserExcelListener2(Integer sheetNo) {
        this.sheetNo = sheetNo;
    }

    @Override
    public void invoke(UserExcel userExcel, AnalysisContext analysisContext) {
        log.info("解析到一条数据:{}", JSON.toJSONString(userExcel));
        userExcelList.add(userExcel);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.info("已解析完所有数据!");
        userExcelList.clear();
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException convertException = (ExcelDataConvertException) exception;
            Integer row = convertException.getRowIndex();
            log.error("sheetNo:{},第{}行数据转换失败,异常信息:{}", sheetNo, row, exception.getMessage());
        } else {
            log.error("导入其他异常信息:{}", exception.getMessage());
        }
    }

    public List<UserExcel> getUserExcelList() {
        return userExcelList;
    }

    public void setUserExcelList(List<UserExcel> userExcelList) {
        this.userExcelList = userExcelList;
    }
}
@PostMapping("/uploadFile6")
public void uploadFile6(MultipartFile file) {
    try (InputStream in = file.getInputStream();
         ExcelReader build = EasyExcel.read(in).build();) {
        List<ReadSheet> readSheets = build.excelExecutor().sheetList();
        for (int i = 0, len = readSheets.size(); i < len; i++) {
            UserExcelListener2 listener = new UserExcelListener2(i);
            ReadSheet sheet = EasyExcel.readSheet(readSheets.get(i).getSheetNo())
                    .head(UserExcel.class)
                    .headRowNumber(1)
                    .registerReadListener(listener)
                    .build();
            build.read(sheet);
        }
        build.finish();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

分批读取(线程池操作)

  1. 使用构造器的方式传入Sheet对应的下标和自定义线程池,使用这种分批处理的方式,避免内存的消耗,加快文件的解析入库
  2. 数据库入库时可以使用MySQL的批量插入语法,同时指定每次插入数据的大小,相较于MyBatisPlus的批量插入方法较快(疑问:在MyBatisPlus的批量插入方法时出现数据部分丢失的情况
/**
 * UserListener 不能被spring管理,要每次读取excel都要new,
 * 然后里面用到spring可以构造方法传进去
 */
public class UserExcelListener3 extends AnalysisEventListener<UserExcel> {

    Logger log = LoggerFactory.getLogger(getClass());

    private static final Integer BATCH_SIZE = 1000;

    private Integer sheetNo;

    private Executor executor;

    private List<UserExcel> userExcelList = new ArrayList<>();


    public UserExcelListener3(Integer sheetNo, Executor executor) {
        this.sheetNo = sheetNo;
        this.executor = executor;
    }

    @Override
    public void invoke(UserExcel userExcel, AnalysisContext analysisContext) {
        log.info("解析到一条数据:{}", JSON.toJSONString(userExcel));
        userExcelList.add(userExcel);
        if (userExcelList.size() >= BATCH_SIZE) {
            List<UserExcel> userExcels = BeanUtil.copyToList(userExcelList, UserExcel.class);
            CompletableFuture.runAsync(() -> {
                // 业务操作
                // saveToDB(userExcels);
            }, executor);
            userExcelList.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.info("已解析完所有数据!");
        if (!userExcelList.isEmpty()) {
            List<UserExcel> userExcels = BeanUtil.copyToList(userExcelList, UserExcel.class);
            CompletableFuture.runAsync(() -> {
                // 业务操作
                // saveToDB(userExcels);
            }, executor);
            userExcelList.clear();
        }
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException convertException = (ExcelDataConvertException) exception;
            Integer row = convertException.getRowIndex();
            log.error("sheetNo:{},第{}行数据转换失败,异常信息:{}", sheetNo, row, exception.getMessage());
        } else {
            log.error("导入其他异常信息:{}", exception.getMessage());
        }
    }
}
@PostMapping("/uploadFile7")
public void uploadFile77(MultipartFile file) {
    try (InputStream in = file.getInputStream();
         ExcelReader build = EasyExcel.read(in).build();) {

        ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 60L,
                TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(1000), new ThreadPoolExecutor.AbortPolicy());
        List<ReadSheet> readSheets = build.excelExecutor().sheetList();
        for (int i = 0, len = readSheets.size(); i < len; i++) {
            UserExcelListener3 listener = new UserExcelListener3(i, executor);
            ReadSheet sheet = EasyExcel.readSheet(readSheets.get(i).getSheetNo())
                    .head(UserExcel.class)
                    .headRowNumber(1)
                    .registerReadListener(listener)
                    .build();
            build.read(sheet);
        }
        build.finish();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

事务操作

当使用监听器读取文件数据,使用分批插入数据的方法时,因为监听器不归Spring管理,所以无法使用Spring的事务注解进行事务的相关操作,怎么保证事务?

可以通过构造器的方式传入事务管理器,手动提交和回滚事务

@Slf4j
public class TestDataListener extends AnalysisEventListener<Test> {
    
    //每隔5条存储数据库,实际使用中可以设置为2500条,然后清理list ,方便内存回收
    private static final int BATCH_COUNT = 5;
    private List<Test> list = new ArrayList<>();

    //事务管理
    private DataSourceTransactionManager dataSourceTransactionManager;
    //事务定义
    private DefaultTransactionDefinition transactionDefinition;
    private TransactionStatus transactionStatus = null;

    private TestService testService;

    public TestDataListener(TestService testService,
                            DataSourceTransactionManager dataSourceTransactionManager,
                            TransactionDefinition transactionDefinition) {
        this.testService = testService;
        this.dataSourceTransactionManager = dataSourceTransactionManager;
        this.transactionDefinition = new DefaultTransactionDefinition(transactionDefinition);
        //设置事务的隔离级别 :未提交读写
        this.transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
        // 手动开启事务
        this.transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
    }

    @Override
    public void invoke(Test data, AnalysisContext context) {
        log.info("解析到一条数据:{}", JSON.toJSONString(data));
        boolean hasCompleted = transactionStatus.isCompleted();
        // 如果事务已经关闭,不执行业务代码
        if (hasCompleted){
            return;
        }
        list.add(data);
        if (list.size() >= BATCH_COUNT) {
            saveData();
            list.clear();
        }
    }

    // 这个方法会在easyexcel读取完文件中所有数据后执行
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        //判断事务是否已被处理,未处理则进行提交事务
        boolean hasCompleted = transactionStatus.isCompleted();
        if (hasCompleted){
            return;
        }
        saveData();
        log.info("所有数据解析完成!");
        if (!hasCompleted){
            //提交事务
            dataSourceTransactionManager.commit(transactionStatus);
            log.info("SensitiveWordListener doAfterAllAnalysed:当前事务已提交");
        }
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        log.info("导入过程中出现异常会进入该方法,重写了父类方法");
        log.info("结束前事务状态:"+  transactionStatus.isCompleted());
        dataSourceTransactionManager.rollback(transactionStatus);
        log.info("结束后事务状态:"+  transactionStatus.isCompleted());
        throw exception;
    }
    
    /**
     * 加上存储数据库
     */
    private void saveData() {
        log.info("{}条数据,开始存储数据库!", list.size());
        if (!CollectionUtils.isEmpty(list)) {
            testService.saveBatch(list);
            System.out.println(list);
        }
        //TODO 这里是测试事务,如有需要可以打开注释
        //int a = 1/0;
        log.info("存储数据库成功!");
    }
}

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

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

相关文章

在 Sui 区块链上创建、部署与测试自定义 move _coin合约的完整教程

系列文章目录&#x1f60a; Task1&#xff1a;hello_move&#x1f340; Task2&#xff1a;move_coin&#x1f340; Task3&#xff1a;move_nft&#x1f340; 目录 系列文章目录&#x1f60a;引言一、更新本地代码1、查看当前项目的远程仓库信息。2、将远程仓库的最新代码同步到…

三层交换机静态路由实验

1、前置知识 2、实验目的 3、实验器材&#xff1a; 3560-23PS交换机2台、主机4台、交叉线1根和直通网线4根。 4、实验规划及拓扑 实验要求&#xff1a; &#xff08;1&#xff09;在交换机A和交换机B上分别划分基于端口的VLAN&#xff1a; 交换机 VLAN 端口成员 交换机…

iOS构建版本以及Hbuilder打iOS的ipa包全流程

目录 Hbuilder打ipa包 打包之前进行应用配置 应用版本号设置 使用广告标识设置 iOS-云打包 下载并转移安装包 使用Transporter提交版本 应用简介 下载应用 账号登录 提交安装包到apple store connect 在apple开发者平台上确认 总结 本篇文章详细的介绍了使用Hbuil…

java学习-集合

为什么有集合&#xff1f; 自动扩容 数组&#xff1a;长度固定&#xff0c;可以存基本数据类型和引用数据类型 集合&#xff1a;长度可变&#xff0c;可以存引用数据类型&#xff0c;基本数据类型的话需要包装类 ArrayList public class studentTest {public static void m…

返回流类型接口的错误信息处理

返回流类型接口的错误信息处理 前言axios拦截器src/utils/request.ts对应接口 前言 返回流类型接口需要在响应成功回调里拦截&#xff0c;且该接口的status始终是200&#xff0c;尽管后端返回的code可能是非2xx&#xff0c;因此返回流类型的接口&#xff0c;其错误信息需要单独…

用宏实现简单的计算器

大家好&#xff0c;那么经过我们前面几期的学习&#xff0c;我们对宏有了一定的了解&#xff0c;那么我们今天就来试试实现一个简单的加减乘除运算。 我们的思路是使用三目操作符来分别进行加减和乘除的运算&#xff0c;然后用if判断来”进入相关的判断体进而来进行计算。当然…

WEB攻防-通用漏洞文件上传js验证mimeuser.ini语言特性

知识点&#xff1a; 1、文件上传-前端验证 2、文件上传-黑白名单 3、文件上传-user.ini妙用 4、文件上传-php语言特性 详细点&#xff1a; 1、检测层面&#xff1a;前端&#xff0c;后端等 2、检测内容&#xff1a;文件头&#xff0c;完整型&#xff0c;二次渲染等 3、检…

《Vue零基础教程》(3)创建第一个应用案例

1 应用实例 参考官方文档 https://cn.vuejs.org/api/application.html#create-app 示例 const {createApp} Vue// 通过createApp创建一个应用实例 const app createApp({/* 选项 */ }) console.log(app) 分析打印结果, 可知 应用实例是一个对象没有_开头的是公开属性/方…

复合瓦片切片集集合数量与性能关系验证

作者&#xff1a;lzzzz Sci瓦片聚合性能分析 需要聚合的图层越多&#xff0c;性能越低&#xff0c;目前测试以每个瓦片仅包含一个矢量面数据为例&#xff1a; sci数量 服务拉起耗时 前端加载&#xff08;单瓦片&#xff09; 100 10s 500ms 1000 5min 3s 10000 1hour …

大数据-231 离线数仓 - DWS 层、ADS 层的创建 Hive 执行脚本

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇开始了&#xff01; 目前开始更新 MyBatis&#xff0c;一起深入浅出&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff0…

摄影:相机控色

摄影&#xff1a;相机控色 白平衡&#xff08;White Balance&#xff09;白平衡的作用&#xff1a; 白平衡的使用环境色温下相机色温下总结 白平衡偏移与包围白平衡包围 影调 白平衡&#xff08;White Balance&#xff09; 人眼看到的白色&#xff1a;会自动适应环境光线。 相…

性能监控利器:Ubuntu 22.04 上的 Zabbix 安装与配置指南

简介 今天我们来聊聊如何在 Ubuntu 22.04 上安装和配置 Zabbix。我们会用到 PostgreSQL 作为数据库后端&#xff0c;Nginx 作为 Web 服务器&#xff0c;并用 Let’s Encrypt SSL 证书来保驾护航。 什么是 Zabbix&#xff1f; Zabbix 是一个开源的网络监控和管理解决方案&…

队列基本实现

模板 int queue[10010]; int hh1,tt0; void push1(int x) {queue[tt]x; } void pop1() {if(hh>tt){cout<<"ERR_CANNOT_POP"<<endl;}else{hh;} } int query1() {if(hh>tt){cout<<"ERR_CANNOT_QUERY"<<endl;}return queue[hh…

【ArcGISPro】使用AI模型提取要素-提取车辆(目标识别)

示例数据下载 栅格数据从网上随便找一个带有车辆的栅格数据 f094a6b1e205cd4d30a2e0f816f0c6af.jpg (1200799) (588ku.com) 添加数据

GitLab|数据迁移

注意&#xff1a;新服务器GitLab版本需和旧版本一致 在旧服务器执行命令进行数据备份 gitlab-rake gitlab:backup:create 备份数据存储在 /var/opt/gitlab/backups/ 将备份数据传输到新服务器的/var/opt/gitlab/backups/下&#xff0c;并修改文件权限&#xff08;下载前和上传…

UE5 5.1.1创建C++项目,显示error C4668和error C4067的解决方法

因为工作要求&#xff0c;没法使用最新 5.5版本的ue5 而是要用ue5.1和5.2版本。 但是我在安装下载了visual studio2022后&#xff0c;使用 ue5.1编辑器 创建C项目&#xff0c;爆出如下错误。 error C4668: ?????__has_feature?????ΪԤ?????꣬???0????…

网络安全概论

一、 网络安全是一个综合性的技术。在Internet这样的环境中&#xff0c;其本身的目的就是为了提供一种开放式的交互环境&#xff0c;但是为了保护一些秘密信息&#xff0c;网络安全成为了在开放网络环境中必要的技术之一。网络安全技术是随着网络技术的进步逐步发展的。 网络安…

51单片机基础01 单片机最小系统

目录 一、什么是51单片机 二、51单片机的引脚介绍 1、VCC GND 2、XTAL1 2 3、RST 4、EA 5、PSEN 6、ALE 7、RXD、TXD 8、INT0、INT1 9、T0、T1 10、MOSI、MISO、SCK 11、WR、RD 12、通用IO P0 13、通用IO P1 14、通用IO P2 三、51单片机的最小系统 1、供电与…

DASCTF 2024 10月 Reverse 完成笔记 附题目

题目链接: https://github.com/Airrcat/long_long/tree/main/DASCTF_2024_10 ezre 查PE 32位无壳 开始分析 看起来很像加壳了 字符串未有暴露信息&#xff0c;但是段中有一个themida 发现是一个壳&#xff0c;直接去找脱壳机 一些脱壳工具&#xff08;Magicmida)是…

JavaScript 中 arguments、类数组与数组的深入解析

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;什么是 arguments 对象2.1 arguments 的定义2.2 arguments 的特性2.3 使用场景 &#x1f4af;深入了解 arguments 的结构3.1 arguments 的内部结构arguments 的关键属性 3.2 类数组…