Java --> IO流(字符集)
2022/7/10 1:22:31
本文主要是介绍Java --> IO流(字符集),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
- 字符集:
1 import java.util.Arrays; 2 3 public class Test { 4 public static void main(String[] args) throws Exception { 5 //1、编码:把文字转换成指定的字节 6 String name = "abc阿1百2川"; 7 byte[] bytes = name.getBytes(); //以当前代码默认字符集进行编码(UTF-8) 8 System.out.println(bytes.length); //一个英文字符占1个字节,一个中文字符占3个字节 9 System.out.println(Arrays.toString(bytes)); 10 11 System.out.println("---------------"); 12 //以指定形式(GBK)转换成字节数组 13 byte[] bytes1 = name.getBytes("GBK"); //一个英文字符占1个字节,一个中文字符占2个字节 14 System.out.println(bytes1.length); 15 System.out.println(Arrays.toString(bytes)); 16 17 //2、解码:把字节转换成对应的中文形式(注:编码前和编码后的字符集要一致) 18 String str = new String(bytes); //以当前代码默认字符集进行解码(UTF-8)<编码、解码前后字符集一致> 19 System.out.println(str); 20 21 System.out.println("-----------------"); 22 String str1 = new String(bytes1); //以当前代码默认字符集进行解码(UTF-8)<编码(GBK)、解码(UTF-8)前后字符集不一致> 23 System.out.println(str1); 24 System.out.println("---乱码原因:GBK以两个字节存储的数据会被UTF-8强行解析成三个字节表示的数据---"); 25 //改正:编码使用GBK、解码也要使用GBK 26 String str2 = new String(bytes1, "GBK"); 27 System.out.println(str2); 28 } 29 }
- 文件字节输入流(FileInputStream):每次读取一个字节(适合读英文,读取中文会发生乱码)
- 作用:以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中去
1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.InputStream; 4 5 public class FileInputStreamDemo1 { 6 public static void main(String[] args) throws Exception{ 7 //创建文件字节输入流管道与源文件对象接通 8 //InputStream inputStream = new FileInputStream(new File("file-io-app/src/data.txt")); //多态 9 //简化写法:可以直接定位到文件 10 InputStream inputStream = new FileInputStream("file-io-app/src/data.txt"); //多态 11 12 //读取一个字节返回 13 // int read = inputStream.read(); 14 // System.out.print(read + " "); //97 15 // System.out.println((char)read); //a 16 // 17 // int read1 = inputStream.read(); 18 // System.out.print(read1 + " "); //98 19 // System.out.println((char)read1); //b 20 // 21 // int read2 = inputStream.read(); 22 // System.out.print(read2 + " "); //99 23 // System.out.println((char)read2); //c 24 // 25 // int read3 = inputStream.read(); 26 // System.out.print("读取不到返回:" + read3); // -1 27 28 //循环:弊端 --> 读取中文时会出现乱码:按照3个字节来读取<会截断原有的字节数据> 29 int read = 0; 30 while ((read = inputStream.read()) != -1){ 31 System.out.print((char) read); 32 } 33 } 34 }
- 文件字节输入流(FileInputStream):每次读取一个字节数组
1 import java.io.FileInputStream; 2 import java.io.InputStream; 3 4 //使用文件字节输入流每次读取一个字节数组的形式 5 public class FileInputStreamDemo2 { 6 public static void main(String[] args) throws Exception{ 7 //创建文件字节输入流管道与源文件接通 8 InputStream inputStream = new FileInputStream("file-io-app/src/data02.txt"); 9 //定义字节数组,用于读取字节数组 10 byte[] bytes = new byte[3]; //声明字节数组大小,即每次读取的字节数 11 12 // int read = inputStream.read(bytes); 13 // System.out.println(read); 14 // //解码(UTF-8) 15 // String str = new String(bytes); 16 // System.out.println(str); 17 // 18 // int len1 = inputStream.read(bytes); 19 // System.out.println(len1); 20 // //解码(UTF-8) 21 // String str1 = new String(bytes); 22 // System.out.println(str1); 23 // 24 // int len2 = inputStream.read(bytes); 25 // System.out.println(len2); 26 // //解码(UTF-8) 27 // String str2 = new String(bytes); 28 // System.out.println(str2); 29 // 30 // //读取几个倒几个 31 // int len3 = inputStream.read(bytes); 32 // System.out.println(len3); 33 // //解码(UTF-8) 34 // String str3 = new String(bytes,0,len3); 35 // System.out.println(str3); 36 // 37 // int len4 = inputStream.read(bytes); 38 // System.out.println(len4); 39 40 //改进:使用循环,每次读取一个字节数组 41 //优点:性能提升(相较于一个一个字节而言,使用字节数组更快)、做复制时没问题 42 //弊端:中英文混合时会发生乱码 43 int length = 0; 44 while ((length = inputStream.read(bytes,0,3)) != -1){ 45 String str = new String(bytes,0,length); 46 System.out.print(str); 47 } 48 } 49 }
示例代码运行结果:
示例代码之所以没有出现乱码的原因:abc刚好够一个字节数组,而一个中文又占3个字节,最后两个字符12读取多少个截取多少个。
- 文件字节输入流:一次读完全部的字节
如何使用字节输入流读取中文内容不乱码?
定义一个与文件一样大的字节数组,一次性读完文件的所有字节。不过这样做也有相应的问题:如果文件过大,字节数组可能引起内存溢出。
- 方式一:自己定义一个与文件一样大的字节数组
- 方式二:官方提供了readAllBytes()的API 【JDK9开始】
1 public class FileInputStreamDemo3 { 2 public static void main(String[] args) throws Exception{ 3 File file = new File("file-io-app/src/data03.txt"); 4 //创建文件字节输入流管道与源文件接通 5 InputStream inputStream = new FileInputStream(file); 6 //定义字节数组,用于读取字节数组 7 int length = (int)file.length(); 8 byte[] bytes = new byte[length]; //声明字节数组大小,即每次读取的字节数 9 int charNumber = inputStream.read(bytes); 10 String str = new String(bytes,0,length); 11 System.out.println("读取了:" + charNumber + "个字节"); 12 System.out.println(str); 13 14 //不过自JDK9开始,Java也提供了可以一次性读完所有文件内容的API 15 // byte[] bytes = inputStream.readAllBytes(); 16 // System.out.println(new String(bytes)); 17 } 18 }
示例代码运行结果:
- 文件字节输出流:写字节数据到文件
1 import java.io.FileOutputStream; 2 3 public class FileOutputStreamDemo1 { 4 public static void main(String[] args) throws Exception { 5 //1、创建文件字节输出流管道与目标文件接通 6 //覆盖管道:先清空之前的管道,在写入新的数据 7 FileOutputStream outputStream = new FileOutputStream("file-io-app/src/out04.txt"); 8 //如果想追加管道,只需在构造器后多加一个参数true 9 //FileOutputStream outputStream = new FileOutputStream("file-io-app/src/out04.txt",true); 10 //2、写数据出去 11 outputStream.write('a'); 12 outputStream.write(98); //对应字符的ASCII码值 13 outputStream.write('c'); 14 outputStream.write("\r\n".getBytes()); //换行 15 //写入中文会发生乱码的原因:默认只能写一个字节,而一个中文占3个字节,写入中文时会强行地把中文字符的第一个字节截断 16 //outputStream.write('人'); 17 //以GBK编码的形式写入出现乱码的原因:编码用的时GBk,解码时用的时UTF-8 18 // byte[] bytes = "闻道有先后".getBytes("GBK"); 19 // outputStream.write(bytes); 20 21 //3、写一个字节数组的一部分出去 22 byte[] bytes = {'a',97,98,99}; //只写前三个 23 outputStream.write(bytes,0,3); 24 25 //刷新数据【写数据必须刷新数据】 26 outputStream.flush(); //刷新后流还可以继续用 27 outputStream.close(); //关闭后流就不可以用了,且关闭之前会自动刷新流 28 } 29 }
data04.txt文件内容:
- 使用字节输入、输出流做文件的拷贝
1 import java.io.*; 2 3 //使用字节流完成文件的复制 4 public class CopyDemo5 { 5 public static void main(String[] args) { 6 //创建字节输入流管道与原视频接通 7 try { 8 InputStream inputStream = new FileInputStream("D:\\tencent\\QQ\\MobileFile\\class_for_183.mp4"); 9 //创建字节输出流管道与目标文件接通 10 OutputStream outputStream = new FileOutputStream("D:\\tencent\\QQ\\MobileFile\\new_class_for_183.mp4"); 11 //定义一个字节数组转移数据 12 byte[] bytes = new byte[1024]; 13 int len = 0; //len 用于记录每次读取到的数据个数(读多少倒多少,防止最后的一组数据装不满) 14 while ((len = inputStream.read(bytes)) != -1 ){ 15 outputStream.write(bytes,0,len); 16 } 17 System.out.println("复制完成"); 18 //关闭流 19 inputStream.close(); 20 outputStream.close(); 21 } catch (Exception e) { 22 e.printStackTrace(); 23 } 24 } 25 }
因为任何文件的底层都是字节,拷贝则是对这些字节进行转移,只要前后文件格式、编码一致就没有任何问题。
- 资源释放的两种方式(第一种):try-catch-finally
因此,对于上述代码建议更改为下列模式的写法:
1 import java.io.*; 2 3 public class TryCatFinallyDemo1 { 4 public static void main(String[] args) { 5 //把对象定义到上边 6 InputStream inputStream = null; 7 OutputStream outputStream = null; 8 //创建字节输入流管道与原视频接通 9 try { 10 //以防出现在代码块上边出现异常导致两个管道都为null ,如:此处出现 System.out.prinln(10 / 0); 11 inputStream = new FileInputStream("D:\\tencent\\QQ\\MobileFile\\class_for_183.mp4"); 12 //创建字节输出流管道与目标文件接通 13 outputStream = new FileOutputStream("D:\\tencent\\QQ\\MobileFile\\new_class_for_183.mp4"); 14 //定义一个字节数组转移数据 15 byte[] bytes = new byte[1024]; 16 int len = 0; //len 用于记录每次读取到的数据个数(读多少倒多少,防止最后的一组数据装不满) 17 while ((len = inputStream.read(bytes)) != -1 ){ 18 outputStream.write(bytes,0,len); 19 } 20 System.out.println("复制完成"); 21 22 23 } catch (Exception e) { 24 e.printStackTrace(); 25 }finally { 26 //关闭流 27 try { 28 if (inputStream != null) inputStream.close(); 29 } catch (IOException e) { 30 e.printStackTrace(); 31 } 32 try { 33 if (outputStream != null) outputStream.close(); 34 } catch (IOException e) { 35 e.printStackTrace(); 36 } 37 } 38 } 39 }
System.exit(0) ; //try代码块里边干掉虚拟机,finall代码块就不会执行了
- 资源释放的两种方式(方式二):try-with-resource
正如上述代码所示(27~36行):如果要关闭两个管道的流,就需要写两个try - catch代码块,写法较为繁琐。
1 import java.io.*; 2 3 public class TryWithResourceDemo1 { 4 public static void main(String[] args) { 5 //创建字节输入流管道与原视频接通 6 try( 7 //这里边防止资源对象,用完后会自动关闭(即使出现异常) 8 //以防出现在代码块上边出现异常导致两个管道都为null ,如:此处出现 System.out.prinln(10 / 0); 9 InputStream inputStream = new FileInputStream("D:\\tencent\\QQ\\MobileFile\\dest_video.mp4"); 10 //创建字节输出流管道与目标文件接通 11 OutputStream outputStream = new FileOutputStream("D:\\tencent\\QQ\\MobileFile\\dest_video.mp4"); 12 13 Myconnection myconnection = new Myconnection() 14 //int age = 9; //这样的代码防止在这里是不被允许的,只能放置资源,而所谓的资源,就是实现了AutoCloseable接口 15 ) { 16 //定义一个字节数组转移数据 17 byte[] bytes = new byte[1024]; 18 int len = 0; //len 用于记录每次读取到的数据个数(读多少倒多少,防止最后的一组数据装不满) 19 while ((len = inputStream.read(bytes)) != -1 ){ 20 outputStream.write(bytes,0,len); 21 } 22 System.out.println("复制完成"); 23 } catch (Exception e) { 24 e.printStackTrace(); 25 } 26 } 27 } 28 29 class Myconnection implements AutoCloseable{ 30 //重写接口里边的close方法 31 @Override 32 public void close() throws Exception { 33 //此方法被调用了就说明是下了AutoCloseable的接口就会自动调用此处的close方法,也就是释放资源 34 System.out.println("资源被成功释放!"); 35 } 36 }
JDK9提供的释放资源的方式:
这样做就很尴尬了,虽说把资源管道定义在了try代码块外边,但是外边的管道又需要把异常抛出,那么既如此,而下边的try-catch代码块就是用来捕获异常的,就起不到作用了~
- 文件字符输入流、文件字符输出流
- 一个一个字符进行读取
1 import java.io.FileReader; 2 import java.io.Reader; 3 4 public class FileReaderDemo1 { 5 public static void main(String[] args) throws Exception{ 6 //每次读取一个字符 7 //1、创建一个字符输入流管道与源文件对象接通 8 Reader reader = new FileReader("file-io-app\\src\\data05.txt"); 9 10 //2、每次读取一个字符 11 // int len1= reader.read(); //返回的是对应字符的编号,没有可读的字符时返回-1 12 // System.out.println("读取到字符编号:" + len1); //49 13 // System.out.println("读取到的字符:" + (char) len1); //1 14 // System.out.println("------------------------"); 15 // int len2 = reader.read(); 16 // System.out.println("读取到字符编号:" + len2); //46 17 // System.out.println("读取到的字符:" + (char) len2); //. 18 // System.out.println("------------------------"); 19 // int len3 = reader.read(); 20 // System.out.println("读取到字符编号:" + len3); //32 21 // System.out.println("读取到的字符:" + (char) len3); //空格 22 23 //使用循环的方式读取 24 int len = 0; 25 while ((len = reader.read()) != -1){ 26 System.out.print( (char) len) ; 27 } 28 } 29 }
data05.txt文件内容:
示例程序运行结果:
注:在此,需要指出的一个小小的点是 -- 有人可能会问,char类型的数据不是底层占2个字节吗,而在Unicode编码中,中文字符是占3个字节的,为什么可以用char来读取中文字符呢?需要阐明的是:这个地方使用的是字符输入流,也就是说 int len = reader.read(),其中 len 作为read 的返回值,源码中是这样描述的:The number of characters read, or -1 if the end of the stream has been reached
即:读取到的字符数,如果到流的末尾了则返回 -1 。也就是说,字符流读取数据是以字符为最小单位进行读取的,读取到的是字符(所代表的Unicode编码值),只是最终结果把该字符的编码值强制转换成了实际所代表值。
- 字符数组进行读取
1 import java.io.FileReader; 2 import java.io.Reader; 3 4 //一个一个字符数组读取 5 public class FileReaderDemo2 { 6 public static void main(String[] args) throws Exception{ 7 //1、创建文件字节输入流管道与源文件接通 8 Reader reader = new FileReader("file-io-app/src/data06.txt"); 9 10 //2、声明循环,每次读取一个字符数组的数据 11 char[] buffer = new char[1024]; //每次读取1k的数据 12 13 //3、定义一个len记录每次读取到的字符个数 14 int len = 0; 15 16 //4、循环读取 17 while ((len = reader.read(buffer)) != -1){ 18 String str = new String(buffer,0,len); 19 System.out.print(str); 20 } 21 } 22 }
data06.txt文档内容(这里为了省事就直接把FileReaderDemo1中的代码粘贴进去了)就不在此展示了,直接展示程序运行结果:
- 文件字符输出流
1 import java.io.FileWriter; 2 import java.io.Writer; 3 4 public class FileWriteDemo3 { 5 public static void main(String[] args) throws Exception{ 6 //覆盖管道:每次运行都会清空之前的数据(输出流如果不存在out08.txt会自动创建) 7 Writer writer = new FileWriter("file-io-app/src/out08.txt"); 8 //追加管道:每次运行都是追加之前的数据,对源数据不会造成影响 9 //Writer writer = new FileWriter("file-io-app/src/out08.txt", true); 10 11 //1、写一个字符 12 writer.write(97); 13 writer.write(98); 14 writer.write('鹏'); 15 writer.write("\r\n"); //换行 16 17 //2、写一个字符串 18 writer.write("闻道有先后,术业有专攻"); 19 writer.write("\r\n"); 20 21 //3、写一个字符数组出去 22 //char[] chars = {'J','a','v','a'}; 23 char[] chars = "Java".toCharArray(); 24 writer.write(chars); 25 writer.write("\r\n"); 26 27 //4、写字符串数组的一部分出去 28 29 /** 30 * off : 开始写入字符的偏移量,(可以理解为字符出的下标) 31 * len : 写入的字符个数 32 */ 33 34 writer.write("一分耕耘一分收获",0,4); 35 writer.write("\r\n"); 36 37 //5、写字符数组的一部分 38 char[] chars1 = "一二三四五六七八九十".toCharArray(); 39 writer.write(chars1,2,5); // 三四五六七 40 writer.write("\r\n"); 41 42 //刷新流 43 //writer.flush(); //刷新后流还可以继续使用 44 //关闭流 45 writer.close(); //关闭(会自动刷新流)后流就不可以使用了 46 } 47 }
示例程序运行后 out08.txt 的文档内容:
这篇关于Java --> IO流(字符集)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-26手写消息中间件:从零开始的指南
- 2024-11-26Java语音识别项目资料:新手入门教程
- 2024-11-26JAVA语音识别项目资料:新手入门教程
- 2024-11-26Java语音识别项目资料:入门与实践指南
- 2024-11-26Java云原生资料入门教程
- 2024-11-26Java云原生资料入门教程
- 2024-11-26Java云原生资料:新手入门教程
- 2024-11-25Java创意资料:新手入门的创意学习指南
- 2024-11-25JAVA对接阿里云智能语音服务资料详解:新手入门指南
- 2024-11-25Java对接阿里云智能语音服务资料详解