疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java基础IO篇之流对象


 

   

  IO(InputOutput)

  (一)破题

  IO流用来处理数据设备之间的数据传输;Java对数据的操作是通过流的方式;Java用于操作流的对象都在IO包中;

  流按操作数据分为两种:字节流与字符流;

  流按流向分为两种: 输入流(读取内存),输出流(写入外设);

  数据是以(二进制)字节形式存在的。字节流可以处理所有对象。

  字符流其实就是字节流+编码表;如果要操作文字数据,优先考虑字符流。

  (二)简述

  一、 IO流常用基类:

  字节流的抽象基类:InputStream, OutputStream;

  字符流的抽象基类:Reader,Writer.

  这些体系中大多的子类都以父类名做后缀,子类名的前缀就是该对象的功能

  二、 IO字符流常用子类:

  Writer(体系)

  |——FileWriter

  2) FileWriter往一个文件中写入文字数据;如果文件不存在,则会自动创建;如果存在文件则会覆盖

  2)FileWriter类中常用方法。

  2.11)刷新数据flush(); 返回值为void

  2.12)关闭数据流close();返回值为void;

  此方法在关闭流资源之前会先调用flush方法刷新再关闭;

  与flush方法比较:flush可以用多次,但是close方法只能用一次

  2.13)写入数据write();返回值为void

  2.14)续写数据在构造函数中加入true可以实现续写;

  FileWriter(StringFileName,booleantrue)

  异常处理细节:

  流对象一般会抛出异常,在try的外面进行对象的创建;在try内进行对象引用。

  记着要判断空指针异常。

  Reader(体系)

  |——FileReader

  2.)FileReader:读取字符数据的流对象,在创建读取对象时,必须要明确被读取的文件,一定要确定该文件是存在的。

  2.)FileReader类中常用的方法

  2.21)读取数据read();有重载方法,有多种返回类型

  三、

  3.)字符流缓冲区:缓冲区的出现提高了对数据的读写效率。缓冲区要结合流才可以使用。

  在流的基础上对流的功能进行了增强,(虽然也可以自定义缓冲区)。

  这样可以使用字符流缓冲区对外提供的方法。

  对应类BufferedWriter BufferedReade

  3.1)BufferedWriter(体系)

  |——

  BufferedWriter类中常用方法

  3.11)write()写入数据进缓冲区

  3.12)flush()刷新

  3.13)newLine()换行(此方法为BufferedWriter类特有,其他类不适用)

  使用系统方法实现平台的换行操作:System.getProperty("line.separator")

  3.2)BufferedReader(体系)

  |——3.3)LineNumberReader(子类)

  BufferedReader类常用方法

  3.21)read()读取数据进缓冲区:可读取字符型数据;数组数据;换行标记

  3.22)readLine()读取一个行;返回值类型String

  此方法使用读取缓冲区的read方法,将读取的字符进行缓冲并判断换行标记。将标记前的缓冲数据变成字符串返回。

  此方法适用情景:对行的操作,如索引行中关键字;

  了解:装饰设计模式——使用情景功能扩展

  装修设计模式与通过继承实现情景功能扩展的区别:只为实现功能扩展而继承使得继承体系变得越来越臃肿庞杂,不够灵活。

  将功能进行单独的封装,哪个对象需要扩展功能,就在将哪个对象和功能关联。

  装饰比继承灵活 ;特点:装饰类和被装饰类必须属于同一接口或者父类。

  3.3)LineNumberReader类常用方法

  3.31)getLineNumber()此方法显示行号

  四、IO流字节流

  字节流与字符流相比而言,处理的数据单元不同;操作的数据文件格式不同,字符流只能操作文本文件,而字节流可以操作媒体文件。

  字节流基类InputStream, OutputStream;

  IO字符流常用子类:

  InputStream(体系)

  |——FileInputStream

  4.1)FileInputStream:往一个文件中写入文字数据;如果文件不存在,则会自动创建;如果存在文件则会覆盖

  4.1)FileInputStream类中常用方法。

  4.11)获取字节的个数available()返回int

  4.12)关闭字节流close(); 返回值为void

  为什么用字符流不能复制一个图片格式的文件?

  字符流再读取源数据后,又进行匹配编码表操作,其中,可能有一些字符不被识别或替换了原有的字符,导致文件内容的变动,不能完成复制操作。

  字符流是处理文本对象的专业对象,不能用来操作媒体文件。

  关于编解码:编码——看的懂的转换为看不懂的;解码——把看不懂的转换为看得懂的。

  转换流:

  字节流与字符流之间的转换;他们转换的关键问题就是编码表;

  (字符流实质就是字节流+编码表)

  InputStream(体系)

  |——InputStreamReader

  InputStreamReader类是字节流同乡字符流的桥梁,他使用指定的charset读取字节并将其解码为字符。它使用的字符集可以由名称指定或显示给定,或者接受平台默认的字符集。

  4.2) InputStreamReader常用方法

  4.21)InputStreamReader(InputStreamin) 构造方法

  字符流与字节流之间的转换

  OutputStream;

  |——OutputStreamWriter

  OutputStreamWriter类是字符流通向字节流的桥梁;他使用指定的charset读取字节并将其编码为字符。它使用的字符集可以由名称指定或显示给定,或者接受平台默认的字符集。

  4.3)OutputStreamWriter常用方法

  4.31)OutputStreamWriter(OutputStreamout)构造方法

  五、流操作中的规律

  转换流: InputStreamReader:字节到字符的桥梁。——解码

  OutputStreamWriter:字符到字节的桥梁。——编码

  规律: (1)明确源和目的(汇)

  源涉及的体系:InputStream Reader

  汇涉及的体系:OutputStream Writer

  (2)明确数据是否是纯文本数据

  源 是纯文本:Reader

  否:InputStream

  汇 是纯文本:Writer

  否:OutputStream

  (3)明确具体的设备

  源设备:

  硬盘:File

  键盘:System,in

  内存:数组

  网络:Socker流

  汇设备:

  硬盘:File

  控制台:System.out

  内存:数组

  网络:Socker流

  (4)是否需要额外对象

  1.是否需要高效(缓冲区)——buffer

  六、Test小练习

  6.1)

  packagecom.IO;

  importjava.io.BufferedReader;

  importjava.io.BufferedWriter;

  importjava.io.FileReader;

  importjava.io.FileWriter;

  importjava.io.IOException;

  /**

  *需求:复制一个文本文件

  *

  *思路:

  *1.明确源和目的源InputStreamReader;目的OutputStreamWriter

  *2.是否为纯文本是源:Reader目的:Writer

  *3.明确具体设备源:硬盘:File目的:硬盘:File

  *4.扩展额外功能需要缓冲区

  *@authorASUS

  *

  */

  publicclassCopyTextTest{

  /**

  *@throwsIOException

  */

  publicstaticvoidmain(String[]args)throwsIOException{

  //1.确定源和目的对象

  BufferedReaderbufr=newBufferedReader(newFileReader("a.txt"));

  BufferedWriterbufw=newBufferedWriter(newFileWriter("b.txt"));

  //2.判断条件,循环写入,刷新缓冲

  Stringline;

  while((line=bufr.readLine())!=null){

  //读行

  bufw.write(line);

  //换行

  bufw.newLine();

  //刷新

  bufw.flush();

  }

  //3.缓冲关流

  bufr.close();

  bufw.close();

  }

  }

  6.2)packagecom.IO;

  importjava.io.BufferedReader;

  importjava.io.BufferedWriter;

  importjava.io.FileWriter;

  importjava.io.IOException;

  importjava.io.InputStreamReader;

  /**

  *需求2:读取键盘录入信息,并写入一个文件中

  *思路:

  *1.明确源和目的;源——InputStreamReader目的——OutputStreamWriter

  *2.是否是纯文本:是源——Reader目的——Writer

  *3.明确设备源——键盘:System.in目的——硬盘:File

  *4.是否需要功能高效——缓冲区;转换——字节流转换为字符流

  */

  publicclassReadKeyText{

  /**

  *@paramargs

  *@throwsIOException

  */

  publicstaticvoidmain(String[]args)throwsIOException{

  //创建字节输入源对象,并关联键盘

  InputStreamReaderisr=newInputStreamReader(System.in);

  //创建目标接收字符流对象并关联目标文件

  FileWriterfw=newFileWriter("c.txt");

  //高效读取缓冲区

  BufferedReaderbufr=newBufferedReader(newInputStreamReader(System.in));

  //高效写入缓冲区

  BufferedWriterbufw=newBufferedWriter(newFileWriter("c.txt"));

  //变量

  intch=0;

  //循环判断写入刷新

  while((ch=bufr.read())!=-1){

  bufw.write((char)(ch));

  bufw.flush();

  }

  //关闭流资源

  bufw.close();

  bufr.close();

  }

  }

  6.3)

  packagecom.IO;

  importjava.io.BufferedReader;

  importjava.io.BufferedWriter;

  importjava.io.FileReader;

  importjava.io.FileWriter;

  importjava.io.IOException;

  importjava.io.OutputStreamWriter;

  /**

  *需求:将文本文件数据显示在控制台上

  *1.明确源和目的:源——InputStreamReader目的——OutputStreamWriter

  *2.是否为纯文本:是源——Reader目的——Writer

  *3.明确具体设备:源——硬盘File;目的——控制台

  *4.额外功能:转换

  */

  publicclassReadKeyText02{

  /**

  *@paramargs

  *@throwsIOException

  */

  publicstaticvoidmain(String[]args)throwsIOException{

  //创建读取流对象,并关联文件,缓冲区提高效率

  BufferedReaderbufr=newBufferedReader(newFileReader("a.txt"));

  //创建输出流对象,并关联输出设备,缓冲区提高效率

  BufferedWriterbufw=newBufferedWriter(newOutputStreamWriter(System.out));

  intch=0;

  while((ch=bufr.read())!=-1){

  bufw.write((char)(ch));

  bufw.flush();

  }

  bufw.close();

  bufr.close();

  }

  }

  6.4)packagecom.IO;

  importjava.io.BufferedReader;

  importjava.io.BufferedWriter;

  importjava.io.IOException;

  importjava.io.InputStreamReader;

  importjava.io.OutputStreamWriter;

  /**

  *需求:读取键盘录入数据,显示在控制台上

  *思路:

  *1.明确源和目的:源——InputStreamReader目的——OutputStreamWriter

  *2.是否为纯文本:是源——Reader目的——Writer

  *3.明确设备:源——键盘目的——控制台

  *4.扩充功能:缓冲转换

  */

  publicclassReadKey04{

  /**

  *@paramargs

  *@throwsIOException

  */

  publicstaticvoidmain(String[]args)throwsIOException{

  //读取字节

  BufferedReaderbufr=newBufferedReader(newInputStreamReader(System.in));

  //输出字符

  BufferedWriterbufw=newBufferedWriter(newOutputStreamWriter(System.out));

  Stringline;

  while((line=bufr.readLine())!=null){

  bufw.write(line);

  bufw.newLine();

  bufw.flush();

  }

  bufw.close();

  bufr.close();

  }

  }

  FileWriter:其实就是转换流指定了本机默认码表的体现。而且这个转换流的子类对象,可以方便操作文本文件。(操作文件的字节流+本机默认的编码表),这是按照默认编码表来操作文件的便捷类。但是如果,操作文本文件明确了编码表就不行了,需要用字节流

  GDK码表中:一个汉字两个字节;UTF-8:一个汉字三个字节;

  一般打开文件是一堆中文乱码,那么极可能是用录入时用其他码表,而用GDK来解码的文件。

  如果打开文件是一堆符号,那么极可能是用GDK来录入,而用其他码表解码的。

  转换流使用的情景:

  1.源或者汇的对应设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁。

  2.一旦操作文本涉及到指定编码表时,必须使用转换流。

  Properties集合对IO流的操作

  Properties集合是Map集合的子类,可记录键值对,多用于配置文件的设置;

  方法store()

  setProperties方法()

  打印流:1.PrintStream:提供打印的方法,可以为多种数据类型提供打印方法

  2.不抛IOException

  构造函数,接收三种类型的值

  1.字符串路径

  2.File对象

  3.字节流

  Out.write();的特点:只写8位

  字符打印流:printWriter

  序列流:有序的排列 一个流对象关联一个源,我有多个数据,关联多个流;

  (集合容器封装多个流)

  文件切割

  1.确定切割条件(按大小;按切割个数)

  2.一个源文件流;多个输出流(有几个目的文件关联几个流)

  3.自定义缓冲区

  关键:设置配置文件获取文件切割个数,及后缀名;键值对Properties对象,在切割时生成

  文件合并

  1.获取配置文件对象2.判断配置文件个数3.读取配置文件信息4.把切割后文件匹配配置文件信息5.将碎片文件和流对象关联并使用集合对象存储6.合并文件多个流合并成一个序列流

  关键:通过过滤器来获取配置文件(配置文件要唯一);来确定需合并的个数和合并后源文件类型

  序列化

  操作对象的流:对象的序列化,实质:把存入硬盘的对象进行排列

  对象的序列化;对象的反序列化

  操作情景:

  ObjectInputStream与ObjectOutputStream

  被操作的对象需要实现Serializable(标记接口);

  RandomAccessFile

  随机访问文件,自身具备读写的方法。

  通过skipBytes(intx),seek(intx)来达到随机访问。

  特点:

  1.该对象即能读又能写

  2.该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素

  3.可以通过getFilePointer方法获取指针的位置,和通过seek方法设置指针的位置

  4.其实该对象就是将字节输入流和输出流进行了封装。

  5.该对象的源或者目的只能是文件,通过构造函数就可以看出。

  管道流

  PipedInputStream和PipedOutputStream

  输入输出可以直接进行连接,通过结合线程使用。

  操作基本数据类型

  DataInputStream与DataOutputStream

  操作字节数组

  ByteArrayInputStream与ByteArrayOutputStream

  操作字符数组

  CharArrayReader与CharArrayWrite

  操作字符串

  StringReader与StringWriter

  字符编码

  字符流的出现为了方便操作字符。

  更重要是的加入了编码转换。

  通过子类转换流来完成。

  InputStreamReader

  OutputStreamWriter

  在两个对象进行构造的时候可以加入字符集

  计算机只能识别二进制数据,早期由来是电信号。

  为了方便应用计算机,让它可以识别各个国家的文字。

  就将各个国家的文字用数字来表示,并一一对应,形成一张表。

  这就是编码表。

  ASCII:美国标准信息交换码。

  用一个字节的7位可以表示。

  ISO8859-1:拉丁码表。欧洲码表

  用一个字节的8位表示。

  GB2312:中国的中文编码表。

  GBK:中国的中文编码表升级,融合了更多的中文文字符号。

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

  所有文字都用两个字节来表示,Java语言使用的就是unicode

  UTF-8:最多用三个字节来表示一个字符。

  ......

  可以将字符以指定编码格式存储。

  可以对文本数据指定编码格式来解读。

  指定编码表的动作由构造函数完成。