1.前置知识:字符集
1.1ASCII
-
美国信息交换标准代码,包含了英文、符号等
-
标准ASCII使用1个字节存储一个字符,收尾是0,总共可表示128个字符
1.2GBK
-
GBK(汉字内码扩展规范,国标)
-
包含了2万多个汉字等字符,GBK中一个中文字符编码成2个字节的形式存储
-
GBK兼容了ASCII字符集
-
GBK规定:汉字的第一个字节的第一位必须是1
1.3Unicode
-
Unicode是国际组织指定的,可以容纳世界上所有文字、符号和字符集
-
UTF-32:4个字节表示一个字符
-
UTF-8:
-
采取可变长编码方案,共分为四个长度区:1个字节,2个字节,3个字节,4个字节
-
英文字符、数字等只占1个字节(兼容标准ASCII编码),汉字字符占用3个字节
-
2.前置知识:编码&解码
编码方法 | 说明 |
---|---|
byte[] getBytes() | 使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中 |
byte[] getBytes(String charsetName) | 使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中 |
解码方法 | 说明 |
---|---|
String(byte[] bytes) | 使用平台的默认字符集解码指定的字节数组来构造新的String |
String(byte[] bytes,String charsetName) | 使用指定的字符集解码指定的字节数组来构造新的String |
String data = "a我b"; //编码 byte[] bytes = data.getBytes(); System.out.println(Arrays.toString(bytes)); //解码 String s = new String(bytes); System.out.println(s);
3.IO流
3.1概述
-
按流的方向分为:
-
输入流:(Input)负责把数据读到内存中去
-
输出流:(Output)负责写数据出去
-
-
按流中数据的最小单位分为:
-
字节流:适合操作所有类型的文件
-
字符流:只适合操作纯文本文件
-
3.2IO流的体系
IO流总体来看有四大流:字节输入流,字节输出流,字符输入流,字符输出流(都是抽象类)
-
字节输入流:InputStream
-
字节输出流:OutputStream
-
字符输入流:Reader
-
字符输出流:Writer
字节流适合做数据的转移,如:文本复制等
字符流适合做读写文本内容
3.3 IO-字节流
3.31每次读取一个字节,
读取性能较差,而且读取汉字输出会乱码
//1.创建文件字节输入流管道 //InputStream is = new FileInputStream(new File("src\\itheima.txt")); //简化写法:推荐使用 InputStream is = new FileInputStream("src\\1.txt"); //2.开始读取文件的字节数据 //public int read(); 每次读取一个字节返回,如果没有数据,返回-1 // int b1 = is.read(); // System.out.println((char)b1); // // int b2 = is.read(); // System.out.println((char)b2); //3.使用循坏改造上述代码 int b;//用于记住读取的字节 while(( b = is.read() ) != -1){ System.out.print((char)b); } // 流使用完毕之后,必须关闭!释放系统资源! is.close();
3.32每次读取多个字节
读取性能得到了提升,但是读取汉字输出还是会乱码
//1.创建文件字节输入流管道 InputStream is = new FileInputStream("src\\1.txt"); //2.开始读取文件的字节数据,每次读取多个字节 //每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1 // byte[] buffer = new byte[3]; // int len = is.read(buffer); // // String rs = new String(buffer); // System.out.println(rs); // // int len2 = is.read(buffer); // String rs2 = new String(buffer,0,len2); // System.out.println(rs2); //3.使用循环改造 byte[] buffer = new byte[3]; int len; while((len = is.read(buffer)) != -1){ String rs = new String(buffer, 0, len); System.out.print(rs); } // 流使用完毕之后,必须关闭!释放系统资源! is.close();
3.33一次读取完全部字节
-
方式一:自己定义一个字节数字与被读取的文件大小一样大,然后使用该字节数组,一次读完文件的全部字节
public int read( byte[] buffer ) //每次用一个字节数组去读取,返回字节数组读取了多少个字节,如果发现没有数据可读会返回-1
//1.创建文件字节输入流管道 InputStream is = new FileInputStream("src\\1.txt"); //2.准备一个字节数据,大小与文件的大小正好一样大 File f =new File("src\\1.txt"); long size = f.length(); byte[] buffer = new byte[(int) size]; int len = is.read(buffer); String rs = new String(buffer, 0, len); System.out.println(rs);
-
方式二 Java官方为InputStream提供了如下方法,可以直接把文件的全部字节读取到一个字节数组中返回
public byte[] readAllBytes() throws IOException//直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回
3.34 文件字节输出流
//1.创建一个字节输出流管道 //覆盖管道,覆盖之前的数据 //OutputStream os = new FileOutputStream("src/2.txt"); //追加数据的管道 OutputStream os = new FileOutputStream("src/2.txt", true); //2.开始写字节数据出去了 os.write(97); byte[] bytes = "我爱你中国abc".getBytes(); os.write(bytes); os.write(bytes,0,15); //换行符 \r\n os.write("\r\n".getBytes()); os.close();
3.35 文件复制
字节流非常适合做一切文件的复制操作
//1.创建一个字节输入流与源文件相同 InputStream is = new FileInputStream("D:\\Users\\1.jpg"); //2.创建一个字节输出流管道与目标文件接通 OutputStream os = new FileOutputStream("src/1.jpg"); //3.创建一个字节数组,负责转移字节数据 byte[] buffer = new byte[1024]; //4.从字节输入流中读取字节数据,写出去到字节输出流中,读多少写多少出去 int len; while ((len = is.read(buffer)) != -1) { os.write(buffer, 0, len); } os.close(); is.close();
3.36 释放资源的方式
try-catch-finally
finally代码区的特点:无论try中的程序是正常执行了,还是出现了异常,最后都一定会执行finally区,除非JVM终止
作用:一般用于在程序执行完成后进行资源的释放操作
try-with-resource
该资源使用完毕后,会自动调用其close()方法,完成对资源的释放!
3.4 字符流
3.41 文件字符输入流
//1.创建一个文件字符输入流与源文件接通 try (Reader r1 = new FileReader("src\\3.txt")) { //2.读取文本文件内容 // int c;//记住每次读取的字符编号 // while((c = r1.read()) != -1) { // System.out.print((char)c); // }//每次读取一个字符的形式,性能肯定是比较差的 //3.每次读取多个字符 char[] buffer = new char[3]; int len;//记住每次读取了多少个字符 while((len = r1.read(buffer)) != -1) { System.out.print(new String(buffer, 0, len)); } }catch(Exception e) { e.printStackTrace(); }
3.42 文件字符输出流
//1.创建一个文件字符输出流管道与目标文件接通 try (FileWriter f1 = new FileWriter("src/4.txt");){ f1.write("Hello World"); f1.write(97); f1.write("范"); f1.write("我爱你中国abc",0,5); f1.write("\r\n"); char[] buffer = {'1','2','c'}; f1.write(buffer); } catch (Exception e) { e.printStackTrace(); }
注意事项:字符输出流写出数据后,必须刷新流,或者关闭流,写出去的数据才能生效
3.5缓冲流
3.51字节缓冲流
包装原始流,提高性能,用法不变
InputStream is = new FileInputStream("src/1.txt"); InputStream bis = new BufferedInputStream(is);
3.52 字符缓冲流
包装原始流,提高性能,用法不变
新增功能:按照行读取字符
public String readLine() // 读取一行数据返回,没有数据可读了,会返回null
3.6 转换流
如果代码编码和被读取的文本文件的编码是不一致的,使用字符流读取文本文件时就会出现乱码
3.61 字符输入转换流
InputStreamReader
//1.得到文件的原始字节流 try ( InputStream is = new FileInputStream("src/1.txt"); Reader isr = new InputStreamReader(is, "UTF-8"); BufferedReader br = new BufferedReader(isr); ) { String line; while((line = br.readLine()) != null) { System.out.println(line); } } catch (Exception e) { e.printStackTrace(); }
3.62 字符输出转换流
OutputStreamWriter
3.7 打印流
作用:打印流可以实现更方便、更高效的打印数据出去,能实现打印啥出去就是啥出去
//1.创建一个打印流管道 try( //PrintStream ps = new PrintStream("src/5.txt"); PrintStream ps = new PrintStream("src/5.txt", "GBK"); ){ ps.println("Hello World"); ps.println(1); ps.print(true); }catch(Exception e){ e.printStackTrace(); }
3.71 PrintStream和PrintWriter的区别
-
打印数据的功能上是一摸一样的:都是使用方便,性能高效
-
PrintStream继承自字节输出流OutputStream,因此支持写字节数据的方式
-
PrintWriter继承自字符输出流Writer,因此支持写字符数据出去
3.72 输出语句的重定向
可以把输出语句的打印位置改到某个文件中去
PrintStream ps = new PrintStream("文件地址"); System.setOut(ps); System.out.println("");
3.8 数据流
-
DataOutputStream
数据输出流:允许把数据和其类型一并写出去
-
DataInputStream
3.9 序列化流
-
ObjectOutputStream
(对象字节输出流)可以将Java对象进行序列化:把Java对象存入到文件中去
public class FileText1 { public static void main(String[] args) { //1.创建一个java对象, User u = new User("admin","张三",32); try( //2.创建一个对象字节输出流包装原始字节输出流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src/7.txt")); ){ //3.序列化对象到文件中 oos.writeObject(u); }catch(Exception e){ e.printStackTrace(); } } } //对象如果需要序列化,必须实现序列化接口 class User implements Serializable{ private String loginName; private String username; private int age; public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public User(String loginName, String username, int age) { this.loginName = loginName; this.username = username; this.age = age; } public User() { } @Override public String toString() { return "User{" + "loginName='" + loginName + '\'' + ", username='" + username + '\'' + ", age=" + age + '}'; } }
-
ObjectInputStream
(对象字节输入流)可以将Java对象进行反序列化:把存储在文件中的Java对象读入到内存中来
try( //1.创建一个对象字节输入流管道,包装 低级的字节输入流与源文件接通 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/7.txt")); ){ User u = (User)ois.readObject(); System.out.println(u); }catch(Exception e){ e.printStackTrace(); } }