文章目录
文件流
IO(input、output)是java重要的核心之一,其中读写操作分为两种:字节流和 字符流
什么是流
流是一个抽象的概念。流式数据很有特点,如我们的自来水一样,未打开水龙头时一滴水都没有,一旦打开,水就源源不断的喷涌而出,直到我们关闭水龙头。
当Java程序需要获取外部的数据时,数据来源可以是文件,内存或者网络等,java就把它们定义为流式数据。同样,当程序需要输出数据到目的地时也一样会开启一个流,数据目的地也可以是文件、内存或者网络等。流的高度抽象后,使我们可以用统一的api来操作文件、内存、网络等,方式统一,代码变的简单。
Java中流分为两种:字节流和字符流,那它们有什么区别呢?
字节流是最基本的,主要用在处理二进制数据,它是按字节来处理的,但实际项目开发中很多的数据是文本类型,于是java又提出了字符流的概念,并且引入Buffer缓存概念,提高读写性能。
简单的说,一般字节流针对二进制文件,字符流针对文本文件。
1.读写txt文件
文件write
- 先新建文件流 FileOuputStream() (FOS)
- 再新建编码转换流OutputStreamWriter (OSW),与文件流相接写文件
读文件read
- 先新建文件输入流(FIS) FileInputStream
- 再新建转换流(ISR),与文件流相接, InputStreamReader
- 再新建BR,与转换流相接BufferedReader
- 读取文本文件的经典组合(套餐)
- BR–ISR–FIS—file
- FIS: 读取文件
- ISR: 编码转换
- BR: 按行读取 readLine()
- in.close();关闭流
package javase.base.file;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import org.junit.Test;
public class TestTxtFile {
@Test
public void write() throws IOException {
File file = new File("d:/javase.txt");
BufferedWriter bw =
new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(file), "utf-8"));
String msg = "java培优班,实现你高薪就业梦想!";
try {
bw.write(msg);
} catch (IOException e) {
e.printStackTrace();
} finally {
bw.close();
}
}
@Test
public void read() throws IOException{
File file = new File("d:/javase.txt");
BufferedReader br =
new BufferedReader(
new InputStreamReader(
new FileInputStream(file), "utf-8"));
String line = "";
while((line = br.readLine()) != null) {
System.out.println( line );
}
br.close();
}
}
读写属性文件jdbc.properties
1.写文件
- jdbc.properties文件
properties文件一般用来作为程序的配置文件,例如,连接数据库时,需要知道数据库服务器的地址,用户名,密码等…
这些连接信息,可以存储在properties配置文件中,便于修改维护java提供了专门的工具,来读写这种格式的数据
java.util.Properteis 类, 继承 HashTable,本质是一个哈希表,提供了线程的文件读写方法: load(), store(),HashTable是旧版本的哈希表,现在已经废弃,用HashMap代替. 它是线程安全的,安全效率低
2.读文件 - 得到Test3.class类文件的存放目录路径Test3.class.getResource("/").getPath()
- “jdbc.properties”;
- ISR–FIS–path, 需要用转换流,把UTF-8转成Unicode
package test.file;
import java.io.FileInputStream;
import java.util.Properties;
import org.junit.jupiter.api.Test;
//属性文件操作
public class PropertiesFile {
@Test //读取文件
public void load() throws Exception {
/*
* 开发步骤:
* 1、获取当前类所在的目录
* 2、创建属性对象Properties
* 3、读取当前类根目录下的资源目录下的属性文件
* 4、读取属性文件内容
* 5、关闭流
* 6、打印全部内容
* 7、获取单个属性
*/
//获取当前类所在目录
String dir = PropertiesFile.class.getResource("/").getPath();
Properties prop = new Properties(); //创建属性文件对象
//创建输入文件流对象
FileInputStream is = new FileInputStream( dir + "/resources/jdbc.properties");
prop.load(is); //调用load方法进行文件内容的读取
is.close(); //流必须关闭
System.out.println(prop);
//读取某个值
String s = prop.getProperty("jdbc.username");
System.out.println(s);
}
}
读取结果:
{jdbc.url=jdbc:mysql://127.0.0.1:3306/yhmisdb?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true, phone=10086, jdbc.username=root, jdbc.driver=com.mysql.jdbc.Driver, jdbc.password=root}
root
解析xml文件
1.用DOM4J解析xml
2.模拟Mybatis框架解析XML
- *) 如何读取xml文件
- Document doc = new SAXReader().read(文件);
- *) 如何获取xml的根元素(顶层元素)
- Element root = doc.getRootElement();
- *) 如何从一个元素来获取它的下层元素
- List list = root.elements(“bean”);
- *) 如何从一个元素获取它的属性数据
- List list = e.attributes();
- *) 如何获得元素内包含的文本
- String s = e.getText();
- *) 获取下层元素
- e.elements()
- e.element(“元素名”)
- *) 获取下层元素内的文本
- e.elementText(“元素名”)
- *) 直接获取属性的值
- e.attributeValue(“id”)
简单点,好做练习
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.yhmis.mapper.OrderMapper">
<!-- 查询所有 -->
<select id="list" resultType="Order">
SELECT * FROM tb_order
</select>
<!-- 删除某条记录 -->
<delete id="delete" parameterType="int">
DELETE FROM tb_order WHERE id=#{id}
</delete>
</mapper>
解析要求:
根据传入的namespace.id找到对应的标签,然后解析出其SQL语句
package a01;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class Test5MybatisXml {
private static Map<String, String> map = new HashMap<String, String>();
public void configuration() throws Exception {
String path = getClass().getResource("/OrderMapper.xml").getPath();
//读取解析xml文件,再获得xml的根元素,即<mapper>元素
Element root = new SAXReader().read(path).getRootElement();
//获得namespace属性的值
String ns = root.attributeValue("namespace");
//获取根元素下一层的所有元素列表
List<Element> elements = root.elements();
//遍历元素列表
for (Element e : elements) {
String name = e.getName();//元素名称
String id = e.attributeValue("id");//id属性的值
String sql = e.getText().trim();//内部包含的文本,即sql语句
map.put(name+":"+ns+"."+id, sql);//数据放入map
}
}
public static void main(String[] args) throws Exception {
Test5MybatisXml t = new Test5MybatisXml();
t.configuration();
for(Entry<String, String> e:map.entrySet()) {
String k = e.getKey();
String v = e.getValue();
System.out.println(k+"="+v);
}
}
}
执行结果:
select:cn.yhmis.mapper.OrderMapper.list=SELECT * FROM tb_order
delete:cn.yhmis.mapper.OrderMapper.delete=DELETE FROM tb_order WHERE id=#{id}
JSON
json对象和java对象互相转换
非阻塞IO(NIO)
传统的 IO 大致可以分为4种类型:
- InputStream、OutputStream 基于字节操作的 IO
- Writer、Reader 基于字符操作的 IO
- File 基于磁盘操作的 IO
- Socket 基于网络操作的 IO
java.net 下提供的 Scoket 很多时候人们也把它归为 同步阻塞 IO,因为网络通讯同样是 IO 行为。
阻塞IO(BIO)
BIO读取过程:共三次复制拷贝过程
- jvm堆执行fileInputStream.read()请求操作系统,然后操作系统请求磁盘。
- 从磁盘中读取到数据,然后写到操作系统缓冲区中。
- 将数据从操作系统缓冲区放到jvm进程缓冲区(按字节流读取,即一个一个字节byte读取数据)。
- jvm将jvm进程中缓冲区东西拷贝到jvm堆内存中(应用部署位置)。
BIO、NIO、AIO的区别
NIO非阻塞IO与BIO的区别有如下两点
1.相对于bio的一个一个byte传,nio是以channel形式读取buffer缓冲区,然后以块数据传输
2.nio减少了复制过程
直接把磁盘映射到JVM进程的虚拟地址空间,放置对应到页表上。
图2,3,4的步骤都没有,取而代之,直接放到jvm的堆中,你说能不快吗?
BIO、NIO、AIO的区别
阻塞IO,BIO 就是传统的 java.io 包,它是基于流模型实现的,交互的方式是同步、阻塞方式,也就是说在读入输入流或者输出流时,在读写动作完成之前,线程会一直阻塞在那里,它们之间的调用时可靠的线性顺序。它的有点就是代码比较简单、直观;缺点就是 IO 的效率和扩展性很低,容易成为应用性能瓶颈。
非阻塞IO,NIO 是 Java 1.4 引入的 java.nio 包,提供了 Channel、Selector、Buffer 等新的抽象,可以构建多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层高性能的数据操作方式。
异步IO,AIO 是 Java 1.7 之后引入的包,是 NIO 的升级版本,提供了异步非堵塞的 IO 操作方式,所以人们叫它 AIO(Asynchronous IO),异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。但目前还不够成熟,应用不多。