(十二)Core Java IO流(Properties,序列化,管道流,字符编码)-03 (108)
42 ). IO流(Properties简述)43 ). IO流(Properties存取)44 ). IO流(Properties存取配置文件)45 ). IO流(Properties练习)46 ). IO流(PrintWriter)47 ). IO流(合并流)48 ).IO流(切割文件)49 ).IO流(对象的序列化)50 ). IO流(管道流)51 ). IO流( RandomAccessFile)52 ). IO流( 操作基本数据类型的流对象DataStream)53 ). IO流(ByteArrayStream)54 ). IO流(转换流的字符编码)55 ).字符编码56 ).字符编码-联通57 ).练习
1 ) . 本文讲述 如何将 指定目录中的文件递归到集合,然后从集合通过字符流写入到指定目标地址文件2 ) . Demo:/*本章讲述 :需求 : 将一个指定目录下的java文件的绝对路径,存储到一个文本文件中也就是建立一个java文件列表清单步骤:1.对指定的目录进行递归2.获取递归过程所有的java文件的路径3.将这些路径存储到集合中4,将集合中的数据写入到一个文件中*/import java.io.*;import java.util.*;class javaFileList{public static void sop(Object obj){System.out.println(obj);}//将指定目录下的文件放入指定集合中public static void fileToList(File file,List<File> list){//获取遍历文件对象的类File[] file1 = file.listFiles();//遍历文件对象for(File fi : file1){//判断是否是目录if(fi.isDirectory())fileToList(fi,list); //是目录继续递归遍历else{ if(fi.getName().endsWith(".java")); //是文件再判断是否是.java文件list.add(fi); //是.java文件则添加入集合}}}//用来将集合中的文件绝对路径放入指定地址文件的方法public static void getFileList(List<File> list,String name) throws IOException{//因为文件内是字符串涉及数据因此用字符流BufferedWriter bw= null;try{bw=new BufferedWriter(new FileWriter(name));//将list集合中数据遍历出for(File fi : list){String path = fi.getAbsolutePath(); //获取文件绝对路径bw.write(path); //写入目标地文件内bw.newLine(); //换行bw.flush(); //刷新}}catch(IOException o){throw o;}finally{try{if(bw!=null)bw.close();}catch(IOException o){throw o;}}}//主方法public static void main(String args[]) throws IOException{//初始化文件对象的目标地File fi1 = new File("S:\\develop\\JavaText");//初始化一个存文件的集合List<File> li =new ArrayList<File>();//调用文件存储到集合的方法fileToList(fi1,li);File fi2= new File("S:\\develop\\JavaText\\myJavaList.txt"); //指定一个目标存放地文件getFileList(li,fi2.toString()); //将list集合与目标存放地一并传入//打印集合大小sop(li.size());}}
小结 :1. 数据存储在内存时临时存储,数据存储在硬盘式数据的持久化存储2. 数组有长度,集合有大小
1 ) . Properties
1.1 配置文件中的数据大多是以键值对的方式存在的,因此Properties是HashTable 的子类1.2 特点 : Properties不仅可以操作键值对(设计Map体系),还可操作硬盘上(涉及IO流)的键值对
2 ) . 案例解说 : 当我们对一个软件的相关用户信息进行更改时,是在内存中更改的,而正常情况退出后,更改就失效了, 而如何让下次打开软件还是自己上次配置的,就用到了软件配置信息文件,我们通过更改配置信息文件中的数据而完成数据持久化,再启动软件之前先访问这个配置文件信息
2.1 通俗讲 : 想要当软件的配置每次打开都是上次配置的,那就需要将配置文件信息数据持久化,每次打开软件都会访问一次配置文件3 ). Demo:/*本章讲述 :Properties是hashtable的子类,也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串Properties是集合中和IO技术相结合的集合容器该对象的特点是:可以用于键值对形式的配置文件*/
小结 :1. 当我们操作硬盘上的键值对文件时,便要想到Properties类
1 ) . Properties 存 setProperty() 设置一对 : getProerty() 取一个 , stringPropertyNames() 取一堆2 ) . Demo:/*本章讲述 :Properties类 : 是集合中与IO技术相结合的容器setProperty(): 用来设置Properties类中的键值对getProerty() : 用来通过键获取properties类中的值stringPropertyNames() : 用来获取properties类中所有的键,返回值是set类型*/import java.io.*;import java.util.*;class PropertiesDemo{public static void sop(Object obj){System.out.println(obj);}public static void getAndSet(){Properties pro =new Properties(); //初始化资源集合类pro.setProperty("summer","hot"); //设置资源键值对pro.setProperty("winter","cold");String value = pro.getProperty("summer"); //通过键获取值//sop("sumer:"+value); //输出值Set<String> keys = pro.stringPropertyNames(); //获取资源集合类中所有键for(String key : keys) //迭代键{sop(key+"::"+pro.getProperty(key)); //输出所有键值}}//主方法public static void main(String args[]) throws IOException{getAndSet();}}
1 ) . Properties存取配置文件 : 用到了资源类中的 load () 加载 和 store()存储方法2 ) . Demo:/*本章讲述 :演示 :如何将流中的数据存储到集合中案例 : 将info.txt文件中的键值对信息存储到集合中进行操作步骤 :[1] 用一个流和info.txt文件关联[2] 读取一行数据,将该行数据用"="进行切割[3] 等号左边作为键,右边作为值,存入到Properties集合中即可方法:properties类中的load() : 用来将字符/字节流指定文件中数据加载到资源类中properties类中的store() : 用来将资源类中的数据存储到字符/字节流指定文件中使用这两个方法都需要 初始化相关的流对象*/import java.io.*;import java.util.*;class PropertiesDemo1{public static void sop(Object obj){System.out.println(obj);}//将磁盘文件信息读取到资源类调用已有工具方法实现public static void readInfo1() throws IOException{BufferedReader br = new BufferedReader(new FileReader("info.txt")); //初始化一个字符流读对象与目标地址相关联Properties pro = new Properties(); //初始化一个集合资源文件类用来存储信息pro.load(br); //用来将目标地的文件信息加载进入 资源文件类pro.setProperty("winter","100"); //设置更改资源类中的键值对BufferedWriter bw =new BufferedWriter(new FileWriter("info.txt")); //初始化一个字符流写对象与目标地址相关联pro.store(bw,"zhangxiaozong"); //将资源类中存储的信息写入到目标地址内,并且需要携带备注信息sop(pro);}//将磁盘文件信息读取到资源类原理public static void readInfo() throws IOException{BufferedReader br = new BufferedReader(new FileReader("info.txt")); //初始化一个字符流读对象与目标地址相关联String line=null;Properties pro = new Properties(); //初始化一个集合资源文件类用来存储信息while((line=br.readLine())!=null) //遍历目标地信息{String[] str = line.split("="); //以==为标识符切割pro.setProperty(str[0],str[1]); //切割后以键值对的方式放入资源文件类}sop(pro);}//主方法public static void main(String args[]) throws IOException{//readInfo();readInfo1();}}小结 :1. properties类操作数据的固定格式 : 键 = 值2. 我们平时的操作是在内存中操作,程序一旦关闭,及恢复默认,若需永久更改,则需更改本地配置文件
1 ) . 练习 : 用来设置程序可免费执行的次数2 ) . Demo:/*本章讲述 :练习 : 用于记录应用程序运行次数,若使用次数已到规定次数,则给出注册提示思考条件:[1] 次数自增 -->计数器[2] 不随程序的结束而修改消失 -->存储硬盘配置文件得出 : 用一个键值对的形式存储到硬盘上的配置文件,在程序开启时便加载即可 ,使用集合中的IO技术 : Map + IO = properties类*/import java.io.*;import java.util.*;class PropertiesDemo2{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]) throws IOException{Properties prop = new Properties(); //初始化资源类用来加载和存储信息File file =new File("S:\\develop\\JavaText\\info.properties"); //初始化文件类 用来指定地址if(!file.exists()) //判断文件是否存在file.createNewFile(); //不存在则创建BufferedReader br =new BufferedReader(new FileReader(file)); //将文件放入字符流读的类中prop.load(br); //将指定地址文件中的数据加载到资源类int count =0; //定义计数器String value = prop.getProperty("count"); //获取本地文件类中count的值if(value!=null) //判断值是否为空,不为空时进入操作{count = Integer.parseInt(value); //将字符串换算为数值if(count>=5){sop("您好,使用次数已到,请拿钱");}}count++; //为空时自动++prop.setProperty("count",count+""); //将 计数器的键值 放入 资源类BufferedWriter bw =new BufferedWriter(new FileWriter(file)); //初始化文件字符流写的类prop.store(bw,"xiaoqinagqiang"); //资源类中的数据写入到字符流写的类中的指定文件地址}}3 ) . 常见的两种配置文件 : .properties 与 .xml
3.1 区别 : .properties 讲究唯一性 ,最好存储 键值对都是唯一的 ;而 .xml中讲究多样性, 一个键可多个值 ,可操作关系复杂的情况3.2 共同点 : .properties 与 .xml都是配置文件,而且 内格式都是 键值对3.3 操作.properties的类是 properties , 操作 .xml的类是 document ,但是这个类不好操作,于是出现了 dom4j3.4 dom4j 是 java的xml API,用来读写xml文件的
小结 :1. 配置文件可以实现应用程序之间的共享2. 目前常见的两种配置文件: .properties 与 .xml
1 ) . IO包中的其他类 :
1.1 打印流 : PrintWriter与PrintStream -->可以直接操作输入流和文件1.2 序列流 : SequenceInputStream -->对多个流进行合并1.3 操作对象 : ObjectInputStream与ObjectOutputStream --> 被操作的对象需要实现Serializable(标记接口)1.4 练习 : 文件分割程序
2 ) . Demo :/*本章讲述 : 打印流 : 该流提供了打印方法,可将各种数据类型的数据都原样打印分类:1.字节打印流: PrintStream构造函数可接收的参数类型 :1.file对象,File2.字符串路径 String3.字节数据流 OutputStream2. 字符打印流 : PrintWriter -->常用构造函数可接收的参数类型 :1.file对象,File2.字符串路径 String3.字节数据流 OutputStream4.字符输出流 Writer小结 : 字符打印流的厉害之处在于 他的构造函数 可传 文件,我们常用字符打印流操作*/import java.io.*;import java.util.*;class PrintWriterDemo{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]) throws IOException{//初始化一个字符流读对象,并把源头设为 键盘输出BufferedReader br =new BufferedReader(new InputStreamReader(System.in));//初始化一个输出写对象,并把目的设为控制台,并自动刷新// PrintWriter pw =new PrintWriter(System.out,true); //这里加 true 的原因是 : println,printf或format 使用时会自动刷新//初始化一个输出写对象,并把目的设为磁盘文件,并自动刷新PrintWriter pw =new PrintWriter(new FileWriter("1.txt"),true);String str=null;while((str=br.readLine())!=null){if(str.equals("over"))break;pw.println(str.toUpperCase()); //将输出的内容大写}pw.close();br.close();}}
小结 :1. PrintWriter 直接对文件进行操作更加便捷
1 ) . 应用场景 : 多个文件数据合并成一个文件时用到合并流2 ) . Demo:/*本章讲述 : 合并流 : 该流提供了让多个流合并成一个流的方式,也就是让流串联起来理解:[1] 序列 : 就是有序的排列,指串联,比如合并流就是序列流,也是序列的一种体现方式 ,序列通常应用于 音乐信息[2] 枚举 : 让各个对象的元素得以连续存入,一次一个SequenceInputStream : 合并流的方法前提 :[1] 需先将流对象存入Vector集合[2] 采用vector集合中方法elements 让其元素得以连续,返回值是 枚举Enumeration[3] 将元素放入序列流中进行排序合并为一流*/import java.io.*;import java.util.*;class SequenceDemo{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]) throws IOException{Vector<FileInputStream> v = new Vector<FileInputStream>(); //初始化一个用来装流的集合//向集合内添加流对象v.add(new FileInputStream("summer.txt")); //文件必须现实存在v.add(new FileInputStream("winter.txt"));v.add(new FileInputStream("spring.txt"));//将集合内的元素存入一个枚举类型泛型是读流的类中 -->枚举是得到连续数据的手段Enumeration<FileInputStream> en = v.elements();SequenceInputStream sis =new SequenceInputStream(en); //初始化序列流对象,将刚才枚举对象中的流合并为一个流FileOutputStream fos =new FileOutputStream("autumn.txt"); //初始化一个文件写出流byte[] buf =new byte[1024]; //定义临时存储区int len=0;while((len=sis.read(buf))!=-1) //读取序列流中数据{fos.write(buf,0,len); //将序列流中数据读取到文件写出流中}fos.close(); //关闭文件写出流sis.close(); //关闭序列流}}小结 :1. 多个源对应一个目标地时,采用合并流,合并流就是将流串联了起来,将最后一个流的返回值当做结束标识符
1 ) . 本章讲述了 切割与合并 ,合并最重要的是用 好 Enumeration枚举对象2 ) . Demo:/*本章讲述 : 切割流 : 该流提供了让一个流切割成多个流的方式切割原理 : 就是 拿一个容器,容器满了再换个容器,也就是换了个文件,具体实现通过while 循环+ close 关流操作 完成当我们做合并流时,最重要的是使用SequenceInputStream ,而它 只接受参数 Enumeration ,因此 需要放入集合,集合数据再放入Enumeration,然后Enumeration再放入SequenceInputStream总结 : Java 获取Enumeration类型的集合方法 有两种:[1] 通过vector集合获得,详细见上一章,但不高效[2] 通过List集合+iterator+匿名内部类的方法实现*/import java.io.*;import java.util.*;class SplitDemo{public static void sop(Object obj){System.out.println(obj);}//切割方法public static void splitFile() throws IOException{FileInputStream fis =new FileInputStream("S:\\develop\\JavaText\\Beyond.mp3"); //初始化文件读取流并关联地址FileOutputStream fos = null; //为文件写出流做外部引用byte[] buf =new byte[1024*1024*3]; //定义一个数组容器,大小为3个MBint len=0; //用来临时存储数据int count =0 ; //用来为文件夹计数while((len=fis.read(buf))!=-1) //读取数据{fos =new FileOutputStream("S:\\develop\\JavaText\\part\\Beyond"+(count++)+".part"); //初始化文件写出流并动态关联地址fos.write(buf,0,len); //写入数据fos.close(); //关流,意味着 文件写出流中只有3MB数据写入到了文件中,再次循环则会再次创建文件}fis.close();}//合并方法public static void merge() throws IOException{ArrayList<FileInputStream> al =new ArrayList<FileInputStream>(); //初始化集合用来存文件读入流for(int i=0;i<=3;i++){al.add(new FileInputStream("S:\\develop\\JavaText\\part\\Beyond"+i+".part")); //将文件读入流对象动态加入ArrayList集合}final Iterator<FileInputStream> it = al.iterator(); //获取迭代器//这里是通过匿名内部类的方式实现其所有抽象方法来完成实例化,Enumeration 与 ArrayList 的关联是 依靠 迭代器 ,请看 点击下边 itEnumeration<FileInputStream> en = new Enumeration<FileInputStream>() //创建枚举对象,将集合中元素存入,以便序列流使用{public boolean hasMoreElements() //复写其测试此枚举是否包含更多元素的方法{return it.hasNext();}public FileInputStream nextElement() //复写其如果此枚举对象至少有一个要提供的元素,则返回此枚举的下一个元素的方法{return it.next();}};//------------以上都是为了获取下边的这一句合并流的类SequenceInputStream sis =new SequenceInputStream(en); //获取序列流用来多流合一FileOutputStream fos =new FileOutputStream("S:\\develop\\JavaText\\part\\Beyond.mp3"); //初始化一个写出流并关联目标地址byte[] buf =new byte[1024]; //定义一个数组容器int len=0; //定义临时容器,用于判断是否到末尾while((len=sis.read(buf))!=-1) //向将序列流中的数据装入数组容器中{fos.write(buf,0,len); //将 数组容器中数据装入写出流的指定目标地中}fos.close(); //关闭写出流sis.close(); //关闭序列流}//主方法public static void main(String args[]) throws IOException{// splitFile(); //分割流方法merge(); //合并流方法} }小结 :1. 一个源对应是三个目标地是切割,三个源对应一个目标地是合并
1 ) . 序列化就是给对象起标识符存入介质的过程2 ) . 案例解说 : 关于用户基本信息存储需要用到操作对象流的问题
2.1 初始化对象之后正常是存在内存中,程序结束之后调用GC进行垃圾回收,内存内数据消失 ;而 一些账户基本信息是不能消失的, 因此 要将其存入可持久化的介质(硬盘),这时 考虑到 IO流,但基本IO流是用来处理数据的,这时需处理对象, 需要用到 ObjectInputStream,ObjectOutputStrean 这是操作对象的流, 前提是 操作的对象需要被 序列化(实现serializable接口),也就是 为对象劳个章(起个UID,标识一下)
3 ) . Demo:/*本章讲述 : 操作对象的流对象 , 被操作的对象需要实现Serializable(标记接口)[1] ObjectInputStream : 用来读取对象[2] ObjectOutputStream : 用来写出对象[3]Serializable : 启用其序列化功能的接口,仅用来表示序列化对象[4] transient : 该标识符标识到变量前,可让其变脸不参与序列化,但存在于堆内存中[5] 一般存储序列化对象的文件名格式是 : 对象名.object1.为何要序列化?只有序列化后才可使用操作流对象,另外序列化后让对象存储时有一个uid去标识,这样在获取时方便2.UUID是如何算出来的?无论任何一个类中的属性参数其实都是具有标识的,UUID就是通过这些标识值算出来的,用来标识自己的类对象,因此唯一性非常之高须知 :[1]静态是不能被序列化的,序列化的是堆内的数据,而静态是在静态区中的[2] 用ObjectOutputStream写出,必须 用他ObjectInputStream才能读入,两者成对存在的*/import java.io.*;import java.util.*;class ObjectInputStreamDemo{public static void sop(Object obj){System.out.println(obj);}//读对象方法public static void readObject() throws Exception{ObjectInputStream ois =new ObjectInputStream(new FileInputStream("obj.txt")); //初始化一个对象读入流,并关联字节读入流的目标地址Person per =(Person) ois.readObject(); //读取目标地址中的对象与person关联sop(per); //输出}//写对象方法public static void writeObje() throws IOException{ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("obj.txt")); //初始化一个对象写出流,并关联字节写出流的目标地址oos.writeObject(new Person("summer",13)); //初始化一个对象,将对象写入到对象写出流中,写出流会写入到关联的字节写出流的目标地址内oos.close(); //关闭对象写出流}//主方法public static void main(String args[]) throws Exception{// writeObje();readObject() ;}}class Person implements Serializable //对象的可串行化-->指对象序列化 //默认的实现此接口 会自动为该类赋予一个UUID,没初始化一次便更新一次UUID{public static final long serialVersionUID=42L; //serialVersionUID : 这个名字是特定的,一旦写错则自定义UUID失败private String name;transient int age; //意味着 该变量不被序列化Person(String name,int age){this.name=name;this.age=age;}public void setName(String name){this.name=name;}public String getName(){return name;}public void setAge(int age){this.age=age;}public int getAge(){return age;}}
小结 :1. 对象的持久化就是将对象信息存储到可长期保存的介质上,也就是对象的序列化2. 我们可通过对象的系列化进行对象的重构,意味着将对象信息存储到硬盘,然后下次使用然后再读出来3. 没有方法的接口通常称为标记接口 ,比如 Serializable 可串行化接口4. 序列化的作用就是给类定义一个固定标识,就是为了使用操作对象流方便
1 ) . 简述 :
1.1 RandomAccessFile
[1] 随机访问文件,自身具备读写方法[2] 通过skipBytes(int x),seek(int x)来达到随机访问
1.2 管道流 : PipedInputStream和PipedOutputStream
[1] 输入输出可以直接进行连接,通过结合线程使用[2] 认识 : 以前的流需要输入流输出流两个流操作.并且两者没关系; 现在一个管道流就可搞定,内含输入输出
2 ) . Demo :/*本章讲述 : 操作线程的流是 PipedInputStream与PipedOutputStream ,这两者之间可以相连接组成管道流//测试read与writer两个线程的运行先后顺序 ,下边有输出语句用来测试 线程运行的先后顺序*/import java.io.*;import java.util.*;class RandomAccessFileDemo{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]) throws Exception{PipedInputStream in =new PipedInputStream(); //实例化管道流的读入流对象PipedOutputStream ou =new PipedOutputStream(); //实例化管道流的写入流对象Read rd =new Read(in); //将读入流放入读方法Writer wr =new Writer(ou); //将写入流放入写方法in.connect(ou); //让其两个管道流相连接new Thread(rd).start(); //启动读方法new Thread(wr).start(); //启动写方法}}//可写的线程对象class Writer implements Runnable{private PipedOutputStream ou ; //管道流的可写流 ,在可写线程一实例化变出现Writer(PipedOutputStream ou){this.ou=ou;}public void run () //启动线程的方法{try{System.out.println("开始写入数据......."); //测试read与writer两个线程的运行先后顺序ou.write("piped a lai le".getBytes()); //往管道流的写流中写入数据ou.close(); //关闭可写流}catch(IOException e){throw new RuntimeException("管道流读取失败"); //抛出异常}}}//可读的线程对象class Read implements Runnable{private PipedInputStream in ; //管道流的可读流 ,在可读线程一实例化变出现Read(PipedInputStream in){this.in=in;}public void run () //启动线程的方法{try{byte[] buf= new byte[1024]; // 定义临时存储数据容器System.out.println("读取前,目前没有数据产生"); //测试read与writer两个线程的运行先后顺序int len =in.read(buf); //将读出的数据放入数组,并返回长度System.out.println("已读到数据,堵塞结束"); //测试read与writer两个线程的运行先后顺序String s =new String(buf,0,len); //将数据放入字符串System.out.println(s); //打印字符串in.close(); //关闭可读流}catch(IOException e){throw new RuntimeException("管道流读取失败"); //抛出异常}}}
小结 :1. 可以对接到一起的流对象就是管道流2. 集合当中涉及到IO流的是Properties , IO流当中涉及到多线程的就是PipedInputStream
1 ) . RandomAccessFile : 随机文件的读取和写入 -->其中涉及到一个案例是 下载软件的原理2 ) . Demo:/*本章讲述 :RandomAccessFile: 该类支持对随机文件的读取和写入特点:[1] 该类不是IO体系中子类,是Object的子类; 但由于它具备读写功能,因此是IO包中成员[2] 该类内部封装了一个数据,可通过指针对数据的元素进行操作[3] 该类可通过getFilePointer获取指针位置,通过seek改变指针的位置[4] 该类通过构造函数可看出,只能操作文件,而且操作文件时还得传入模式参数:例如: 只读r ,读写rw等解析 : 他为何可完成读写? 因为内部封装了字节输入流和输出流方法 :seek(); 调整指针指向的坐标skipBytes(); 跳过指定字节数write(); 向随机访问流对象内写数据read(); 读取随机访问流对象的数据小结 :[1] 若模式为只读r,则不会创建文件,会去读取一个已存在文件,若该文件不存在,则会出现异常[2] 若模式为读写rw,操作的文件不存在时,会自动创建,若存在则不会覆盖*/import java.io.*;import java.util.*;class RandomAccessFileDemo{public static void sop(Object obj){System.out.println(obj);}public static void getRead()throws Exception{RandomAccessFile raf =new RandomAccessFile("ran.txt","r"); //初始化随机访问流对象//该方法是调整指针,动态的获取文件中任何地方的数据,前提是文件中的数据有规律// raf.seek(8*0); //这里存储的数据是 8 个字节的 ,若要让指针指到下一个坐标,即可获取下一个 8字节的数据 *2即可//跳过指定字节数raf.skipBytes(8);byte[] buf =new byte[4];raf.read(buf); //可用来读取字节的方法String name =new String(buf);int age = raf.readInt(); //专门用来读取int数据类型的方法sop(name+"::"+age);raf.close();}public static void getWrite()throws Exception{RandomAccessFile raf =new RandomAccessFile("ran.txt","rw");raf.write("张三".getBytes());//raf.write(97); //默认是char类型接收,即97占一个字节raf.writeInt(97); //char类型向上提升为int,即占4个字节, 这样的好处是让字母与数字之间有了距离raf.write("李四".getBytes());raf.writeInt(99);raf.close();}//主方法public static void main(String args[]) throws Exception{// getWrite();getRead();}}3 ) . 关于一个字符占几个字节 :
3.1 ASCII码表中 :
[1] 一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间
3.2 UTF-8中 :
[1] 一个英文字符等于一个字节,一个中文(含繁体)等于三个字节
3.3 Unicode编码中:
[1] 一个英文字符等于两个字节,一个中文 (含繁体) 等于两个字节
3.4 关于符号是 : 英文标点占一个字节,中文占两个字节
小结 :1. 随机读写访问类可实现软件任务多线程的下载 ; 思想 : 将数据分为几段, 一个线程负责一段,即可完成同时下载 -->这就是下载软件的原理2. 若存储某事物时容量不确定时,尽量给最大容量,避免出现内存溢出 ; 例如 : 名字 , 中国人名字最长也就4个字, 当然还有 少数民族 有可能 6个字,那么给 16个字节即可
1 ) . IO包中的其他类 :
1.1 DataInputStream与DataOutputStream -->操作基本数据类型1.2 ByteArrayInputStream与ByteArrayOutputStream -->操作字节数组1.3 CharArrayReader 与CharArrayWrite --> 操作字符数组1.4 StringReader 与 StringWriter --> 操作字符串
2 ) . Demo:/*本章讲述 :DataInputStream与DataOutputStream : 可以用于操作基本数据类型的数据的流对象须知 : DataOutputStream 写入的数据 必须 DataInputStream 读出,否则会出现乱码*/import java.io.*;import java.util.*;class DataStreamDemo{public static void sop(Object obj){System.out.println(obj);}//读入UTF-8修改版的编码格式的数据public static void readUTF() throws IOException{DataInputStream dis =new DataInputStream(new FileInputStream("demoUTF.txt"));String summ= dis.readUTF();sop("summ:"+summ);}//以UTF-8的修改版的编码格式写出public static void writeUTF() throws IOException{DataOutputStream dos = new DataOutputStream(new FileOutputStream("demoUTF.txt"));dos.writeUTF("sumer");}//写出数据类型相关的数据public static void writeData() throws IOException{DataOutputStream dos = new DataOutputStream(new FileOutputStream("demo.txt"));//初始化数据类型输出流对象dos.writeInt(99);dos.writeBoolean(true);dos.writeDouble(98.2342);dos.close();}//读入数据类型相关的数据public static void readData() throws IOException{DataInputStream dis =new DataInputStream(new FileInputStream("demo.txt")); //初始化数据类型输入流对象int num= dis.readInt(); //写入int类型的数据Boolean bol = dis.readBoolean();Double dou =dis.readDouble();sop(num+"::"+bol+"::"+dou);}//主方法public static void main(String args[]) throws Exception{/*演示读入写出数据类型相关数据的流*///writeData();//readData();/*演示读入写出数据类型相关数据的流的其它字符写入流*/// writeUTF();readUTF();}}小结 :1. UTF-8一个中文字3个字节,但UTF-8的修改版中是一个中文字4个字节2. 往后若只操作相关数据类型的流对象则用 Data...Stream
1 ) . ByteArrayStream 该对象是数组与流对象的封装,使用方便2 ) . Demo:/*本章讲述 :ByteArrayStream : 用于操作字节数组的流对象,底层封装的是 可变长度字节数组ByteArrayInputStream :在构造的时候,需要接受数据源,而且数据源是一个字节数组ByteArrayOutputStream : 在构造的时候,不用定义数据目的,因为该对象内部封装了可变长度的字节数据,因此这就是数据目击地特点 : 该对象不涉及系统资源,因为都是在内存中操作数组,所以close也不用关闭总结 : 流操作规律讲解 :源设备 :键盘 : System.in. 硬盘 FileStream 内存 ArrayStream目的设备:控制台: System.out 硬盘 FileStream 内存 ArrayStream*/import java.io.*;import java.util.*;class ByteArrayStreamDemo{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]){//数据源ByteArrayInputStream bais =new ByteArrayInputStream("ASDFGH".getBytes());//数据目地ByteArrayOutputStream baos =new ByteArrayOutputStream();int by=0; //临时存储变量while((by=bais.read())!=-1) //读数据{baos.write(by); //写数据}sop(baos.size()); //获取数组大小sop(baos.toString()); //以字符串的形式打印数组内容//将数据写入磁盘文件 baos.writeTo(new FileOutputStream("rellay.txt"));}}
小结 :1. 对数组的操作就是 设置和获取 ,同样对流的操作时 写 和读
1 ) . 简述 : 字符编码
1.1 字符流的出现为了方便操作字符 ,更重要的是加入了编码转换1.2 通过子类转换流来完成:
[1] InputStreamReader[2] OutputStreamWriter
1.3 在两个对象进行构造的时候可以加入字符集
2 ) . 可以玩编码表的流 :
2.1 转换流:
[1] InputStreamReader[2] OutputStreamWriter
2.2 打印流:
[1] printWriter[2] printReader
3 ) . 编码表的由来 :
3.1 历程 : 开关开关的电信号-->1010的二进制 -->1010与不同国家的不同文字相对应而形成了一张表 --->这张表就是编码表
3.2 分类 :
[1] ASCII : 美国标准信息交换码 : 用一个字节的七位可以表示[2] ISO8859-1: 拉丁码表.欧洲码表 : 用一个字节的8位表示[3] GB2312 : 中国的中文编码表: 用两个字节的16位表示[4] GBK : 中国的中文编码表升级融合了更多的中文文字符号[5] Unicode : 国际标准码表,融合了多国文字 : 所有文字都是用两字节表示,java语言使用的就是unicode[6] UTF-8 : 最多用三个字节来表示一个字符-->也就是 可用一个字节,也可用两个字节,最多用三个字节
4 ) . DEmo:/*本章讲述 :[1] OutputStreamWriter : 写出的字符字节转换流,其构造方法可指定编码[2] InputStreamReader : 读入的字符字节转换流,其构造方法可指定编码总结 : GBK编的码 用UTF-8去读则会出现 ?? 的乱码; UTF-8编的码用GBK去读则会出现类似繁文的文字*/import java.io.*;import java.util.*;class EncodeStream{public static void sop(Object obj){System.out.println(obj);}public static void writeText() throws IOException{OutputStreamWriter osw =new OutputStreamWriter(new FileOutputStream("demo.txt"),"UTF-8");osw.write("你好");osw.close();}public static void readText() throws IOException{InputStreamReader isr =new InputStreamReader(new FileInputStream("demo.txt"),"GBK");char[] buf =new char[1024];int len =isr.read(buf);String str =new String(buf,0,len);sop(str);isr.close();}//主方法public static void main(String args[]) throws IOException{// writeText();readText();}}
小结 :1. UTF-8编的码拿着GBK解码这时会出现繁体乱码; GBK编的码拿着UTF-8解码这时会出现??乱码
1 ) . 字符编码就是字符串与字节数组来回转换的过程2 ) . Demo:/*本章讲述 :编码 : 字符串编程字节数组解码 : 字节数组变成字符串String--> byte[]; str.getBytes(charsetName);byte[] --> String : new String(byte[],cahrsetName);*/import java.io.*;import java.util.*;class EncodeDemo{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]) throws IOException{String s = "你好";byte[] b1 = s.getBytes("UTF-8"); // 编码sop("编码输出:"+Arrays.toString(b1)); //输出编码内容String str =new String(b1,"GBK"); //解码sop("解码输出:"+str); ///解码失败,因为编码的码表与解码的码表不是一张表,一个UTF-8,一个GBKbyte[] b2 = str.getBytes("GBK"); //反向编码sop("反向编码输出:"+Arrays.toString(b2));String str2 = new String(b2,"UTF-8"); //再次解码sop("解码输出:"+str2); //解码成功,因为编码的码表与解码的码表是一张表,是UTF-8//结论 : 拿什么编的码就得拿什么解码 ,若出现编码失败,则反向编码出原来内容即可,再次重新解码即可}}3 ) . 重点 :
3.1 当我们是get请求时 , 解决乱码的方式就是 再次 反向编码
小结 :1. 所谓的数据编码及解码就是对数据的来回 转换2. Tomcat服务器的默认编码格式是ISO8859-13 .我们通常会用到的码表是 GBK ,ISO8859-1 ,UTF-84. 项目中要统一编码格式
1 ) . 字符编码 : 明白UTF-8的编码怎么判断何时读一字节,何时读两字节,何时读三字节的, 当我们换算为 二进制时,是依靠二进制前的标识符判断的2 ) . Demo:/*本章讲述 :Integer.toBinaryString() :用来将字符串换算为二进制&255 : 用来取二进制的有效位,也就是后八位小结 :当字节前的标识符是111时,便一次读三个字节当字节前的标识符是11时,便一次读两个字节当字节前的标识符是1时,便一次读一个字节*/import java.io.*;import java.util.*;class EncodeDemo1{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]) throws IOException{String str ="联通";byte[] buf = str.getBytes("GBK");for(byte b : buf){sop(Integer.toBinaryString(b&255));}}}小结 :1. 转码的过程 : 字节数据--><--编码表 -->生成 对应符号2. UTF-8的编码数据中有标识头信息,用来标识是读1个字节还是2个字节还是3个字节
[1] 当标识头是111时,便向下读两个字节+自身 =3字节[2] 当标识头是11时,便向下读1个字节+自身 =2字节[3] 当标识头是1时,便读自身即可也就是1字节
1 ) . 以下输入数据,处理数据(数据排序),存入磁盘的过程2 ) . Demo:/*本章讲述 :需求 :有五个学生,每个学生有三门课的成绩,从键盘输入以上数据(包括姓名,三门课成绩)输入的格式: 如: 张三,30,40,60计算出总成绩并把学生的信息和计算出的总分数高低顺序存放在磁盘文件的"stud.txt"中实现步骤 :[1] 描述学生对象[2] 定义一个可操作学生的工具类思想:1.通过获取键盘录入一行数据,并将该行的信息取出封装成对象2.因为学生量大,因此需要存储集合,又因需总分排序,则需要TreeSet3.通过IO流的方式将集合的信息写入到一个文件中总结 :[1] HashSet底层是哈希表结构,依赖的是HashCode和Equals[2] TreeSet底层是二叉树结构,依赖的是CompareTo用到的方法:[1] Comparable接口中的compare()方法 : 用来为指定数据进行排序[2] equals()方法 : 默认排序[3] TreeSet集合:存储可排序的数据[4]BufferedReader : 用来加强读入IO流数据的临时容器[5] InputStreamReader: 字符流与读字节流之间的转换器[6]System.in : 用来在dos窗口输入数据的方法[7]split : 字符串的数据切割[8]BufferedWriter : 用来加强写出IO流数据的临时容器[9]FileWriter: 用来写出数据的IO字符流[10]compareto :比较器当中的比较方法[11] Collections.reverseOrder() : 集合工具类当中让已排序的数据按逆序排列的方法*/import java.io.*;import java.util.*;//该类当中默认使用equals , 优先使用compareToclass Student implements Comparable<Student> //可操作对象{private String name;private int ma,cn,en;private int sum;Student(String name,int ma,int cn,int en){this.name=name;this.ma=ma;this.cn=cn;this.en=en;this.sum=ma+cn+en;}public int compareTo(Student s) //实现比较器{int num =new Integer(this.sum).compareTo(new Integer(s.sum)); //比较总成绩if(num==0)return this.name.compareTo(s.name);return num;}public String getName(){return name;}public int getSum(){return sum;}public int hashCode() //这个方法在此过程中不具备意义,只是考虑若使用set存储该对象则需要实现此方法{return name.hashCode()+sum*78; //}public boolean equals(Object obj){if(!(obj instanceof Student))throw new ClassCastException("类型不匹配");Student s = (Student)obj;return this.name.equals(s.name) && this.sum==s.sum; //返回名字和成绩总和}public String toString(){return "student["+name+","+ma+","+cn+","+en+"]";}}//操作学生的工具类class StudentInfoTool{//将数据写入并放入集合的方法public static Set<Student> getStudents() throws IOException //该方法是下边方法的抽取版本,下边方法是此方法的完善版本 -->理解 : 一个{return getStudents(null);}//将数据写入并放入集合的方法public static Set<Student> getStudents(Comparator<Student> cmp) throws IOException{BufferedReader bufr =new BufferedReader(new InputStreamReader(System.in)); //初始化一个缓存区写入流用来写入数据String line= null;Set<Student> stus= new TreeSet<Student>(); //初始化一个临时存储集合if(cmp==null) //判断是否传入比较器,若传入则初始化传入的TreeSet集合stus= new TreeSet<Student>();elsestus= new TreeSet<Student>(cmp);while((line=bufr.readLine())!=null) //将数据放入集合的方法{if("over".equals(line))break;String[] info = line.split(","); //将数据切割Student st =new Student(info[0],Integer.parseInt(info[1]),Integer.parseInt(info[2]),Integer.parseInt(info[3]));stus.add(st); //切割后的数据放入集合}bufr.close(); //关流return stus; //返回集合中的数据}//将集合中的数据通过IO流放入本地文件的方法public static void write2File(Set<Student> stus) throws IOException{BufferedWriter bufw =new BufferedWriter(new FileWriter("stuinfo.txt"));for(Student stu:stus){bufw.write(stu.toString()+"\t");bufw.write(stu.getSum()+"");bufw.newLine();bufw.flush();}bufw.close();}}class EncodeText{public static void sop(Object obj){System.out.println(obj);}//主方法public static void main(String args[]) throws IOException{//用来将下边集合中的数据的排序逆序的方法Comparator<Student> cmp = Collections.reverseOrder();//通过工具类调用输入流的方法用来输入数据,并将输入的数据放入集合Set<Student> stus = StudentInfoTool.getStudents(cmp);//将数据通过流写出到本地磁盘文件的方法StudentInfoTool.write2File(stus);}}
(十二)Core Java IO流(Properties,序列化,管道流,字符编码)-03 (108)相关推荐
- Java NIO系列教程(十二) Java NIO与IO
原文地址:http://tutorials.jenkov.com/java-nio/nio-vs-io.html 作者:Jakob Jenkov 译者:郭蕾 校对:方腾飞 当学习了Java ...
- 【Java数据结构与算法】第十二章 哈夫曼树和哈夫曼编码
第十二章 哈夫曼树和哈夫曼编码 文章目录 第十二章 哈夫曼树和哈夫曼编码 一.哈夫曼树 1.基本术语 2.构建思路 3.代码实现 三.哈夫曼编码 1.引入 2.介绍 3.代码实现哈夫曼编码综合案例 一 ...
- java中过滤流_第十四讲 Java中的字节流和过滤流
第十四讲Java中的字节流和过滤流 主要内容 InputStream和FileInputStream OutputStream和FileOutputStream 文件字节IO流应用举例 过滤流类和常用 ...
- 【十四】Java IO框架思维导图
知识章节参考:[十四]Java IO框架
- java io broken pipe解决_报错!!java.io.IOException: 断开的管道 中文报错?Broken pipe?这次发生的报错不影响业务,已有解决方案...
org.apache.catalina.connector.ClientAbortException: java.io.IOException: 断开的管道 at org.apache.catalin ...
- Java IO(input output)流二
一.字符流的缓冲区 1.什么是缓冲区 缓冲区又称为缓存,它是内存空间的一部分.也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据, 这部分预留的空间就叫做缓 ...
- JavaSE:第十二章:IO流
史上最全的知识体系脑图,覆盖所有知识点,所有细节,注意事项. IO流:包含 java.io.File类的使用, IO原理及流的分类,节点流(或文件流):FileInputStream / FileOu ...
- JavaWeb技术内幕二:Java IO工作机制
IO问题是当今web应用所面临的主要问题之一,因为数据在网络中随处流动,在这个流动过程中都涉及IO问题,并且大部分应用的瓶颈都是IO瓶颈. 本章将从IO的角度出发,介绍IO类库的基本架构,磁盘IO的工 ...
- 三十二、Java集合中的ArrayList
@Author:Runsen @Date:2020/6/3 作者介绍:Runsen目前大三下学期,专业化学工程与工艺,大学沉迷日语,Python, Java和一系列数据分析软件.导致翘课严重,专业排名 ...
最新文章
- PPStream、PPlive等播放器花屏之解决办法
- hdu 1174:爆头(计算几何,三维叉积求点到线的距离)
- FSG2.0脱壳记录
- 【百度地图API】如何使用suggestion--下拉列表方式的搜索建议
- 【Android Developers Training】 0. 序言:构建你的第一个应用
- 二叉树的基本操作及哈夫曼编码/译码系统的实现
- HDU-3622 Bomb Game 2sat
- 367. 有效的完全平方数(二分法)
- 顺丰控股子公司亮榛拟1000万美元参投海外投资基金
- 物联网云计算成本核算 小厂的出路在哪里
- eatwhatApp开发实战(二)
- 最详细的制作正式版10.11 OS X El Capitan 安装U盘的方法
- excel数据库_EXCEL数据库函数dcount、dcounta
- 万兴pdf编辑解压后打不开_为什么有的PDF文档无法编辑?
- UML--用例图详解
- [Chatter] 架构设计是做甚么
- 解决Linux“Device is busy”与磁盘只读
- 医院选址c语言课程设计,通信学院2012届本科毕业设计选题结果(学生)2.xls
- 魅族手机TOF摄像头搭载奥比中光解决方案,看看到底有哪些功能?
- 【DDR3_Electrical Characteristics and AC Timing】_Addr/Cmd Setup,Hold and Derating