文章目录
- IO流
- 字符流
- 字符流原理解析
- flush和close方法
- 文件拷贝代码
- 文件加密解密
- 修改文件中的数据
- 缓冲流
- 字节缓冲流
- 字符缓冲流
- 例题
- 转换流
- 序列化流
- 序列化流/对象操作输出流
- 反序列化流
- 序列化流/反序列化流的细节汇总
- 打印流
- 字节打印流
- 字符打印流
- 解压缩流
- 压缩流
- Commons-io
- 常见方法
- Hutool工具包
- 多线程
- 并发和并行
- 实现方式
- 成员方法
- 生命周期
- 同步代码块
- 同步方法
- Lock锁
- 等待唤醒机制(生产者和消费者)
IO流
字符流
字符流原理解析
- 创建字符输入流对象
底层::联文件,并创建缓冲区(长度为8192的字节数) - 读取数据
底层:
- 判断缓冲区中是否有数据可以读取
- 缓冲区没有数据:就从文件中获取数据,装到缓冲区中,每次尽可能装满缓冲区
如果文件中也没有数据了,返回-1 - 缓冲区有数据:就从缓冲区中读取
空参的read方法:一次读取一个字节,遇到中文一次读多个字节,把字节解码并转成十进制返回
有参的read方法:把读取字节,解码,强转三步合并了,强转之后的字符放到数组中
flush和close方法
成员方法 | 说明 |
---|---|
public void flush() | 将缓冲区中的数据,刷新到本地文件中 |
public void close() | 释放资源/关流 |
文件拷贝代码
public class demo1 {public static void main(String[] args) throws IOException {File src = new File("E:\\文件练习JAVA嘿嘿嘿");File dest = new File("E:\\拷贝后的地址");copydir(src, dest);}private static void copydir(File src, File dest) throws IOException {dest.mkdirs();File[] files = src.listFiles();for(File file : files){if(file.isFile()) {FileInputStream fis = new FileInputStream(file);FileOutputStream fos = new FileOutputStream(new File(dest, file.getName()));byte[] bytes = new byte[1024];int len;while((len = fis.read(bytes)) != -1){fos.write(bytes, 0, len);}fos.close();fis.close();}else {copydir(file, new File(dest, file.getName()));}}}
}
文件加密解密
public class Demo2 {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("C:\\Users\\HP\\Desktop\\111\\哈哈\\4月27日 日报.pdf");FileOutputStream fos = new FileOutputStream("C:\\Users\\HP\\Desktop\\111\\哈哈\\copy_4月27日 日报.pdf");int b;while ((b = fis.read()) != -1) {fos.write(b ^ 2);}fos.close();fis.close();}
}
修改文件中的数据
//1
public class demo1 {public static void main(String[] args) throws IOException {FileReader fr = new FileReader("a.txt");StringBuilder sb = new StringBuilder();int ch;while((ch = fr.read()) != -1) {sb.append((char) ch);}fr.close();System.out.println(sb);String str = sb.toString();String[] arrStr = str.split("-");ArrayList<Integer> list = new ArrayList<>();for(String s : arrStr) {int i = Integer.parseInt(s);list.add(i);}Collections.sort(list);System.out.println(list);FileWriter fw = new FileWriter("a.txt");for (int i = 0; i < list.size(); i++) {if(i == list.size() - 1)fw.write(list.get(i) + "");elsefw.write(list.get(i) + "-");}fw.close();}
}//2
public class demo1 {public static void main(String[] args) throws IOException {FileReader fr = new FileReader("a.txt");StringBuilder sb = new StringBuilder();int ch;while((ch = fr.read()) != -1) {sb.append((char) ch);}fr.close();Integer[] array = Arrays.stream(sb.toString().split("-")).map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s);}}).sorted().toArray(new IntFunction<Integer[]>() {@Overridepublic Integer[] apply(int value) {return new Integer[value];}});FileWriter fw = new FileWriter("a.txt");for (int i = 0; i < array.length; i++) {if(i == array.length - 1)fw.write(array[i] + "");elsefw.write(array[i] + "-");}fw.close();}
}
缓冲流
字节缓冲流
方法名称 | 说明 |
---|---|
public BufferedInputStream(InputStream is) | 把基本流包装成高级流,提高读取数据的性能 |
public BufferedOutputStream(OutputStream os) | 把基本流包装成高级流,提高写出数据的性能 |
原理 :底层自带了长度为8192的缓冲区提高性能
字符缓冲流
方法名称 | 说明 |
---|---|
public BufferedReader(Reader r) | 把基本流变成高级流 |
public BufferedWriter(Writer w) | 把基本流变成高级流 |
方法名称 | 说明 |
---|---|
public String readLine() | 读取一行数据,如果没有数据可读了,会返回 null |
public void newLine() | 跨平台的换行 |
例题
只能使用三次的程序
public class demo2 {public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new FileReader("a.txt"));String s = br.readLine();br.close();System.out.println(s);int count = Integer.parseInt(s);count++;if(count <= 3){System.out.println("第" + count + "免费试用~~~");}else {System.out.println("使用结束啦,请充值会员继续使用~~");}BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));bw.write(count + "");bw.close();}
}
转换流
作用1 :指定字符集读写
作用2 :字节流想要使用字符流中的方法
public class demo3 {public static void main(String[] args) throws IOException {FileReader fr = new FileReader("a.txt", Charset.forName("UTF-8"));int ch;while((ch = fr.read())!= -1)System.out.print((char)ch);fr.close();}
}
字符转换输入流:InputStreamReader
字符转换输出流:0utputStreamWriter
序列化流
可以把Java中的对象写到本地文件中
序列化流/对象操作输出流
一、构造方法
构造方法 | 说明 |
---|---|
public ObjectOutputStream(0utputStream out) | 把基本流包装成高级流 |
二、成员方法
成员方法 | 说明 |
---|---|
public final void writeObject(Object obj) | 把对象序列化(写出)到文件中去 |
public class demo4 {public static void main(String[] args) throws IOException {Student stu = new Student("xiaodu", 18);ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));oos.writeObject(stu);oos.close();}
}
使用对象输出流将对象保存到文件时会出现NotserializableException
异常
解决方案:需要让Javabean类实现Serializable接口
public class Student implements Serializable{}
反序列化流
一、构造方法
public ObjectInputStream(InputStream in) | 把基本流变成高级流 |
---|
二、成员方法
public Object readObject() | 把序列化到本地文件中的对象,读取到程序中来。 |
---|
public class demo5 {public static void main(String[] args) throws IOException, ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));Object o = ois.readObject();System.out.println(o);}
}
transient
关键字:该关键字标记的成员不参与序列化过程。
序列化流/反序列化流的细节汇总
- 使用序列化流将对象写到文件时,需要让Javabean类实现Serializable接口。
否则,会出现NotSerializableException异常 - 序列化流写到文件中的数据是不能修改的,一旦修改就无法再次读回来了
打印流
分类:打印流一般是指:PrintStream,PrintWriter两个类
特点1:打印流只操作文件目的地,不操作数据源
特点2:特有的写出方法可以实现,数据原样写出
例如: 打印:97------文件中:97
打印:true------文件中:true
特点3:特有的写出方法,可以实现自动刷新,自动换行
打印一次数据 = 写出 + 换行 + 刷新
字节打印流
一、构造方法
构造方法 | 说明 |
---|---|
public PrintStream(OutputStream/File/String) | 关联字节输出流/文件/文件路径 |
public PrintStream(String fileName, Charset charset) | 指定字符编码 |
public PrintStream(OutputStream out, boolean autoFlush) | 自动刷新 |
public PrintStream(OutputStream out, boolean autoFlush, String encoding) | 指定字符编码且自动刷新 |
二、成员方法
成员方法 | 说明 |
---|---|
public void write(int b) | 常规方法: 将指定的字节写出 |
public void println(Xxx xx) | 特有方法 : 打印任意数据,自动刷新,自动换行 |
public void print(Xxx xx) | 特有方法 : 打印任意数据,不换行 |
public void printf(String format, Object... args) | 特有方法 : 带有占位符的打印语句,不换行 |
public class demo6 {public static void main(String[] args) throws FileNotFoundException {PrintStream ps = new PrintStream(new FileOutputStream("a.txt"), true, Charset.forName("UTF-8"));ps.println(97);ps.println(true);ps.println("嘿嘿嘿");ps.close();}
}
字符打印流
一、构造方法
构造方法 | 说明 |
---|---|
public PrintWriter(Writer/File/String) | 关联字节输出流/文件/文件路径 |
public PrintWriter(String fileName, Charset charset) | 指定字符编码 |
public PrintWriter(Writer w, boolean autoFlush) | 自动刷新 |
public PrintWriter(OutputStream out, boolean autoFlush, Charset charset) | 指定字符编码且自动刷新 |
二、成员方法
成员方法 | 说明 |
---|---|
public void write(...) | 常规方法: 规则跟之前一样,写出字节或者字符串 |
public void println(Xxx xx) | 特有方法: 打印任意类型的数据并且换行 |
public void print(Xxx xx) | 特有方法: 打印任意类型的数据,不换行 |
public void printf(String format, Object... args) | 特有方法: 带有占位符的打印语句 |
public class demo7 {public static void main(String[] args) throws IOException {PrintWriter pw = new PrintWriter(new FileWriter("a.txt"), true);pw.println(111);pw.println(222);pw.println(333);pw.close();}
}
解压缩流
public class demo8 {public static void main(String[] args) throws IOException {File src = new File("E:\\aaa.zip");File dest = new File("E:\\");unzip(src, dest);}private static void unzip(File src, File dest) throws IOException {ZipInputStream zip = new ZipInputStream(new FileInputStream(src));ZipEntry entry;while((entry = zip.getNextEntry()) != null) {if(entry.isDirectory()) {File file = new File(dest, entry.toString());file.mkdirs();}else {FileOutputStream fos = new FileOutputStream(new File(dest, entry.toString()));int b;while ((b = zip.read()) != -1) {fos.write(b);}fos.close();zip.closeEntry();}}zip.close();}
}
压缩流
public class ZipStreamDemo2 {public static void main(String[] args) throws IOException {// 源文件路径File src =new File("E:\\TestCode\\testFile.txt");// 压缩文件存储路径File dest =new File("E:\\TestCode");// 执行文件压缩toZip(src, dest);}private static void toZip(File src, File dest) throws IOException {// 创建压缩输出流ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest, "testFile.zip")));// 创建一个zip文件实体并添加到压缩流中ZipEntry entry = new ZipEntry(src.getName());zos.putNextEntry(entry);// 读取源文件并写入压缩流FileInputStream fis = new FileInputStream(src);int b;while ((b = fis.read()) != -1) {zos.write(b);}// 关闭当前zip条目并压缩流zos.closeEntry();zos.close();}
}
Commons-io
Commons-io是apache开源基金组织提供的一组有关io操作的开源工具包
- 在项目中创建一个文件夹:lib
- 将jar包复制粘贴到lib文件夹
- 右键点击jar包,选择 Add as Library ->点击OK
- 在类中导包使用
常见方法
FileUtils类(文件/文件夹相关) | 说明 |
---|---|
static void copyFile(File srcFile, File destFile) | 复制文件 |
static void copyDirectory(File srcDir, File destDir) | 复制文件夹 |
static void copyDirectoryToDirectory(File srcDir, File destDir) | 复制文件夹 |
static void deleteDirectory(File directory) | 删除文件夹 |
static void cleanDirectory(File directory) | 清空文件夹 |
static String readFileToString(File file, Charset encoding) | 读取文件中的数据变成成字符串 |
static void write(File file, CharSequence data, String encoding) | 写出数据 |
构造方法 | 说明 |
---|---|
public static int copy(InputStream input, OutputStream output) | 复制文件 |
public static int copyLarge(Reader input, Writer output) | 复制大文件 |
public static String readLines(Reader input) | 读取数据 |
public static void write(String data, OutputStream output) | 写出数据 |
Hutool工具包
相关类 | 说明 |
---|---|
IoUtil | 流操作工具类 |
FileUtil | 文件读写和操作的工具类 |
FileTypeUtil | 文件类型判断工具类 |
WatchMonitor | 目录、文件监听 |
ClassPathResource | 针对ClassPath中资源的访问封装 |
FileReader | 封装文件读取 |
FileWriter | 封装文件写入 |
多线程
线程是操作系统能够进行运算调度的最小单位。它被包含在进程
之中,是进程中的实际运作单位。
并发和并行
并发:在同一时刻,有多个指令在单个CPU上交替执行
并行:在同一时刻,有多个指令在多个CPU上同时执行
实现方式
-
继承Thread类的方式进行实现
- 自己定义一个类继承Thread
- 重写run方法
- 创建子类的对象,并启动线程
public class demo1 {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("现成1");t2.setName("现成2");t1.start();t2.start();} } public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + "HelloWorld");}} }
-
实现Runnable接口的方式进行实现
- 自己定义一个类实现Runnable接口
- 重写里面的run方法
- 创建自己的类的对象
- 创建一个Thread类的对象,并开启线程
public class demo1 {public static void main(String[] args) {myRun mr = new myRun();Thread t1 = new Thread(mr);Thread t2 = new Thread(mr);t1.setName("现成1");t2.setName("现成2");t1.start();t2.start();} } public class myRun implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "HelloWorld");}} }
-
利用Callable接口和Future接口方式实现(可以获取到多线程运行的结果)
-
创建一个类MyCallable实现Callable接口
-
重写ca11(是有返回值的,表示多线程运行的结果)
-
创建MyCa1lable的对象)表示多线程要执行的任务)
-
创建FutureTask的对象(作用管理多线程运行的结果)
-
创建Thread类的对象,并启动(表示线程)
public class demo1 {public static void main(String[] args) throws ExecutionException, InterruptedException {MyCallable mc = new MyCallable();FutureTask<Integer> ft = new FutureTask<>(mc);Thread t1 = new Thread(ft);t1.start();Integer result = ft.get();System.out.println(result);} } public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 0; i <= 100; i++) {sum += i;}return sum;} }
对比
-
成员方法
方法名称 | 说明 |
---|---|
String getName() | 返回此线程的名称 |
void setName(String name) | 设置线程的名字(构造方法也可以设置名字) |
static Thread currentThread() | 获取当前线程的对象 |
static void sleep(long time) | 让线程休眠指定的时间,单位为毫秒 |
setPriority(int newPriority) | 设置线程的优先级 |
final int getPriority() | 获取线程的优先级 |
final void setDaemon(boolean on) | 设置为守护线程 |
public static void yield() | 出让线程/礼让线程 |
public static void join() | 插入线程/插队线程 |
生命周期
同步代码块
格式
synchronized{}
特点1:锁默认打开,有一个线程进去了,锁自动关闭
特点2:里面的代码全部执行完毕,线程出来,锁自动打开
public class MyThread1 extends Thread{static int ticket = 0;static Object obj = new Object();@Overridepublic void run() {while (true) {synchronized (obj) {if(ticket < 100) {try {Thread.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}ticket++;System.out.println(getName() + "正在卖" + ticket + "票!!!");} else {break;}}}}
}
public class demo1 {public static void main(String[] args) {MyThread1 t1 = new MyThread1();MyThread1 t2 = new MyThread1();t1.setName("111");t2.setName("222");t1.start();t2.start();}
}
同步方法
就是把synchronized关键字加到方法上
特点1: 同步方法是锁住方法里面所有的代码
特点2:锁对象不能自己指定
非静态:this
静态:当前类的字节码文件对象
public class MyRunnable implements Runnable{int ticket = 0;@Overridepublic void run() {while (true) {try {if(method())break;} catch (InterruptedException e) {throw new RuntimeException(e);}}}private synchronized boolean method() throws InterruptedException {if(ticket == 100)return true;else{Thread.sleep(10);ticket++;System.out.println(Thread.currentThread().getName() + "@" + ticket);}return false;}
}
public class demo1 {public static void main(String[] args) {MyRunnable mr = new MyRunnable();Thread t1 = new Thread(mr);Thread t2 = new Thread(mr);Thread t3 = new Thread(mr);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}
Lock锁
虽然我们可以理解同步代码块和同步方法的锁对象问题
但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁
为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作
Lock中提供了获得锁和释放锁的方法
void lock()
:获得锁
void unlock()
:释放锁
手动上锁、手动释放锁
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
ReentrantLock的构造方法
ReentrantLock()
:创建一个ReentrantLock的实例
public class LockExample { private Lock lock = new ReentrantLock(); public void doSomething() { lock.lock(); // 手动上锁 try { // 访问或修改共享资源的代码 // ... } finally { lock.unlock(); // 手动释放锁,确保在finally块中执行以处理异常 } }
}
等待唤醒机制(生产者和消费者)
方法名称 | 说明 |
---|---|
void wait() | 当前线程等待,直到被其他线程唤醒 |
void notify() | 随机唤醒单个线程 |
void notifyAll() | 唤醒所有线程 |
已经到底啦!!