Java中IO类扫盲篇
文章目录
- 一、简介
- 二、字节流与字符流
- 1. 字节流(InputStream、OutputStream)介绍与用法
- 2. 字符流(Reader、Writer)介绍与用法
- 三、文件操作与目录遍历
- 1. File类的基本使用
- 2. 目录遍历与递归操作
- 四、序列化与反序列化
- 1. 序列化与反序列化概念和作用
- 2. 实现Serializable接口的对象序列化
- 3. 自定义序列化与反序列化
- 五、NIO与异步IO
- 1. NIO概述及与传统IO的区别
- 2. 缓冲区(Buffer)的使用
- 3. 通道(Channel)的基本使用
- 4. 选择器(Selector)的使用
一、简介
-
Java IO概述:
Java的IO(输入/输出)是用于处理与外部设备、文件和网络资源之间数据传输的机制。它提供了一套丰富的类和方法,用于读取和写入数据,并提供了灵活的处理方式。 -
IO模型和IO流的概念:
IO模型是指描述程序与外部设备进行数据交换的方式,主要有阻塞IO模型和非阻塞IO模型。阻塞IO模型是指程序在进行IO操作时会阻塞等待返回结果,而非阻塞IO模型是指程序在进行IO操作时可以继续执行其他任务,不需要等待返回结果。
IO流是Java中用来处理输入和输出的抽象概念。它将数据的输入和输出视为连续的数据流,通过流的方式进行读取和写入操作。Java中的IO流分为字节流和字符流两种类型,分别对应处理字节数据和字符数据。
- Java IO类库的分类和用途:
Java的IO类库可以分为两个大类:字节流和字符流。
- 字节流:以字节为单位进行读写操作,主要包括InputStream和OutputStream两个类,用于处理二进制数据,例如图片、视频等。
- 字符流:以字符为单位进行读写操作,主要包括Reader和Writer两个类,用于处理文本数据,例如文本文件等。
除了字节流和字符流,Java的IO类库还提供了许多其他类和接口,用于处理特定类型的数据或提供更高级别的功能,例如处理文件、网络通信等。
总结起来,Java的IO类库提供了丰富的工具和方法来进行各种输入和输出操作,能够满足不同场景下的需求。
二、字节流与字符流
1. 字节流(InputStream、OutputStream)介绍与用法
// 1.1 输入字节流的基本使用(FileInputStream、ByteArrayInputStream等)// 使用FileInputStream读取文件内容
try (InputStream inputStream = new FileInputStream("file.txt")) {int data;while ((data = inputStream.read()) != -1) {// 处理读取到的字节数据System.out.print((char) data);}
} catch (IOException e) {e.printStackTrace();
}// 1.2 输出字节流的基本使用(FileOutputStream、ByteArrayOutputStream等)// 使用FileOutputStream写入数据到文件
try (OutputStream outputStream = new FileOutputStream("file.txt")) {String data = "Hello, World!";outputStream.write(data.getBytes());
} catch (IOException e) {e.printStackTrace();
}// 1.3 使用缓冲字节流提高IO性能(BufferedInputStream、BufferedOutputStream等)// 使用BufferedInputStream读取文件内容
try (InputStream inputStream = new BufferedInputStream(new FileInputStream("file.txt"))) {int data;while ((data = inputStream.read()) != -1) {// 处理读取到的字节数据System.out.print((char) data);}
} catch (IOException e) {e.printStackTrace();
}// 使用BufferedOutputStream写入数据到文件
try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream("file.txt"))) {String data = "Hello, World!";outputStream.write(data.getBytes());
} catch (IOException e) {e.printStackTrace();
}
2. 字符流(Reader、Writer)介绍与用法
// 2.1 输入字符流的基本使用(FileReader、StringReader等)// 使用FileReader读取文件内容
try (Reader reader = new FileReader("file.txt")) {int data;while ((data = reader.read()) != -1) {// 处理读取到的字符数据System.out.print((char) data);}
} catch (IOException e) {e.printStackTrace();
}// 2.2 输出字符流的基本使用(FileWriter、StringWriter等)// 使用FileWriter写入数据到文件
try (Writer writer = new FileWriter("file.txt")) {String data = "Hello, World!";writer.write(data);
} catch (IOException e) {e.printStackTrace();
}// 2.3 使用缓冲字符流提高IO性能(BufferedReader、BufferedWriter等)// 使用BufferedReader读取文件内容
try (Reader reader = new BufferedReader(new FileReader("file.txt"))) {int data;while ((data = reader.read()) != -1) {// 处理读取到的字符数据System.out.print((char) data);}
} catch (IOException e) {e.printStackTrace();
}// 使用BufferedWriter写入数据到文件
try (Writer writer = new BufferedWriter(new FileWriter("file.txt"))) {String data = "Hello, World!";writer.write(data);
} catch (IOException e) {e.printStackTrace();
}
三、文件操作与目录遍历
1. File类的基本使用
// 1.1 创建、删除和重命名文件
File file = new File("file.txt");try {// 创建文件if (file.createNewFile()) {System.out.println("文件创建成功");}// 删除文件if (file.delete()) {System.out.println("文件删除成功");}// 重命名文件File newFile = new File("newFile.txt");if (file.renameTo(newFile)) {System.out.println("文件重命名成功");}
} catch (IOException e) {e.printStackTrace();
}// 1.2 获取文件信息(大小、路径、修改时间等)
File file = new File("file.txt");System.out.println("文件大小:" + file.length() + "字节");
System.out.println("文件路径:" + file.getAbsolutePath());
System.out.println("最后修改时间:" + new Date(file.lastModified()));// 1.3 文件遍历与过滤
File dir = new File("directory");// 遍历文件夹下的所有文件和子文件夹
for (File file : dir.listFiles()) {if (file.isFile()) {System.out.println("文件:" + file.getName());} else if (file.isDirectory()) {System.out.println("文件夹:" + file.getName());}
}
2. 目录遍历与递归操作
// 2.1 递归遍历目录下的文件
public static void listFiles(File directory) {File[] files = directory.listFiles();if (files != null) {for (File file : files) {if (file.isFile()) {System.out.println("文件:" + file.getName());} else if (file.isDirectory()) {System.out.println("文件夹:" + file.getName());listFiles(file);}}}
}// 调用递归遍历目录
listFiles(new File("directory"));// 2.2 搜索指定类型的文件
public static void searchFiles(File directory, String extension) {File[] files = directory.listFiles();if (files != null) {for (File file : files) {if (file.isFile() && file.getName().endsWith(extension)) {System.out.println("符合条件的文件:" + file.getName());} else if (file.isDirectory()) {searchFiles(file, extension);}}}
}// 调用搜索指定类型的文件
searchFiles(new File("directory"), ".txt");// 2.3 统计目录大小
public static long calculateDirectorySize(File directory) {long size = 0;File[] files = directory.listFiles();if (files != null) {for (File file : files) {if (file.isFile()) {size += file.length();} else if (file.isDirectory()) {size += calculateDirectorySize(file);}}}return size;
}// 获取目录大小
long size = calculateDirectorySize(new File("directory"));
System.out.println("目录大小:" + size + "字节");
四、序列化与反序列化
1. 序列化与反序列化概念和作用
序列化是将对象转换为字节序列的过程,用于对象的持久化或网络传输。反序列化是将字节序列转换回对象的过程。
2. 实现Serializable接口的对象序列化
// 2.1 序列化对象到文件
try (OutputStream outputStream = new FileOutputStream("object.ser")) {ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);MyObject myObject = new MyObject();objectOutputStream.writeObject(myObject);System.out.println("对象序列化成功");
} catch (IOException e) {e.printStackTrace();
}// 2.2 从文件反序列化对象
try (InputStream inputStream = new FileInputStream("object.ser")) {ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);MyObject myObject = (MyObject) objectInputStream.readObject();System.out.println("对象反序列化成功");
} catch (IOException | ClassNotFoundException e) {e.printStackTrace();
}// 2.3 序列化对象到字节数组
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);MyObject myObject = new MyObject();objectOutputStream.writeObject(myObject);byte[] bytes = byteArrayOutputStream.toByteArray();System.out.println("对象序列化成功,字节数组长度:" + bytes.length);
} catch (IOException e) {e.printStackTrace();
}
3. 自定义序列化与反序列化
// 3.1 实现Externalizable接口
public class MyObject implements Externalizable {private String data;// 必须提供默认构造方法public MyObject() {}// 实现writeExternal方法,手动控制序列化字段@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeObject(data);}// 实现readExternal方法,手动控制反序列化字段@Overridepublic void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {data = (String) in.readObject();}
}// 3.2 控制序列化的过程(writeObject、readObject方法)
public class MyObject implements Serializable {private String data;private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();// 手动调用其他操作}private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();// 手动调用其他操作}
}// 3.3 解决序列化版本兼容性问题
public class MyObject implements Serializable {private static final long serialVersionUID = 1L;...
}
五、NIO与异步IO
1. NIO概述及与传统IO的区别
NIO(New I/O)是Java提供的一种基于通道和缓冲区的IO模型,相比传统的IO模型,NIO具有更高的效率和灵活性。
2. 缓冲区(Buffer)的使用
// 2.1 ByteBuffer、CharBuffer等缓冲区类型
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
CharBuffer charBuffer = CharBuffer.allocate(1024);// 2.2 缓冲区的读写操作
byteBuffer.put((byte) 'H');
byteBuffer.put((byte) 'e');
byteBuffer.put((byte) 'l');
byteBuffer.put((byte) 'l');
byteBuffer.put((byte) 'o');
byteBuffer.flip();while (byteBuffer.hasRemaining()) {System.out.print((char) byteBuffer.get());
}
3. 通道(Channel)的基本使用
// 3.1 文件Channel的读写操作
try (RandomAccessFile file = new RandomAccessFile("file.txt", "rw");FileChannel channel = file.getChannel()) {ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = channel.read(buffer);while (bytesRead != -1) {buffer.flip();while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}buffer.clear();bytesRead = channel.read(buffer);}
} catch (IOException e) {e.printStackTrace();
}// 3.2 Socket Channel和Server Socket Channel的使用
try (SocketChannel socketChannel = SocketChannel.open()) {socketChannel.connect(new InetSocketAddress("example.com", 80));if (socketChannel.isConnected()) {System.out.println("连接成功");ByteBuffer buffer = ByteBuffer.allocate(1024);socketChannel.read(buffer);buffer.flip();while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}}
} catch (IOException e) {e.printStackTrace();
}
4. 选择器(Selector)的使用
选择器(Selector)是Java NIO(New IO)中的一个重要组件,用于实现非阻塞IO操作。它可以通过单个线程处理多个通道(Channel),从而提高系统的IO处理效率。
下面是使用选择器的基本步骤:
-
创建选择器:使用
Selector.open()
方法创建一个Selector对象。Selector selector = Selector.open();
-
注册通道:将需要监听IO事件的通道注册到选择器上。通道可以是一些可读、可写或可接受连接的网络通道,例如
SocketChannel
、ServerSocketChannel
等。channel.configureBlocking(false); // 设置通道为非阻塞模式 SelectionKey key = channel.register(selector, interestOps);
其中,
interestOps
参数表示对该通道感兴趣的事件类型,包括SelectionKey.OP_READ
(可读事件)、SelectionKey.OP_WRITE
(可写事件)、SelectionKey.OP_ACCEPT
(可接受连接事件)等。 -
选择就绪通道:使用
selector.select()
方法来选择已经准备好进行IO操作的通道。该方法会阻塞直到至少有一个通道准备好,或者超时时间到达。int readyChannels = selector.select();
-
处理就绪通道:使用
selector.selectedKeys()
方法获取选择器中已经就绪的键集合,然后遍历处理每个键对应的通道和事件。Set<SelectionKey> selectedKeys = selector.selectedKeys(); for (SelectionKey key : selectedKeys) {if (key.isReadable()) {// 处理可读事件} else if (key.isWritable()) {// 处理可写事件} else if (key.isAcceptable()) {// 处理可接受连接事件}// 其他事件处理... }
-
取消选择键:在处理完通道后,一般需要将其对应的选择键取消,防止重复处理。
key.cancel();
-
关闭选择器:使用
selector.close()
方法关闭选择器,释放资源。selector.close();
使用选择器可以实现单个线程管理多个通道,提高了系统的IO处理效率。它适用于需要同时处理多个IO操作、提高系统吞吐量的场景,例如网络编程中的服务器端。
// 4.1 注册通道到选择器
try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();Selector selector = Selector.open()) {serverSocketChannel.bind(new InetSocketAddress(8080));serverSocketChannel.configureBlocking(false);serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {selector.select();Set<SelectionKey> selectedKeys = selector.selectedKeys();for (SelectionKey key : selectedKeys) {if (key.isAcceptable()) {// 处理接收事件ServerSocketChannel channel = (ServerSocketChannel) key.channel();SocketChannel socketChannel = channel.accept();// ...} else if (key.isReadable()) {// 处理读取事件SocketChannel channel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = channel.read(buffer);// ...}selectedKeys.remove(key);}}
} catch (IOException e) {e.printStackTrace();
}// 4.2 监听通道事件
try (DatagramChannel datagramChannel = DatagramChannel.open();Selector selector = Selector.open()) {datagramChannel.bind(new InetSocketAddress(8080));datagramChannel.configureBlocking(false);datagramChannel.register(selector, SelectionKey.OP_READ);while (true) {selector.select();Set<SelectionKey> selectedKeys = selector.selectedKeys();for (SelectionKey key : selectedKeys) {if (key.isReadable()) {// 处理读取事件DatagramChannel channel = (DatagramChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);SocketAddress sender = channel.receive(buffer);// ...}selectedKeys.remove(key);}}
} catch (IOException e) {e.printStackTrace();
}// 4.3 多路复用(IO多路复用)
try (Selector selector = Selector.open()) {SocketChannel channel1 = SocketChannel.open(new InetSocketAddress("example.com", 80));SocketChannel channel2 = SocketChannel.open(new InetSocketAddress("example.org", 80));channel1.configureBlocking(false);channel2.configureBlocking(false);channel1.register(selector, SelectionKey.OP_READ);channel2.register(selector, SelectionKey.OP_READ);while (true) {selector.select();Set<SelectionKey> selectedKeys = selector.selectedKeys();for (SelectionKey key : selectedKeys) {if (key.isReadable()) {// 处理读取事件SocketChannel channel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);channel.read(buffer);// ...}}}
} catch (IOException e) {e.printStackTrace();
}
简介:本文介绍了Java中的IO类库,包括字节流、字符流的基本使用,文件操作与目录遍历,序列化与反序列化,以及NIO与异步IO的概念与使用。通过学习本文,读者能够掌握Java IO类的基本用法和核心概念,并且理解NIO的特点和优势。
相关文章:

Java中IO类扫盲篇
文章目录 一、简介二、字节流与字符流1. 字节流(InputStream、OutputStream)介绍与用法2. 字符流(Reader、Writer)介绍与用法 三、文件操作与目录遍历1. File类的基本使用2. 目录遍历与递归操作 四、序列化与反序列化1. 序列化与反…...

中秋国庆双节将至,企业如何进行软文推广?
节点营销是每个企业都会面临的课题,中秋国庆双节将至,这两个节日不仅是人们消费的高峰期,也是各大企业通过节日营销提高品牌知名度和美誉度的最佳时机,节点营销的方式之一就是软文推广,那么企业应该如何利用双节来进行…...

SpringMvc--CRUD
目录 一.什么是SpringMvc--CRUD 二.前期准备 公共页面跳转(专门用来处理页面跳转) 三.ssm之CRUD后端实现 配置pom.xml 双击mybatis-generator:generate自动生成mapper 编写generatorConfig.xml 项目结构 编写PagerAspect切面类 编写hpjyBiz接口类 编写hpjyBizImpl接…...

数据库去重(MYSQL和ORACLE)
一、数据库中的去重操作(删除数据库中重复记录的SQL语句)主要有三种方法 (1)、rowid方法 (2)、group by 方法 (3)、distinct方法 1、用rowid方法 根据Oracle带的rowid属性&#…...

微服务-kubernetes安装
文章目录 一、前言二、kubernetes2.1、Kubernetes (K8S) 是什么2.1.1、主要特性:2.2.2、传统部署方式:2.2.3、虚拟机部署2.2.4容器部署2.2.5什么时候需要 Kubernetes2.2.6、Kubernetes 集群架构 三、kubernetes安装3.1、主节点需要组件3.1.1、设置对应主…...

stm32f103zet6移植标准库的sdio驱动
sdio移植 st官网给的标准库有给一个用于st出的评估板的sdio外设实现,但一是文件结构有点复杂,二是相比于国内正点原子和野火的板子也有点不同,因此还是需要移植下才能使用。当然也可以直接使用正点原子或野火提供的实例,但为了熟…...

为什么vector容器的begin()既可以被iterator 也可以被const_iterator指向?
答:vector容器中的begin()是函数接口,它作为函数,被重载了。 typedef T* iterator; typedef const T* const_iterator; iterator begin();//括号中有隐含形参*this; const_iterator begin() const;//形参为…...

uniapp里textarea多行文本输入限制数量
uniapp里textarea多行文本域实现输入计数 <template><view class"inputs"><textarea class"text1" maxlength50 placeholder请输入... input"sumfontnum"></textarea><text class"text2">{{fontNum}}/…...

真香:Alibaba开源GitHub星标100K微服务架构全彩进阶手册
前言: 微服务架构作为一种高效灵活的应用架构,正在成为企业级应用开发的主流选择。在众多的微服务架构指南中,阿里巴巴开源的GitHub微服务架构全彩进阶手册备受瞩目,其100star更是证明了其在开发者社区中的重要地位。 这本手册汇…...

Mysql--事务
事务 开始之前,让我们先想一个场景,有的时候,为了完成某个工作,需要完成多种sql操作 比如转账 再比如下单 第一步 我的账户余额减少 第二步 商品的库存要减少 第三步 订单表中要新增一项 事务的本质,就是为了把多个操…...

【算法题】小红书2023秋招提前批算法真题解析
文章目录 题目来源T1:5900: 【DP】小红书2023秋招提前批-连续子数组最大和5801: 【二分查找】小红书2023秋招提前批-精华帖子解法1——排序滑动窗口解法2——前缀和 二分查找 5000: 【模拟】小红书2023秋招提前批-小红的数组构造解法——数学 5300: 【哈希表】小红…...

序列到序列学习(seq2seq)
permute(1,0,2),将batch_size 放在中间state 最后一个时刻,每个层的输出...

基于Java+SpringBoot+Vue摄影分享网站的设计与实现 前后端分离【Java毕业设计·文档报告·代码讲解·安装调试】
🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…...

接口测试系列 —— POSTMAN的简单使用
postman的基本使用 概述 我相信对于postman的介绍,网上一搜肯定很多很多。下面我就不打算跟大家普及postman了。只看应该怎么用postman进行接口测试。好了,下面咱们直接进入正文吧。 环境 postman之前是作为chrome插件形式存在的。后面变成了独立的应…...

一个帮各位填秋招表格省一点事的浏览器插件
最近应该很多和我一样的双非鼠鼠在秋招等面试,而且处于海投阶段,为了不忘记投了哪些公司,可以用这样一个表格来记录: 其中有些字段,比如状态、投递时间、查看进度的网址其实可以不手动输入,所以搞个插件来…...

react16之前diff算法的理解和总结
此篇文章所讨论的是 React 16 以前的 Diff 算法。而 React 16 启用了全新的架构 Fiber,相应的 Diff 算法也有所改变,本片不详细讨论Fiber。 fiber架构是为了支持react进行可中断渲染,降低卡顿,提升流畅度。 react16之前的版本&…...

JavaEE初阶(1)(冯诺依曼体系、CPU、CPU基本原理、如何衡量CPU的好坏?指令、操作系统、操作系统“内核”)
目录 冯诺依曼体系(Von Neumann Architecture) CPU CPU基本原理: 如何衡量CPU的好坏? 1、主频(时钟速度): 2、核心数: 指令 操作系统 操作系统“内核” 冯诺依曼体系&#x…...

记录在yapi上传接口的问题
sorry ,upload api error cause:请求参数 data.path 不应少于 1 个字符 自己在写的代码中使用到了DeleteMapping DeleteMapping("/deleteCart/{skuId}")public Result deleteCart(PathVariable Long skuId,HttpServletRequest request){报上面的错误,原因…...

DevOps管理软件生命周期
整体的软件开发流程 PLAN:开发团队根据客户的目标制定开发计划 CODE:根据PLAN开始编码过程,需要将不同版本的代码存储在一个库中。GIT,SVN BUILD:编码完成后,需要将代码构建并且运行。MAVEN TEST:成功构建…...

快速解决 adb server version doesn‘t match this client
这个问题是由于电脑上安装了多个版本的adb工具,客户端和服务端的版本不一致,无法正常通信导致。最快的解决方法就是将Android SDK中adb复制到系统目录下。 操作步骤如下: 1. 查看adb版本和路径 执行adb version,如下࿰…...

【更新至2022年】2000-2022年全国31省市以2000年为基期的实际GDP、名义GDP、GDP平减指数数据(含原始数据+计算过程+计算结果)
2000-2022年31省市名义GDP 实际GDP GDP平减指数 1、时间:2000-2022 2、范围:31省市 3、来源:GJ统计J和统计NJ 4、指标:名义GDP、地区生产总值指数(上年100)、实际GDP(以2000年为基期&#x…...

【LeetCode】剑指 Offer <二刷>(5)
目录 题目:剑指 Offer 10- II. 青蛙跳台阶问题 - 力扣(LeetCode) 题目的接口: 解题思路: 代码: 过啦!!! 题目:剑指 Offer 11. 旋转数组的最小数字 - 力…...

rtsp 拉流 gb28181 收流 经AI 算法 再生成 rtsp server (一)
1、 rtsp 工具 1 vlc 必备工具 2 wireshark 必备工具 3 自己制作的工具 player 使用tcp 拉流,不自己写的话,使用ffmpeg 去写一个播放器就行 4 live555 编译好live555, 将live555的参数修改以下,主要是缓存大小 文章使用c 来写一…...

Jmeter系列-环境部署、详细介绍、安装目录介绍(1)
环境部署 官网下载Jmeter http://jmeter.apache.org/下载最新版本的 JMeter,解压文件到任意目录 安装JDK,配置Java环境 1、下载(注意选择操作系统对应的位数32/64) 官网 :http://www.oracle.com 2、安装࿰…...

更换 yum 阿里源 - 手把手教你怎么配置,在也不需要求别人了 - 看懂一个就相当于看懂了其他的linux系统
更换阿里源 我的是centos8 当然 centos7 也可以换 后面有更详细的怎么配 ,再也不用求别人怎么弄了 最直接的方式 直接复制 执行 centos7 curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo或者 wget -O /etc/yum.repos.…...

966SEO扫地僧站群·万能HTML模板[V1.9.1]
扫地僧站群万能HTML模板是一款站点管理软件,其主要特点是可以将原始的html模板放入程序中,无需编写任何标签,程序会全自动替换处理,从而快速构建出一个完整的网站,这种模式相对于传统的网站建设方式更加快速、简单,同时可以大幅度降低网站建设的成本和难度.服务器及域名量的配置…...

angular:html2canvas对ion-avatar节点渲染不正确
问题: 如题 解决办法: 简单实现头像遮罩 <div class"ion-avatar" style"width: 40px; height: 40px; border-radius: 50%; overflow: hidden"><img src"" alt""/> </div><style>.ion-…...

使用dockerfile文件部署Python+PyWebIO项目
1、安装docker 教程详见之前的内容。https://blog.csdn.net/weixin_44691253/category_12101661.html 2、打包好Python项目 之前的文章中有提到我编写测试工具使用的框架:PythonRequestsPyWebIO框架详解,编写测试工具提高团队测试效率 打包项目时&am…...

【web开发】5.Mysql及python代码执行数据库操作
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、MYSQL二、MySQL管理查看已有数据库创建数据库删除数据库进入数据库创建表删除表展示表的行列插入数据查看表中的数据删除数据修改数据 三、python代码执行数据库…...

Android学习之路(13) Handler详解
1. 简介 Handler是一套 Android 消息传递机制,主要用于线程间通信。 用最简单的话描述: handler其实就是主线程在起了一个子线程,子线程运行并生成Message,Looper获取message并传递给Handler,Handler逐个获取子线程中的Message.…...