自学Java基础知识第十七天
作者:互联网
day17
1. 字符流
1.1 字节流读取中文文本乱码问题
问题 : 使用字节输入流读取带有中文文本文件, 一边读取文件, 一边查看文件内容, 导致了按照字节进行读取, 有可能将中文拆分开, 将拆分的不完成的字节转换成字符, 于是发生数据读取出来乱码问题
解决 : 当读取带有中文文本时, 不要使用字节流, 使用字符流进行操作即可
代码
package com.ujiuye.io; import java.io.FileInputStream; import java.io.IOException; public class Demo01_字节流读取中文文本乱码 { public static void main(String[] args) throws IOException{ FileInputStream fis = new FileInputStream("中文.txt"); byte[] b = new byte[2]; int len; while((len = fis.read(b)) != -1) { System.out.print(new String(b,0,len)); } fis.close(); } } |
读取结果: ?? 就是出现了乱码
源文件内容:
1.2 字符流读取文件原理
所有文件都是由字节组成, 字符流也是从文件中读取出字节数据, 字符流先从文件中读取出一个字节, 验证这个字节结果是否为一个正数, 证明读到了一个符号, 一个字母,一个数字, 那么直接参考编码表将字节转换成字符数据获取到;
平台默认的编码表GBK中, 中文占有2个字节, 中文第一个字节为负数, 如果从文件中读取到第一个字节为负数, 证明读取到中文, 动态向下读取出一个字节, 将两个字节的结果转换成整数, 参考编码表转换成一个字符
1.3 字符输入流
- Reader : 字符输入流的抽象父类, 来自于java.io包, 抽象类不能实例化对象, 需要子类, FileReader
- FileReader 构造方法:
FileReader(String path) : 将path所表示的文件路径分装在字符输入流中, 以后输入流重文件中读取出字符数据
FileReader(File path) : 将path所表示的文件路径分装在字符输入流中, 以后输入流重文件中读取出字符数据
- 读取文件方法:
1) read() : 表示每次从文件中读取出一个字符, 返回值类型int, 如果返回-1,证明文件读取完毕
2) read(char[] ch) : 表示每次最多从文件中读取出ch.length个字符, 将读取到的字符结果放置到参数数组ch中, 返回值类型int, 表示每次读取到的字符个数, 如果返回-1, 证明文件读取完毕
3) close() : 关闭资源
代码
package com.ujiuye.io; import java.io.FileReader; import java.io.IOException; public class Demo02_字符流读取中文文本 { public static void main(String[] args) throws IOException{ // 1. 创建出字符输入流, 绑定一个数据源 FileReader fr = new FileReader("中文.txt"); // 2. 使用单个字符读取文件 // len表示每次读取到的字符对应的整数结果 /*int len; while((len = fr.read()) != -1) { System.out.print((char)len); }*/ // len表示每次读取到的字符个数 int len; char[] ch = new char[2]; while((len = fr.read(ch)) != -1) { System.out.print(new String(ch,0,len)); } // 3. 关闭资源 fr.close(); } } |
1.4 字符输出流
- Writer : 是字符输出流抽象父类, 来自于java.io包, 抽象类不能实例化对象, 需要一个子类FileWriter
- FileWriter构造方法:
FileWriter(String path) : 将path所表示的文件路径封装在字符输出流中, 以后输出流向文件中写入字符数据
FileWriter(File path) : 将path所表示的文件路径封装在字符输出流中, 以后输出流向文件中写入字符数据
- 向文件中写入字符方法:
代码
package com.ujiuye.io; import java.io.FileWriter; import java.io.IOException; public class Demo03_字符流向文件中写入数据 { public static void main(String[] args) throws IOException{ // 1. 创建出一个字符输出流, 绑定一个数据目的 FileWriter fw = new FileWriter("字符流.txt"); // 2. 写入单个字符 fw.write('a'); // 写入字符数组 char[] ch = {'A','1','?','家'}; fw.write(ch); // 写入字符数组的一部分 fw.write(ch, 1, 2); // 写入字符串 String s = "今天星期二"; fw.write(s); // 写入字符串的一部分 fw.write(s, 0, 1);
fw.close(); } } |
1.5 flush和close方法
FileWriter 类型, 底层带有默认的数组缓冲, 使用数组的方式写入文件, 如此提高文件读写效能, 如果向文件中写入内容时, 没有刷新数据,也没有关闭资源, 数据都存储在底层数组缓冲区中, 没有同步到文件中, 因此文件中有可能缺失数据
- flush() : 表示刷新, 将IO流资源存在于底层缓冲区中的数据, 同步到文件中, 流资源刷新之后, 还能继续使用
- close() : 表示关闭资源, 在关闭资源之前, 先调用flush功能, 将底层缓冲区中的数据, 同步到文件中, 然后在关闭资源, 关闭流资源之后, 流不能在继续使用
代码
package com.ujiuye.io; import java.io.FileWriter; import java.io.IOException; public class Demo03_字符流向文件中写入数据 { public static void main(String[] args) throws IOException{ // 1. 创建出一个字符输出流, 绑定一个数据目的 FileWriter fw = new FileWriter("字符流.txt"); //aA1?家1?今天星期二今 // 2. 写入单个字符 fw.write('a'); // 写入字符数组 char[] ch = {'A','1','?','家'}; fw.write(ch); // 写入字符数组的一部分 fw.write(ch, 1, 2); fw.flush(); // 写入字符串 String s = "今天星期二"; fw.write(s); // 写入字符串的一部分 fw.write(s, 0, 1);
fw.close(); } } |
1.6 字符流复制
- 字符流可以复制纯文本文件(纯文本文件表示可以使用txt记事本打开文件, 打开后可以读懂),但是不建议使用, 效率低
- 字符流不能复制非纯文本文件, 例如 : 图片,视频...一律不能复制
- 字节流和字符流使用:
a : 如果做文件的复制, 建议字节流完成复制
b : 如果有带有中文文件, 边读边看, 防止中文乱码问题出现, 使用字符流进行文件内容的读取
复制文本文件代码
package com.ujiuye.io; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class Demo04_字符流可以复制文本 { public static void main(String[] args) throws IOException{ FileReader fis = new FileReader("字符流.txt"); FileWriter fw = new FileWriter("字符流copy.txt");
int len; while((len = fis.read()) != -1) { fw.write(len); }
fw.close(); fis.close(); } } |
复制非纯文本文件代码
package com.ujiuye.io; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class Demo05_字符流不能复制非纯文本 { public static void main(String[] args) throws IOException{ FileReader fis = new FileReader("D:\\0810Java系统班\\day16\\图解\\IO流向.png"); FileWriter fw = new FileWriter("D:\\IO流向.png");
int len; while((len = fis.read()) != -1) { fw.write(len); } fw.close(); fis.close(); } } |
1.7 字符高效缓冲流
- BufferedReader : 是Reader一个子类, 表示高效字符输入流, 包装类, 将一个普通字符输入流包装成一个高效字符输入流
BufferedReader(Reader in)
a : 高效原理, 当创建出一个BufferedReader 字符输入流时, 类型底层会默认创建出一个大小为8192的字符数组, 每次通过read方法读取内存时, 最多读取出8192个字符, 将读取到字符放置到底层数组缓冲区中, 以后读取从数组中读取内容, 减少与磁盘文件交互次数,从而提高读写性能. 一直到文件读取完毕为止
- BufferedWriter : 是Writer一个子类, 表示高效字符输出流, 保证类, 将一个普通字符输出流包装成一个高效字符输出流
BufferedWriter(Writer in)
b :高效原理, 当创建出一个BufferedWriter字符输出流时, 类型底层默认创建出一个大小为8192的字符数组, 向文件中写入字符内容, 先写入到底层数组缓冲中, 当将8192写满,或者通过flush以及close方法, 可以将缓冲区中的数据同步到文件中, 减少与磁盘文件交互次数,从而提高读写效能
代码
package com.ujiuye.io; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class Demo06_字符高效缓冲流 { public static void main(String[] args) throws IOException{ // 1. 定义出高效缓冲流 BufferedReader br = new BufferedReader( new FileReader("Info.txt")); BufferedWriter bw = new BufferedWriter( new FileWriter("InfoCopy.txt"));
// 2. 边读边写 // len表示每次读取到的字符转换成整数结果 int len; while((len = br.read()) != -1) { bw.write(len); } bw.close(); br.close(); } } |
1.8 字符高效缓冲流特有方法
- BufferedReader: 有特有方法
readLine() : 每次可以从文件中读取出一行数据, 读取出数据返回值类型String, 当读取到null, 证明文件读取完毕
- BufferedWriter: 有特有功能
newLine() : 表示向文件中写入一次回车换行
代码
package com.ujiuye.io; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; public class Demo07_字符高效流特有功能 { public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader( new FileReader("产品.txt")); BufferedWriter bw = new BufferedWriter( new FileWriter("产品Copy.txt")); String s; while((s = br.readLine()) != null) { String[] arr = s.split("\\|"); System.out.println(Arrays.toString(arr));
bw.write(s); bw.newLine(); } br.close(); bw.close(); } } |
2. 转换流
- 编码表:
1) UTF-8 : 万国码表, 一个数字, 一个字母,一个符号, 占有1个字节, 一个中文占有3个字节
2) GBK : 国标码, 兼容ASCII和所有中文文字, 一个数字, 一个字母,一个符号, 占有1个字节, 一个中文占有2个字节
- 修改文件的编码集, 在Eclipse中
选中指定文件, 鼠标右键-->properties(属性)
- 转换流解决不同编码集乱码问题:
1) InputStreamReader(InputStream in,String charsetName) : 字节流向字符桥梁
a : 通过参数in从文件中读取出字节数据
b : 通过参数charsetName给定的编码表, 将字节通过对应编码表转换成字符
2) OutputStreamWriter(OutputStream out, String charsetName) : 字符流向字节桥梁
a : 将字符通过给定的charsetName编码表, 转换成对应字节
b : 使用out将字节数据写入到文件中
注意 : 使用转换流资源时,给出的编码集一定要与文件中实际编码保持一致
代码
package com.ujiuye.io; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; public class Demo09_转换流解决不同编码集文件读写 { public static void main(String[] args) throws IOException{ // 1. 创建出一个转换流(输入流) InputStreamReader isr = new InputStreamReader( new FileInputStream("UTF-8.txt"),"UTF-8"); OutputStreamWriter osw = new OutputStreamWriter( new FileOutputStream("GBK.txt"), "GBK");
int len; while((len = isr.read()) != -1) { osw.write(len); } osw.close(); isr.close(); } } |
3. IO流异常标准处理方式(扩展)
在JDK1.7版本, 针对IO流异常处理有了新的异常处理语法结构:
try(
需要创建IO流资源;
){
IO流使用过程;
}catch(异常类型 对象名){
异常处理方式;
}
1) 将需要创建的IO流资源创建过程,写入到try小括号中
2) try大阔号中, 写入可能发生问题的代码
3) catch一样匹配和捕获异常
4) 优势 : 当流资源使用完毕, 不需要手动关闭流资源, try小括号自动再留资源 使用完毕之后进行关闭, 并且处理关闭流资源异常情况
最标准的异常处理方式
package com.ujiuye.io; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class Demo10_IO流中异常标准处理方式 { public static void main(String[] args) { // 1. 为了在finally中关闭资源, 变量可以使用, 提高变量的作用范围 FileInputStream fis = null; FileOutputStream fos = null;
try { fis = new FileInputStream("a\\中文.txt"); fos = new FileOutputStream("中文Cpoy.txt"); int len; while((len = fis.read()) != -1) { fos.write(len); }
} catch (FileNotFoundException e) {// ctrl + t : 能查看当前类型继承关系 e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { // 2. 关闭资源也会有异常,需要try...catch处理, 但因为fos初始值为null, // 因此, 验证fos不为null再关闭流资源 if(fos != null) { fos.close(); } } catch (IOException e) { e.printStackTrace(); }finally { try { // 3. fis关闭资源的方式与fos一致 if(fis != null) { fis.close(); } } catch (IOException e) { e.printStackTrace(); } } } } } |
JDK7异常新语法处理IO流异常
package com.ujiuye.io; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Demo11_IO流异常全新处理方式 { public static void main(String[] args) { try( FileInputStream fis = new FileInputStream("a\\中文.txt"); FileOutputStream fos = new FileOutputStream("中文Cpoy.txt"); ){ int len; while((len = fis.read()) != -1) { fos.write(len); } }catch(IOException e) { e.printStackTrace(); } System.out.println("over代码结束"); } } |
4. 多线程
4.1 多线程相关概念
- 程序 : 就是一系列数据和逻辑结合体, 例如 : 写出java文件,就是程序
- 进程 : 正在内存中运行程序,称为进程
- 线程 : 进程(正在运行代码), 需要有代码的独立执行通道, 代码独立执行通道称为线程,
线程代码执行通道彼此之间互相独立, 如果程序中有多条代码的执行通道, 称程序为多线程程序
举例 : 例如main方法, 本身就是一条线程, 表示程序中代码的执行通道, 代码经过执行通道才能运行
- 并行 : 如果多个程序要求同时执行, 硬件完全支持, 效果让多个程序同时都在执行
举例 : 饭店, 客户, 点了5道菜, 5个厨师每一个人炒一道菜, 5道菜同时在炒
- 并发 : 如果多个程序要求同时执行, 硬件设备不能完全支持, CPU处理程序速度非常快, 于是CPU在多个程序之间来回切换执行, 感受不到CPU对于程序切换执行
举例 : 饭店, 客户, 点了5道菜, 1个厨师, 架起5口锅, 1个厨师在5个菜中来回翻炒
注意 : 多线程代码运行都是并发执行机制, 因此多线程程序执行具有很大随机性
4.2 多线程的实现方式
4.2.1 继承Thread类
- Thread线程类介绍:
- 多线程实现步骤:
1) 自定义出一个类, 让Thread类作为自定义类的直接父类, 于是自定义类也是线程类
2) 重写Thread父类中的run方法功能, 将需要独立运行的代码设计在run方法中
3) 创建一个自定义线程类对象
4) 调用从父类Thread继承来的start方法功能:
start() :
a : 开启一个线程
b : 在独立线程通道中, JVM虚拟机主动调用运行当前线程的run方法
注意 : 每一个线程类对象只能开启一次
代码
package com.ujiuye.thread; // 1. 自定义出一个类, 让Thread类作为自定义类的直接父类, 于是自定义类也是线程类 public class MyThread extends Thread { // 2. 重写Thread父类中的run方法功能, 将需要独立运行的代码设计在run方法中 @Override public void run() { for(int i = 1; i <= 10; i++) { System.out.println("run---" + i); } } } |
package com.ujiuye.thread; public class TestThread { // main方法本身就是一条线程 public static void main(String[] args) { // 除了main方法线程之外, 还需要额外的, 独立线程通道 // 3. 创建一个自定义线程类对象 MyThread my = new MyThread(); // 4. 调用从父类Thread继承来的start方法功能,开启线程 my.start();
// main方法线程中,设计出循环 for(int i = 1; i <= 10; i++) { System.out.println("main---" + i); } } } |
4.2.2 实现Runnable接口
- Thread线程类就是Runnable的一个实现类, Runnable是实现一个线程接口
- 多线程实现步骤:
1) 自定义出一个类, 实现Runnable接口
2) 重写Runnable中唯一方法功能run , 将需要独立运行代码设计到run中
3) 创建出一个自定义线程类对象
4) 借助Thread线程类中构造方法, 将Runnable实现类对象封装在一个Thread类型中
Thread(Runnable run) ;
5) 借助封装后的Thread类型对象,调用start方法功能:
a : 开启一个独立线程通道
b : 运行就是构造参数中的Runnable实现类中的run方法功能
代码
package com.ujiuye.thread; public class MyThread2 implements Runnable { @Override public void run() { for(int i = 1; i <= 10; i++) { System.out.println("runnable---"+i); } } } |
package com.ujiuye.thread; public class TestThread { // main方法本身就是一条线程 public static void main(String[] args) { // 除了main方法线程之外, 还需要额外的, 独立线程通道 // 3. 创建一个自定义线程类对象 MyThread my = new MyThread(); // 4. 调用从父类Thread继承来的start方法功能,开启线程 my.start();
// 使用Runnable接口实现方法创建出一个独立线程通道 MyThread2 my2 = new MyThread2(); Thread t = new Thread(my2); t.start();
// main方法线程中,设计出循环 for(int i = 1; i <= 10; i++) { System.out.println("main---" + i); } } } |
4.2.3 匿名内部类实现多线程
- 匿名内部类 : 本质就是一个类的子类或者是一个接口的实现类
- new 父类或者父接口(){
// 大括号就表示父类的子类或者接口实现类, 实现过程
}
整体语法结构, 相当于创建出一个匿名内部类对象
代码
package com.ujiuye.thread; public class Demo02_匿名内部类对象实现多线程 { // 1. main方法本身就是一个线程 public static void main(String[] args) { // 定义出一个线程 new Thread() { @Override public void run() { for(int i = 1; i <= 100; i++) { System.out.println("线程1---"+ i); } } }.start();
new Thread() { @Override public void run() { for(int i = 1; i <= 50; i++) { System.out.println("线程2---"+ i); } } }.start();
new Thread() { @Override public void run() { for(int i = 1; i <= 10; i++) { System.out.println("线程3---"+ i); } } }.start();
for(int i = 1; i <= 10; i++) { System.out.println("main---" + i); } } } |
标签:字符,java,new,基础知识,io,import,Java,第十七,public 来源: https://www.cnblogs.com/masterhxh/p/13629010.html