• 16.IO之其他流


    第一  打印流

    一、概述:

    该流提供了打印方法,可以将各种数据类型的数据都原样打印

    原理将97先变成字符保持原样将数据打印到目的地

    1、字节打印流:PrintStream  构造函数可以接收的参数类型:
    1)file对象。File
    2)字符串路径。String
    3)字节输出流。OutputStream

    2、字符打印流:PrintWriter 构造函数可以接收的参数类型:
    1)file对象。File
    2)字符串路径。String
    3)字节输出流。OutputStream
    4)字符输出流,Writer。


      PrintStream out = new PrintStream("print.txt");
    // int by = read();
    // write(by);
    // out.write(610);//只写最低8位,
    // out.print(97);//将97先变成字符保持原样将数据打印到目的地。
      out.close();
    从控制台写到控制台
    1. private static void controlToC() throws IOException {
    2. BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    3. PrintWriter pw = new PrintWriter(System.out);
    4. String line = null;
    5. while ((line = bf.readLine()) != null) {
    6. if ("over".equals(line)) {
    7. break;
    8. }
    9. pw.println(line.toUpperCase());
    10. pw.flush();
    11. }
    12. pw.close();
    13. bf.close();
    14. }
    从控制台写到文件中
    1. public static void main(String[] args) throws IOException {
    2. BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
    3. //特有构造器,turn就自动刷新,可是写到文件中不能自动刷新new FileWriter("out.txt"),所以写到一个输出流中,完成自动刷新
    4. PrintWriter out = new PrintWriter(new FileWriter("out.txt"),true);
    5. String line = null;
    6. while((line=bufr.readLine())!=null){
    7. if("over".equals(line))
    8. break;
    9. out.println(line.toUpperCase());
    10. // out.flush();
    11. }
    12. out.close();
    13. bufr.close();
    14. }
    15. }
    获取系统信息,并保存:
    步骤:
    1)获取系统信息:
    Properties getProperties()
    2)将信息输出到指定输出流中
    void  list(PrintStream out)
    3)将输出流中数据存入指定文件中
    new PrintStream("systeminfo.txt")

    1. public class SysInfo {  
    2.     public static void main(String[] args) {  
    3.         Properties pro = System.getProperties();  
    4.   
    5.         try {  
    6.             pro.list(new PrintStream("sysinfo.txt"));// list方法将属性列表输出到指定的输出流。  
    7.         } catch (FileNotFoundException e) {  
    8.             e.printStackTrace();  
    9.         }  
    10.     }  
    11. }

    第二  合并流(序列流)

    一、概述:

    SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

    二、如何合并多个文件:

    1、创建集合,并将流对象添加进集合或者SequenceInputStream(InputStream s1,InputStream s2)加入两个输入流

    2、创建Enumeration对象,将集合元素加入。

    3、创建SequenceInputStream对象,合并流对象

    4、创建写入流对象,FileOutputStream,将数据写入流资源

    5、定义数组,将读取流数据存入数组,并将数组中元素写入文件中。

    1. public class SequenceInputStreamDemo {
    2. /*
    3. * 需求:将1.txt 2.txt 3.txt文件中的数据合并到一个文件中。
    4. */
    5. Vector(枚举)中才有Enumeration
    6. // Vector<FileInputStream> v = new Vector<FileInputStream>();
    7. // v.add(new FileInputStream("1.txt"));
    8. // v.add(new FileInputStream("2.txt"));
    9. // v.add(new FileInputStream("3.txt"));
    10. // Enumeration<FileInputStream> en = v.elements(); //这样就获取了枚举了
    11. //枚举和迭代一样,枚举没过时,过时是编译器不认识了,不过 ArrayList有效率
    12. ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
    13. for(int x=1; x<=3; x++){
    14. al.add(new FileInputStream(x+".txt"));
    15. }
    16. Enumeration<FileInputStream> en = Collections.enumeration(al);
    17. //有个返回枚举的方法,它的原理就是下边这个
    18. /*
    19. final Iterator<FileInputStream> it = al.iterator(); //内部类访问局部变量用final
    20. Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){
    21. //new了个 Enumeration,匿名内部类
    22. //枚举接口的实现中利用迭代器,这样写比较麻烦,不懂,参见io流--51
    23. @Override
    24. public boolean hasMoreElements() {
    25. return it.hasNext();
    26. }
    27. @Override
    28. public FileInputStream nextElement() {
    29. return it.next();
    30. }
    31. };*/
    32. //合并
    33. SequenceInputStream sis = new SequenceInputStream(en);
    34. FileOutputStream fos = new FileOutputStream("1234.txt");
    35. byte[] buf = new byte[1024];
    36. int len = 0;
    37. while((len=sis.read(buf))!=-1){
    38. fos.write(buf,0,len);
    39. }
    40. fos.close();
    41. sis.close();
    42. }
    43. }

    切割文件重点,定义一个你需要把文件切成多大的数组,然后把数据读到数组中,读满后写出到文件中,这样就完成了切割:

    1. * 文件的切割和合并
    2. */
    3. public class SplitFile {
    4. public static void main(String[] args) throws IOException {
    5. // splitFile();
    6. sequence();
    7. }
    8. /*
    9. * 切割文件
    10. */
    11. public static void splitFile() throws IOException
    12. {
    13. FileInputStream fis = new FileInputStream("0.jpg");
    14. FileOutputStream fos = null;
    15. byte[] byf = new byte[1024*1024];//定义需要切割大小的空间
    16. int len = 0;
    17. int count = 1;//为文件取名用的数字
    18. while((len=fis.read(byf)) != -1){
    19. fos = new FileOutputStream((count++) + ".patch");//创建指定的文件
    20. fos.write(byf,0,len);//把读取到的数据写入指定的文件中
    21. fos.close();//关闭资源
    22. }
    23. fis.close();//关闭资源
    24. }
    25. /*
    26. * 合并文件
    27. */
    28. public static void sequence() throws IOException{
    29. ArrayList<FileInputStream> list = new ArrayList<FileInputStream>();
    30. list.add(new FileInputStream("1.patch"));
    31. list.add(new FileInputStream("2.patch"));
    32. list.add(new FileInputStream("3.patch"));
    33. //通过迭代器方法获取枚举
    34. final Iterator<FileInputStream> it = list.iterator();//内部类使用的成员变量必须是final修饰的
    35. //通过内部类实现枚举
    36. Enumeration<FileInputStream> en = new Enumeration<FileInputStream>() {
    37. @Override
    38. public FileInputStream nextElement() {
    39. return it.next();
    40. }
    41. @Override
    42. public boolean hasMoreElements() {
    43. return it.hasNext();
    44. }
    45. };
    46. SequenceInputStream sequence = new SequenceInputStream(en);
    47. FileOutputStream fos = new FileOutputStream("10.jpg");
    48. byte[] byf = new byte[1024];
    49. int len = 0;
    50. while((len=sequence.read(byf)) != -1){
    51. fos.write(byf,0,len);
    52. }
    53. sequence.close();
    54. fos.close();
    55. }
    56. }


    练习1:文件切割(按大小切)
    1. public class SplitFileDemo {
    2. private static final int SIZE = 1024 * 1024;
    3. public static void main(String[] args) throws Exception {
    4. File file = new File("c:\aa.mp3");
    5. splitFile_2(file);
    6. }
    7. // 修改后
    8. private static void splitFile_2(File file) throws IOException {
    9. // 用读取流关联源文件。
    10. FileInputStream fis = new FileInputStream(file);
    11. // 定义一个1M的缓冲区。
    12. byte[] buf = new byte[SIZE];
    13. // 创建目的。
    14. FileOutputStream fos = null;
    15. int len = 0;
    16. int count = 1;
    17. /*
    18. * 切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数。 以方便于合并。
    19. * 这个信息为了进行描述,使用键值对的方式。用到了properties对象
    20. */
    21. Properties prop = new Properties();
    22. File dir = new File("c:\partfiles");// 将碎片放到固定文件夹中,也可以不写
    23. if (!dir.exists())
    24. dir.mkdirs();
    25. while ((len = fis.read(buf)) != -1) {
    26. fos = new FileOutputStream(new File(dir, (count++) + ".part"));
    27. // 不能写new
    28. // FileOutputStream("1.txt"),问题1:第二次new把第一次new的覆盖了,所有1不能写死,还要合并。
    29. // 问题2:扩展名不能写死,碎片文件不能阅读
    30. fos.write(buf, 0, len);
    31. fos.close();
    32. }
    33. // 将被切割文件的信息保存到prop集合中。
    34. prop.setProperty("partcount", count + "");// 碎片文件的个数
    35. prop.setProperty("filename", file.getName());// 文件的名字
    36. fos = new FileOutputStream(new File(dir, count + ".properties"));
    37. // 将prop集合中的数据存储到文件中。
    38. prop.store(fos, "save file info");//
    39. fos.close();
    40. fis.close();
    41. }
    42. // 原始:
    43. public static void splitFile(File file) throws IOException {
    44. // 用读取流关联源文件。
    45. FileInputStream fis = new FileInputStream(file);
    46. // 定义一个1M的缓冲区。
    47. byte[] buf = new byte[SIZE];
    48. // 创建目的。
    49. FileOutputStream fos = null;
    50. int len = 0;
    51. int count = 1;
    52. File dir = new File("c:\partfiles");
    53. if (!dir.exists())
    54. dir.mkdirs();
    55. while ((len = fis.read(buf)) != -1) {
    56. fos = new FileOutputStream(new File(dir, (count++) + ".part"));
    57. fos.write(buf, 0, len);
    58. }
    59. fos.close();
    60. fis.close();
    61. }
    62. }

    练习2:合并
    1. public class MergeFile {
    2. public static void main(String[] args) throws IOException {
    3. File dir = new File("c:\partfiles");
    4. mergeFile_2(dir);
    5. }
    6. public static void mergeFile(File dir) throws IOException {
    7. ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
    8. for (int x = 1; x <= 3; x++) {
    9. al.add(new FileInputStream(new File(dir, x + ".part")));
    10. }
    11. Enumeration<FileInputStream> en = Collections.enumeration(al);
    12. SequenceInputStream sis = new SequenceInputStream(en);
    13. FileOutputStream fos = new FileOutputStream(new File(dir, "1.bmp"));// 合并到当前目录下
    14. byte[] buf = new byte[1024];
    15. int len = 0;
    16. while ((len = sis.read(buf)) != -1) {
    17. fos.write(buf, 0, len);
    18. }
    19. fos.close();
    20. sis.close();
    21. }
    22. }

    可是并知道有多少个碎片,也不知道碎片对应原来的名字是什么

     修改后

     
    1. public static void mergeFile_2(File dir) throws IOException {
    2. /*
    3. * 获取指定目录下的配置文件对象。
    4. */
    5. File[] files = dir.listFiles(new SuffixFilter(".properties"));//过滤器,过滤文件名
    6. if(files.length!=1)
    7. throw new RuntimeException(dir+",该目录下没有properties扩展名的文件或者不唯一");//自定义异常
    8. //记录配置文件对象。
    9. File confile = files[0];
    10. //获取该文件中的信息================================================。
    11. Properties prop = new Properties();
    12. FileInputStream fis = new FileInputStream(confile);
    13. prop.load(fis);//流中信息加载进来
    14. String filename = prop.getProperty("filename");
    15. int count = Integer.parseInt(prop.getProperty("partcount"));
    16. //获取该目录下的所有碎片文件。 ==============================================
    17. File[] partFiles = dir.listFiles(new SuffixFilter(".part"));
    18. if(partFiles.length!=(count-1)){
    19. throw new RuntimeException(" 碎片文件不符合要求,个数不对!应该"+count+"个");//如果少了一个
    20. }
    21. //将碎片文件和流对象关联 并存储到集合中。
    22. ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
    23. for(int x=0; x<partFiles.length; x++){
    24. al.add(new FileInputStream(partFiles[x]));
    25. }
    26. //将多个流合并成一个序列流。
    27. Enumeration<FileInputStream> en = Collections.enumeration(al);
    28. SequenceInputStream sis = new SequenceInputStream(en);
    29. FileOutputStream fos = new FileOutputStream(new File(dir,filename));
    30. byte[] buf = new byte[1024];
    31. int len = 0;
    32. while((len=sis.read(buf))!=-1){
    33. fos.write(buf,0,len);
    34. }
    35. fos.close();
    36. sis.close();
    37. }
    38. }

    第三  Objectstream(对象流)

    一、概述:

    ObjectStream是可以操作对象的流。它的写方法是ObjectOutputStream,读方法是ObjectInputStream。它主要操作的是对象,而对象中也能封装数据,所以它也具备操作基本数据类型的方法。被它操作的对象必须是实现了序列化的对象也就是Serializable接口,但是输入流还多支持一种Externalizable 接口的对象。持久化

              

    实例:

    1.  * 对对象进行读写操作  
    2. public class ObjectstreamDemo {  
    3.     public static void main(String[] args) throws Exception {  
    4. //      writeObj();  
    5.         readObj();  
    6.     }  
    7.       
    8.     /*  
    9.      * 写对象  
    10.      */  
    11.     public static void writeObj() throws Exception{  
    12.         ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));  
    13. //仅仅是把对内存的对象存在硬盘上,下次拿来用,不需要用记事本解析
    14.         oos.writeObject(new Person("zhangsan", 23, "ASC"));  
    15.         oos.close();  
    16.     }  
    17.       
    18.     /*  
    19.      * 读取对象  ,读出来不是一个组合的对象,读出是数据.注意:没class文件,取不出来
    20.      */  
    21.     public static void readObj() throws Exception{  
    22.         ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.object"));  
    23.      //  他是person的属性
    24.         Person p = (Person) ois.readObject();  
    25.         System.out.println(p);  
    26.         ois.close();  
    27.     }  
    28. }

    用作被操作的类:
     * 用作对象的持久化存储,也就是用流存放到硬盘上  
     *

     * Serializable:用于给被序列化的类加入ID号。

     * 用于判断类和对象是否是同一个版本。

     * 静态不能被序列化  
     * transient关键字修饰的不能被序列化  
    1. public class Person implements Serializable///*标记接口*/实现这个接口,让该类被序列化  
    2. {  
    3.     //给类指定一个序列化标识,方便序列化,不定义会自动生成一个,如果不定义序列化,改变属性就会读不出来
    4.     private static final long serialVersionUID = 42L;  
    5.       
    6.     private String name;  //private transient String name;
    7.     private int age;  
    8.     private static String country = "cn";  
    9.       
    10.     Person(String name, int age, String country){  
    11.         this.name = name;  
    12.         this.age = age;  
    13.         Person.country = country;  
    14.     }  
    15.       
    16.     public String toString(){  
    17.         return name+":"+age+":"+country;  
    18.     }  
    19. }



    第四  RandomAccessFile

    一、概述:

    1、RandomAccessFile称之为随机访问文件的类,自身具备读写方法。

    2、该类不算是IO体系中的子类,而是直接继承Object,但是它是IO包成员,因为它具备读写功能,内部封装了一个数组,且通过指针对数组的元素进行操作,同时可通过seek改变指针的位置。

    3、可以完成读写的原理:内部封装了字节输入流

    4、构造函数:RandomAccessFile(File file,String mode),可已从它的构造函数中看出,该类只能操作文件(也有字符串),而且操作文件还有模式。

    模式传入值:”r“:以只读方式打开;”rw“:打开以便读写

    如果模式为只读,则不会创建文件,会去读一个已存在的文件,若文件不存在,则会出现异常,如果模式为rw,且该对象的构造函数要操作的文件不存在,会自动创建,如果存在,则不会覆盖,也可通过seek方法修改。

    二、特有方法:

    1、seek(int n):设置指针,可以将指针设置到前面或后面

    2、skipBytes(int n):跳过指定字节数,不可往前跳

    实例:

    1. public class RandomAccessFileDemo {
    2. public static void main(String[] args) throws IOException {
    3. writeFile();
    4. // readFile();
    5. }
    6. public static void writeFile() throws IOException{
    7. RandomAccessFile raf = new RandomAccessFile("random.txt","rw");
    8. //如果文件不存在,则创建,如果文件存在,不创建,把下边的代码注释掉,再读这些东西还在
    9. raf.write("张三".getBytes()); //内部封装的是一个字节数组,转成字节数组
    10. raf.writeInt(97);//write方法只读取最低8位,用writeint
    11. raf.write("李四".getBytes()); //不是覆盖,是接着写
    12. raf.writeInt(98); //不是覆盖,是接着写
    13. //********往指定位置上存储数据,也可以修改数据
    14. raf.seek(8*4);
    15. raf.write("王五".getBytes());
    16. raf.writeInt(103);
    17. raf.close();
    18. }
    19. public static void readFile() throws IOException{
    20. RandomAccessFile raf = new RandomAccessFile("random.txt","r");
    21. //调整对象中的指针
    22. // raf.seek(8*1);//根据数组定,数组大小*跳几个
    23. //跳过指定的字节数,只能向前不能向后
    24. raf.skipBytes(8);
    25. byte[] buf = new byte[4];
    26. raf.read(buf);
    27. String name = new String(buf);
    28. int age = raf.readInt();
    29. System.out.println(name + " : " + age);
    30. raf.close();
    31. }
    32. }



    第五  管道流

    一、概述:

    可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入PipedOutputStream 对象,并由其他线程从连接的PipedInputStream 读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于毁坏状态(read是阻塞状态,他会一直等)

    二、使用步骤:

    1、要先创建一个读和写的两个类,实现Runnable接口,因为是两个不同的线程,覆盖run方法,注意,需要在内部处理异常,因为重写run方法

    2、创建两个管道流,并用connect()方法将两个流连接

    3、创建读写对象,并传入两个线程内,并start执行

    实例:
    1. /
    2. * 管道流
    3. * 用多线操作,单线程容易造成死锁
    4. */
    5. public class PipedStreamDemo {
    6. public static void main(String[] args) throws IOException {
    7. PipedInputStream in = new PipedInputStream();
    8. PipedOutputStream out = new PipedOutputStream();
    9. in.connect(out); //将俩个线程连接起来,谁连谁都一样
    10. Read r = new Read(in);
    11. Write w = new Write(out);
    12. new Thread(r).start();
    13. new Thread(w).start();
    14. }
    15. }
    16. class Write implements Runnable {
    17. private PipedOutputStream out;
    18. Write(PipedOutputStream out) {
    19. this.out = out;
    20. }
    21. @Override
    22. public void run() {
    23. try {
    24. Thread.sleep(4000);
    25. out.write("piped stream come".getBytes());
    26. out.close();
    27. } catch (IOException e) {
    28. e.printStackTrace();
    29. } catch (InterruptedException e) {
    30. e.printStackTrace();
    31. }
    32. }
    33. }
    34. class Read implements Runnable {
    35. private PipedInputStream in;
    36. Read(PipedInputStream in) {
    37. this.in = in;
    38. }
    39. @Override
    40. public void run() {
    41. byte[] byf = new byte[1024];
    42. int len = 0;
    43. try {
    44. while ((len = in.read(byf)) != -1) {
    45. String str = new String(byf, 0, len);
    46. System.out.println(str);
    47. }
    48. } catch (IOException e) {
    49. e.printStackTrace();
    50. }
    51. }
    52. }


    第六  DataStream(操作基本类型的流)

    一、概述:

    DataStream是可以用于操作基本数据类型的数据的流对象:DataInputStream与DataOutputStream,它主要的特点就是操作基本数据类型。

    实例:

    1. * DataInputStreamDataOutputStream
    2. *
    3. * 可以用于操作基本数据类型的数据的流对象。
    4. */
    5. public class DataStreamDemo {
    6. public static void main(String[] args) throws IOException {
    7. // write();
    8. // read();
    9. // writeUTF();
    10. readUTF();
    11. //一般加入编码的方法
    12. // OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"utf-8");
    13. // osw.write("你好");
    14. // osw.close();
    15. }
    16. public static void write() throws IOException{
    17. DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
    18. dos.writeInt(236);
    19. dos.writeBoolean(false);
    20. dos.writeDouble(2323.02154);
    21. dos.close();
    22. }
    23. public static void read() throws IOException{
    24. DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
    25. int i = dis.readInt();
    26. boolean b = dis.readBoolean();
    27. double d = dis.readDouble();
    28. System.out.println("int: " + i);
    29. System.out.println("boolean: " + b);
    30. System.out.println("double: " + d);
    31. dis.close();
    32. }
    33. //加入了改编后的UTF-8编码,所以只有它自己能读
    34. public static void writeUTF() throws IOException{
    35. DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
    36. dos.writeUTF("你家婆");
    37. dos.close();
    38. }
    39. public static void readUTF() throws IOException{
    40. DataInputStream dis = new DataInputStream(new FileInputStream("utf.txt"));
    41. String s = dis.readUTF();
    42. System.out.println(s);
    43. dis.close();
    44. }
    45. }



    第七  ByteArraytStream(操作数组的流)

    一、概述:

    ByteArrayInputStream :在构造的时候,需要接收数据源,而且数据源是一个字节数组。

    ByteArrayOutputStream: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组,这就是数据目的地。

    参数是字节数组,访问网络写的是字节,需要new string(bos.tobyteArray)

    注:因为这两个流对象都操作的数组,并没有使用系统资源。所以,不用进行close关闭,而且关闭也是无效的。

    源设备,
      键盘 System.in,硬盘 FileStream,内存 ArrayStream
      目的设备:
       控制台 System.out,硬盘FileStream,内存 ArrayStream。

    1. public class ByteArrayStreamDemo {
    2. public static void main(String[] args) {
    3. //数据源
    4. ByteArrayInputStream bis = new ByteArrayInputStream("defef".getBytes());
    5. //目的地
    6. ByteArrayOutputStream bos = new ByteArrayOutputStream();
    7. int ch = 0;
    8. while((ch=bis.read()) != -1){
    9. bos.write(ch);
    10. }
    11. System.out.println(bos.size());
    12. System.out.println(bos.toString());
    13. try {
    14. //将此 byte 数组输出流的全部内容写入到指定的输出流参数中
    15. bos.writeTo(new FileOutputStream("b.txt"));
    16. } catch (FileNotFoundException e) {
    17. e.printStackTrace();
    18. } catch (IOException e) {
    19. e.printStackTrace();
    20. }
    21. }
    22. }


    第八  字符编码

    一、‘常见的编码表:

    1、ASCII:美国标准信息交换码表。用一个字节的7位表示

    2、IOS8859-1:拉丁码表;欧洲码表。用一个字节的8位表示

    3、GB2312:中国的中文编码表

    4、GBK:中国的中文编码表升级,融合了更多的中文文字字符。打头的是两个高位为1的两个字节编码。为负数

    5、Unicode:国际标准码,融合了多种文字

    6、UTF-8:升级版国际码表,是可变长度的码表。最多用三个字节表示一个字符的编码表,包括:一位、两位、三位表示的字符

          UTF-8有自己的字节码:

    一个字节:0开头

    两个字节:字节一  ---> 110     位数:10 ~ 6

                        字节二  --->  10      位数:5 ~ 0

    三个字节:字节一  ---> 1110     位数:15 ~ 12

                        字节二  --->  10      位数:11 ~ 6

                        字节三 --->  10       位数:5 ~ 0

    二、编码和解码:

    1、编码:字符串变成字节数组

          解码:字节数组变成字符串

    2、转换:

    1)默认字符集:

          String  --->  byte[]   :srt.getBytes()

          byte[]   --->  String  :new String(byte[])

    2)指定字符集:

          String  --->  byte[]   :srt.getBytes(charsetName)

          byte[]   --->  String  :new String(byte[],charsetName)

    三、对于编码和解码的字符集转换

    1、如果编码失败,解码就没意义了。

    2、如果编码成功,解码出来的是乱码,,则需对乱码通过再次编码(用解错码的编码表),然后再通过正确的编码表解码。针对于IOS8859-1是通用的。

    3、如果用的是GBK编码,UTF-8解码,那么再通过2的方式,就不能成功了,因为UTF-8也支持中文,在UTF-8解的时候,会将对应的字节数改变,所以不会成功。

    特别注意:对于中文的”联通“,这两个字比较特别,它的二进制位正好是和在UTF-8中两个字节打头的相同,可以找到对应的符号,但不再是”联通“了。

    但是只要他前面还有其他汉字就不会被被UTF-8解码了,也就不会出现乱码了。

      1. * 编码:字符串变成字节数组。
      2. * 解码:字节数组变成字符串。
      3. * String-->byte[]; str.getBytes(charsetName);
      4. * byte[] -->String: new String(byte[],charsetName);
      5. */
      6. public class EncodeDemo {
      7. public static void main(String[] args) {
      8. method();
      9. }
      10. public static void show() {
      11. String s = "你好";
      12. try {
      13. byte[] b = s.getBytes("GBK");
      14. System.out.println(Arrays.toString(b)); // printBytes(buf);
      15. String str = new String(b, "iso8859-1");// 编码正确,解码错误
      16. System.out.println(str);
      17. // 对str进行iso8859-1编码。以这样的方式解决乱码
      18. byte[] b1 = str.getBytes("iso8859-1");
      19. System.out.println(Arrays.toString(b1));
      20. String str1 = new String(b1, "GBK");
      21. System.out.println(str1);
      22. } catch (UnsupportedEncodingException e) {
      23. e.printStackTrace();
      24. }
      25. }

      
      1. /*
      2. * 联通
      3. */
      4. public static void method() {
      5. String s = "联通";
      6. try {
      7. byte[] bs = s.getBytes("GBK");
      8. for (byte b : bs) {
      9. // Integer.toBinaryString将其转换为二进制,&255取出前面多余的1,保留最低8位
      10. // 联通的二进制是110...10...110...10...这个刚好符合utf-8的读取两个字节的编码形式,
      11. // 所以当度存在会被默认为utf-8编码来解读,从而造成乱码
      12. /*
      13. * 'u0001' 到 'u007F' 范围内的所有字符都是用单个字节表示的:
      14. *
      15. * 位值 字节一 0 位 6-0
      16. *
      17. *
      18. * null 字符 'u0000' 以及从 'u0080' 到 'u07FF' 的范围内的字符用两个字节表示:
      19. *
      20. * 位值 字节一 1 1 0 位 10-6
      21. *
      22. * 字节二 1 0 位 5-0
      23. *
      24. * 'u0800' 到 'uFFFF' 范围内的 char 值用三个字节表示: 字节一 1 1 1 0 位
      25. * 15-12
      26. *
      27. * 字节二 1 0 位 11-6
      28. *
      29. * 字节三 1 0 位 5-0
      30. */
      31. System.out.println(Integer.toBinaryString(b & 255));
      32. }
      33. } catch (UnsupportedEncodingException e) {
      34. e.printStackTrace();
      35. }
      36. }
      37. }
    练习:
    1. public class Test {
    2. public static void main(String[] args) throws IOException {
    3. String str = "ab你好cd谢谢";
    4. // str = "ab琲琲cd琲琲";
    5. // int len = str.getBytes("gbk").length;
    6. // for(int x=0; x<len; x++){
    7. // System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByByte(str, x+1));
    8. // }
    9. int len = str.getBytes("utf-8").length;
    10. for(int x=0; x<len; x++){
    11. System.out.println("截取"+(x+1)+"个字节结果是:"+cutStringByU8Byte(str, x+1));
    12. }
    13. // String str = "琲";
    14. // byte[] buf = str.getBytes("gbk");
    15. // for(byte b : buf){
    16. // System.out.println(b);//-84 105
    17. // }
    18. }
        在java中,字符串“abcd”与字符串“ab你好”的长度是一样,都是四个字符。
      但对应的字节数不同,一个汉字占两个字节。
      定义一个方法,按照最大的字节数来取子串。
      如:对于“ab你好”,如果取三个字节,那么子串就是ab与“你”字的半个,
      那么半个就要舍弃。如果去四个字节就是“ab你”,取五个字节还是“ab你”.
      
    1. public static String cutStringByU8Byte(String str, int len) throws IOException {
    2. byte[] buf = str.getBytes("utf-8");
    3. int count = 0;
    4. for(int x=len-1; x>=0; x--){
    5. if(buf[x]<0)
    6. count++;
    7. else
    8. break;
    9. }
    10. if(count%3==0)
    11. return new String(buf,0,len,"utf-8");
    12. else if(count%3==1)
    13. return new String(buf,0,len-1,"utf-8");
    14. else
    15. return new String(buf,0,len-2,"utf-8");
    16. }
    17. public static String cutStringByByte(String str,int len) throws IOException{
    18. byte[] buf = str.getBytes("gbk");
    19. int count = 0;
    20. for(int x=len-1; x>=0; x--){
    21. if(buf[x]<0)
    22. count++;
    23. else
    24. break;
    25. }
    26. if(count%2==0)
    27. return new String(buf,0,len,"gbk");
    28. else
    29. return new String(buf,0,len-1,"gbk");
    30. }
    31. }
    32. }



    练习

    五个学生,每个学生有3门课程的成绩,从键盘输入以上数据(姓名,三门课成绩),

    输入格式:如:zahngsan,30,40,60计算出总成绩,并把学生的信息和计算出的总分数高低按顺序存放在磁盘文件stud.txt中

    步骤:
    1、描述学生对象
    2、定义一个可操作学生对象的工具类

    思路:
    1、通过获取键盘录入一行的数据,并将该行数据的信息取出,封装成学生对象
    2、因为学生对象很多,则需要存储,使用集合,因为要对学生总分排序
    所以可以使用TreeSet
    3、将集合中的信息写入到一个文件中

    1. public class StudentInfoTest {  
    2.     public static void main(String[] args) {  
    3.         try {  
    4.             Comparator<StudentInfo> cmp = Collections.reverseOrder();// 强行反正比较顺序  
    5.             // Set<StudentInfo> stus = StudentInfoTool.getStudents();//默认比较  
    6.             Set<StudentInfo> stus = StudentInfoTool.getStudents(cmp);// 自定义比较器  
    7.             StudentInfoTool.write2File(stus);//调用写方法,将数据写文件中去  
    8.         } catch (IOException e) {  
    9.             e.printStackTrace();  
    10.         }  
    11.     }  
    12. }  
    13.   
    14. class StudentInfo implements Comparable<StudentInfo> {  
    15.   
    16.     private String name;// 姓名  
    17.     private int ma, cn, en;// 数学、语文、英语成绩  
    18.     private int sum;// 总分  
    19.   
    20.     //初始化就需要具备姓名,数学、语文、英语成绩  
    21.     StudentInfo(String name, int ma, int cn, int en) {  
    22.         this.name = name;  
    23.         this.ma = ma;  
    24.         this.cn = cn;  
    25.         this.en = en;  
    26.   
    27.         sum = ma + cn + en;//计算出总成绩  
    28.     }  
    29.   
    30.     public String getName() {  
    31.         return name;  
    32.     }  
    33.   
    34.     public void setName(String name) {  
    35.         this.name = name;  
    36.     }  
    37.   
    38.     public int getMa() {  
    39.         return ma;  
    40.     }  
    41.   
    42.     public void setMa(int ma) {  
    43.         this.ma = ma;  
    44.     }  
    45.   
    46.     public int getCn() {  
    47.         return cn;  
    48.     }  
    49.   
    50.     public void setCn(int cn) {  
    51.         this.cn = cn;  
    52.     }  
    53.   
    54.     public int getEn() {  
    55.         return en;  
    56.     }  
    57.   
    58.     public void setEn(int en) {  
    59.         this.en = en;  
    60.     }  
    61.   
    62.     public int getSum() {  
    63.         return sum;  
    64.     }  
    65.   
    66.     public void setSum(int sum) {  
    67.         this.sum = sum;  
    68.     }  
    69.   
    70.     @Override  
    71.     public int compareTo(StudentInfo o) {//建立自己的比较方法  
    72.         int num = new Integer(this.sum).compareTo(new Integer(o.sum));//比较分数  
    73.         if (num == 0) {  
    74.             return this.name.compareTo(o.name);//主条件相同判定次要条件  
    75.         }  
    76.         return num;//返回比较的值,大于正数,相同0,小于负数  
    77.     }  
    78.   
    79.     @Override  
    80.     public int hashCode() {//重写hashcode方法是因为数据有可能存到hashtable中  
    81.         return name.hashCode() + sum * 23;//尽可能保证hashcode值不相同,减少比较次数  
    82.     }  
    83.   
    84.     @Override  
    85.     public boolean equals(Object obj) {//建立自己独有的判断相同方式  
    86.         if (!(obj instanceof StudentInfo)) {  
    87.             throw new ClassCastException("类型不匹配");  
    88.         }  
    89.   
    90.         StudentInfo si = (StudentInfo) obj;  
    91.         return this.name.equals(si.name) && this.sum == si.sum;//姓名和总分相同视为同一人  
    92.     }  
    93.   
    94.     @Override  
    95.     public String toString() {//建立自己的toString方法  
    96.         return "studentinfo[" + name + ", " + ma + ", " + cn + ", " + en + "]";  
    97.     }  
    98. }  
    99.   
    100. class StudentInfoTool {  
    101.     //定义默认比较顺序  
    102.     public static Set<StudentInfo> getStudents() throws IOException {  
    103.   
    104.         return getStudents(null);  
    105.     }  
    106.   
    107.     //定义自定义的比较顺序  
    108.     public static Set<StudentInfo> getStudents(Comparator<StudentInfo> cmp)  
    109.             throws IOException {  
    110.         BufferedReader bfr = new BufferedReader(  
    111.                 new InputStreamReader(System.in));  
    112.   
    113.         Set<StudentInfo> stus = null;  
    114.         if (cmp == null) {  
    115.             stus = new TreeSet<StudentInfo>();  
    116.         } else {  
    117.             stus = new TreeSet<StudentInfo>(cmp);  
    118.         }  
    119.         String line = null;  
    120.         while ((line = bfr.readLine()) != null) {  
    121.             if ("over".equals(line)) {  
    122.                 break;  
    123.             }  
    124.             String[] info = line.split(",");//将数据以“,”切开,形成新的数据  
    125.   
    126.             StudentInfo si = new StudentInfo(info[0],  
    127.                     Integer.parseInt(info[1]), Integer.parseInt(info[2]),  
    128.                     Integer.parseInt(info[3]));  
    129.   
    130.             stus.add(si);  
    131.         }  
    132.   
    133.         bfr.close();  
    134.         return stus;  
    135.     }  
    136.   
    137.     public static void write2File(Set<StudentInfo> stus) throws IOException {  
    138.         BufferedWriter bfw = new BufferedWriter(new FileWriter("stuinfo.txt"));  
    139.   
    140.         for (StudentInfo si : stus) {  
    141.             bfw.write(si.toString() + " ");  
    142.             bfw.write(si.getSum() + "");  
    143.             bfw.newLine();  
    144.             bfw.flush();  
    145.         }  
    146.   
    147.         bfw.close();  
    148.     }  
    }  





  • 相关阅读:
    1.从Node.js链接到MongoDB
    2.mongoDB add user in v3.0 问题的解决(Property 'addUser' of object admin is not a func)
    汇编——模拟试卷二
    汇编——模拟试卷一
    汇编语言——数据处理的两个基本问题(处理的数据在什么地方 要处理的数据有多长)
    汇编语言——更灵活的定位内存地址的方法
    汇编语言——包含多个段的程序
    汇编语言——[bx]和loop指令
    汇编语言——汇编程序从写出到最终执行的过程
    汇编语言——编译器
  • 原文地址:https://www.cnblogs.com/sixrain/p/4912423.html
Copyright © 2020-2023  润新知