您的位置:首页 > 职场人生

黑马程序员:IO流

2013-03-23 16:46 281 查看
-------
android培训、java培训、期待与您交流! ----------

Io流

       -io流用来处理设备之间的数据传输

       -java对数据的操作是通过流的方式

       -JAVA用于操作流的对象都在io包中

       -按操作的数据分为两种:字节流 字符流

       -按流向分为:输入流,输出流

自注:字符流实际就是文字对应的字符编码表中的编码,(解析字符流要使用正确的编码方式解码,否则乱码)。

             字符流都有编码,不指定字符流的编码时,默认为系统的编码.

 

io流常用基类:   字节流:inputStream outputStream 字符流:Reader Writer

注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀,(前缀表明该对象的功能)。

 

字符流

       文件字符流: FileReader and FileWriter

       既然io流失永远操作数据的,那么数据的最常见的体现形式是:文件。

需求:在硬盘上,创建一个文件并写入一些文字数据。

使用FileWriter(创建时,必须指定文件名)-----new FileWriter(“demo.text”, boolean append(表示是否为追加数据));

-Write()方法只是将数据写入到流对象中(还在内存临时缓冲中),

-Flush()方法刷新流对象中的缓冲中的数据将数据刷到目的地中.

-Close()方法关闭流资源,但是关闭之间会刷新一次内部的缓冲中的数据,将数据刷到目的地中,

和flush()区别: flush()刷新完后,没有关闭流,流可以继续使用.

 

Java的流会调用底层系统(如windows)的资源来完成读写,所以需要关闭流,释放资源.

Windows自带的软件如记事本不会将”\n”解析成回车(显示为一个黑块),而是”\r\n”,而linux中回车为\n;

创建一个文件读取流对象,必须指定的文件名关联的文件是存在,否则抛出异常,没有文件你读取个什么劲儿

-read()方法一次读一个字符,返回一个字符的int形式,读到文件末尾返回-1;

-read(char[]) 定义一个字符数组, 用于存储读到的字符,返回读到的字符个数,到末尾返回-1;

 

需求:从c盘读取一个文件的数据储存到d盘.

方法1:c盘读取一个字符,就往d盘写一个字符;

方法2:创建一个缓冲区字符数组,把c盘的字符通过输入流都先存到数组中,再通过输出流写到d盘.

 

字符流缓冲区: BufferedReader and BufferedWriter

缓冲区的出现是提高流的操作效率而出现的,所以在创建缓冲区之前,必须先有流对象.

BufferedReader(inputStream );bufferedWriter(OutputStream)必须有参数---流对象.

只要用到缓冲区,就要记得刷新, 因为每次读写操作都只是将数据临时存储在缓冲区中.

关闭字符流缓冲区,就是在关闭了缓冲区中的流对象.

 

字符读取流缓冲区:  ------提供了一次读一行的方法readline();

创建一个读取流对象和文件相关联: FileReader fr = new FileReader(“buf.txt”);

为了提高效率.加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数:

BufferedReader bufr = newBufferedReader(fr);

Readline() 读取一行(读到回车换行符认为一行终止),不包含终止符 ,到达末尾返回null;

Readline()方法的原理: 无论是读一行,获取读取多个字符.其实最终都是在硬盘上一个一个读取.所以最终使用的还是read()方法一次读一个的方法..

 

可以自定义一个类中包含一个功能和readLine()一样的方法:

classMyBufferedReader{

       private FileReader fr;

       MyBufferedReader(FileReader fr){

              this.fr=fr;

       }

PublicString MyReadLine(){

              StringBuilder sb = newStringBuilder();//定义一个临时容器.

              Int ch = 0;

              While(ch=fr.read()!=-1){

                     If(ch==”\r”)

                            Continue;

                     If(ch==”\n”)

                            Returnsb.toString();

                     else

                            sb.append((char)ch);

              }

              if(sb.length)!=0)

                     return sb.toString();

              return null;           

       }

       public void myclose(){

              fr.close();

}

}                          

装饰设计模式 (将已有的对象传入新定义的对象,在新对象中对已有的对象进行操作,添加增强功能)

       当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有对象的功能,并提供加强功能,

那么自定义的该类称为装饰类.

装饰类通常会通过构造方法接收被装饰的对象.并基于被装饰的对象,提供更强的功能.

所以装饰类和被装饰类通常是属于一个体系中,避免通过继承来增强类功能所造成臃肿.比继承灵活

 

字符流他其实是一样走的字节,但是他需要将字节临时存起来(否则只读到一个字节怎么弄),然后查编码表,.字符流底层也用的是字节流那么缓冲区, 直接使用字节流,没有使用具体指定的缓冲区的话,他是不需要刷新缓冲的,直接将字节一个个的写到目的地中去.

字节流:

 FileInputStream.available()返回流对象关联的文件的长度。

注:有缓冲的流对象写入时需要刷新缓冲区,若没有缓冲,字符流(内部有缓冲区)需要刷新,字节流不需要刷新。

 演示mp3的复制,通过缓冲区

注: 流对象中read()从流中读取一个byte提升为int返回,而write(int b)只写int类型的最低8位.

      

读取键盘录入 System.out 标准输出设备,默认控制台,System.in标准输入, 默认键盘.

       流程: 将字节流转换成字符流  然后再使用字符流缓冲区包装字符流,再调用readline();

       readline方法是字符流bufferedReader的方法 而键盘录入的read方法是字节流InputStream的放法.

       能不能将字节流转换成字符流再使用字符流缓冲区(BufferedReader)的readLine方法.

inputStreamReader字节流通向字符流的桥梁. 例子:键盘录入

       OutputStreamWriter字符流通向字节流的桥梁 例子:直接将字符写入到System.out字节流中

       这两个流对象构造参数中可以指定编码表,没有指定则使用平台默认的编码表.

 

       1明确源和目的  源输入流: InputStream ,Reader .目的 输出流 :ouputStream ,Writer.

       2操作数据是否是吹文本 是 字符流. 不是:字节流.

       3明确用哪个具体对象 通过设备区分  源设备内存,硬盘,键盘, 目的设备:内存,硬盘,控制台.

流缓冲区(Buffered-)将各个字节或字符写入底层输出流中,然后一次存到目的地,而不必针对每次字节写入调用底层系统,增加了一些他底层读入流的功能,等等见文档,(缓冲区大小可设置)。

 

通常 Writer 将其输出立即发送到底层字符或字节流。除非要求提示输出,否则建议用BufferedWriter 包装所有其 write() 操作可能开销很高的 Writer(如 FileWriters 和 OutputStreamWriters)。

FileReader(File f) =InputStreamReader(InputStream is, charSet cs) .(fileReader固定死了编码表为默认的).

 记住:转换流什么时候使用. 字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流.比如将utf-8文件转码成gbk编码格式的文件

 

system.setIn() 修改标准输入流  System.out 修改输出流

文本文件其实也是字节文件 字符输入流读取时查对应的编码表把独到的解码成字符.字符输出流按照指定的编码表将字符编码成对应的字节文件.

printWriter 像字符输出流打印对象的格式化表示形式. 构造参数可以接收字符输出流,

printStream 打印各种数据值表示形式(保持数据原样),打印的字符使用默认编码转换成字节,然后完全用write写入这些字节 比如 printStream.write(int b) 写入这个数据的最低八位;printStream.print(int b) 写入数据完整的32位字节.

区别:printStream 构造可接受参数类型:    File ,String, OutputStream,    不抛异常,      可开启自动刷新(输出byte数组、调用println方法、输出换行符或者byte值10(即\n)时自动调用flush方法)

        printWriter 构造函数可接受参数类型 File ,String, OutputStream ,writer.   通用性强. 可开启自动刷新(当print ()println() format()),不能写入字节,

参见print(String s)和print(int t)    理解这个方法解释,便于理解打印流. (要理解)
 

File    方便对文件和文件的属性信息进行操作,可以作为参数传递给流的构造函数.

createNewFile();必须调用了此方法,才能真正在硬盘创建文件,如果存在则不创建,返回false….

renameTo() 可以实现类似剪切的功能,即可以修改文件路径。

List(FilenameFilterfnf ) 接收一个过滤器对象,对名字进行判定过滤。

删除一个带内容的目录:在window中,删除目录是从里面往外面删除.

 

Properties是hashtable的子类

也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串

是集合中和IO技术相结合的集合容器。 可以用于键值对形式的配置文件。

 

演示:如何将流中的数据存储到集合中。

想要将info.txt中键值对数据存到properties集合中进行操作

1,用一个流和info.txt文件关联。    new bufferedReader(newfileReader(“x.txt”));

2,读取一行数据,将该行数据用“=”切割         String.split(“=”);

3,等号左边为键,右边作为值,存入到properties集合中去。 ……

Properties.load(InputStream is);将流关联的文件的数据直接加载进集合.比上面方法方便的多,

Properties.store(OutputStream os) 将集合中的内容存储到流和文件中.

 

用于记录应用程序运行次数 如果使用次数已到,那么给出注册提示

 所以要建立一个配置文件,用于记录该软件的使用次数

 

合并流 (用于合并文件):

SequenceStream(Enumeration<?  extends InputStream> e)   Enumeration = Vector.elements();

SequenceInputStream(InputStreams1,InputStream s2)

IO包中其他类

       RandomAccessFile

       随机访问文件. 父类为Object.自身具备随机读取和写入功能,行为类似一个存储在文件系统的大型byte数组.

存在一个指向该隐函数组的光标或索引,称为 文件指针. 内部封装了一个数组,通过指针对数组元素操作.

getFilePoint()获取指针位置,同时可用seek()改变指针位置. skipBytes(int n)只能向前跳n个字节.

其实其完成读写原理就是内部封装了字节输入流和输出流.   可读写基本数据类型可读一行

       RandomAccessFile(String filename,String mode) 如果模式为r,不会创建,只会读取,若文件不存在,报异常.

        可实现多线程下载,

PipedStream 管道流                 pipedInpuStream.connect(PipedOutputStreampos);

PipedInputStream(PipedOutputStreampos) 输入输出可以直接进行连接 一个线程写入,另一个线程读取

例: pipedInputStream.write(258) 只写低八位,而.writeInt(258)按照4个字节写入258,先写高字节.

自注:文本文件存在硬盘上其实也是特殊的字节文件(这些字节都是字符编码),当记事本打开文件,会参照默认编码表将这些字节解码成字符显示,当用字符流读取时,也会用对应编码表将这些字节解码程字符.

DataInputStream DataInpuStream();可以用于操作基本数据类型的数据的流对象

 作用: DataOutputStrea,writeInt(234)向文件写入4个字节(注意,不是写入表示234的字符编码的字节).,所以当记事本打开这么文件时会查gbk的表,显示结果当然乱码,需要用DataOutputStream.readInt()来读取返回一个int类型,假如用字符流存取,取的时候需要parseInt()才能获得int值234.假如用字节流存取,取得时候要先往一个数组中装4个字节,再将这个字节变成一个字符串,再用parseInt(Strings,Radix r);

writeUTF()以与机器无关方式使用 UTF-8修改版编码将一个字符串写入基础输出流。必须用ReadUTF()来读取

 

ByteArrayInputStream(byte[]) 包含一个内部缓冲区(使用
buf
作为其缓冲区数组),该缓冲区包含可以从流中读取的字节。

没有调用底层资源(如读写文件),所以关闭无效,即使关闭了仍然可以调用 ,不产生io异常.

ByteArrayOutputStream() 此类实现了一个输出流,其中数据被写入一个byte数组(缓冲区自动增长).同上

其在构造时,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组

例子 :

ByteArrayinputStream bis = new ByteArrayInputStream(“aaaaa”.getBytes()); 数据源为字节

ByArrayOutputStream bos = new ByteArrayoutputStream();  数据目的

Int by=0;

While((by=bis.read())!=-1)

    bos.write(by);

System.out.print(bos.toString());

 

CharArrayReader 此类实现一个可用作字符输入流()的字符缓冲区。把字符数组作为源的输入流

数据源为charArray.  目的charArrayWriter实现了以数组作为目标的输出流,有内部缓冲区

StringReader 其源为一个字符串的字符流。  目的:StringWriter 的内部缓冲区 

 

字符编码         

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

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

通过子类转换流来完成

inputStreamreader OutputStreamWriter 加入了编码表的流对象,构造的时候可以设定字符集.

PrintWriter printOutputStream 也可以指定字符集

 

编码表:将文字用二进制数字一一对应的表示,形成一张表.

Ascii 一个字节的低7位.        美国标准信息交换码

ISO8859-1 一个字节的8位表示     拉丁码表,欧洲码表,

Gbk2312,Gbk 两个字节,每一个字节开头高位为1

Unicode     2个字节表示   java语言使用的是unicode    国际标准码        

InputStreamReader(newFileInputStream(“aaa.txt”),”gbk”)===等于====FileReader(“aaa.txt”); 输出流同理理解

编码: 字符变字节      解码: 字节变字符          

Stringàbyte[]  string.getBytes(charsetName) 按指定编码表将字符编码成字节数组

Byte[]àString  new String(byte[],charsetName)   按指定编码表将字节数组解码成字符

Arrays.toString(arr[])返回一个表示arr数组中的内容的字符串,可用来打印byte[]中实际内容.

Integer.toBinaryString(byteb));获取字节b的二进制表示的字符串

 


联通记事本打开会乱码,因为”联通”的gbk编码正好像utf-8编码,在只有联通两个字的情况下,记事本就默认用utf-8来解码.联通前面随便加上一个其他汉字就能解决乱码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: