java基础_11_IO流

来源:互联网 发布:服装纸样软件 编辑:程序博客网 时间:2024/06/05 14:23
IO

当程序需要读取或写入数据的时候,就会开启一个数据源的流,这个数据源可以是文件,内存,或是网络连接。

 

流的分类:

1,按数据方向分:输入流和输出流

输入流:Reader / InputStream

输出流:Writer / OutputStream

2,按数据类型分:字节流和字符流

字节流:InputStream / OutputStream

|-- FileOutputStream

|-- FileInputStream

缓冲技术

|-- BufferedInputStream 

|-- BufferedOutputStream

字符流:Reader / Writer

|-- FileReader

|-- FileWriter

缓冲技术

|-- BufferedReader    字符读取流缓冲区

|-- BufferedWriter  字符写入流缓冲区

转换流

OutputStreamWriter :将输出的字符流转化为字节流

InputStreamReader :将输入的字节流转换为字符流

例://源,键盘

    BufferedReader bufr =  new  BufferedReader(new InputStreamReader(System.in));

注意:不管如何操作,最后都是以字节的形式保存在文件中的。

 

转换流什么时候使用?

是字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流。

例:

按照指定的编码表(UTF-8)存到文件中使用下面的方法

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\123\\d.txt""UTF-8")));

 

管道流

管道输出流:PiPedOutputStream

管道输入流:PipedInputStream

打印流

PrintStream

为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException

合并流

SequenceInputStream (Enumeration<? extends InputStream> e)

将多个流合并成一个,然后再输出到指定位置

例:

将三个文本文件中内容合并成一个文件。

思路:读取一个文本就会创建一个流。把这些流放在集合中。

   Vector<FileInputStream> v = new Vector<FileInputStream>();     v.add(new FileInputStream("d:\\123\\1.txt"));     v.add(new FileInputStream("d:\\123\\2.txt"));     v.add(new FileInputStream("d:\\123\\3.txt"));     Enumeration<FileInputStream> en = v.elements();    //SequenceInputStream 只接收 Enumeration(枚举)所以在选用集合时选能实现枚举的     SequenceInputStream sis = new SequenceInputStream(en);     FileOutputStream fos = new FileOutputStream("d:\\123\\123.txt");     byte[] buf = new byte[1024];     int len = 0;     while ((len=sis.read(buf))!=-1)     {fos.write(buf,0,len);     }     fos.close();     sis.close();

 

操作字节数组的流对象

ByteArrayInputStream   

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

例:

ByteArrayInputStream bis = new ByteArrayInputStream("abcd".getBytes());

 

ByteArrayOutputStream

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

     例:

      ByteArrayOutputStream bos = new ByteArrayOutputStream();

           int by = 0;

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

{

  bos.write(by);

}

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

操作字符数组

CharArrayReader

CharArrayWriter  用法一样

操作字符串

StringReader

StringWriter

操作基本数据类型的流对象

DataInputStreamgn 

DataOutputStream

Properties 

操作于集合和IO流之间, Properties 继承于 Hashtable

 

缓冲区技术

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

例:

使用写入流缓冲区技术

//1,创建一个字符写入流对象

FileWriter fw = new FileWriter("buf.txt");

//2,为了提高写入流效率,加入缓冲技术

BufferedWriter bufw = new BufferedWriter(fw);

这样就可以使用缓冲技术的方法,如:newLine()  换行,使用这个具有跨平台性。

 

注意: bufw.close();  //底层操作其实就是fw流,所以只要关闭缓冲区就是关闭fw

例:

复制一个Mp3,通过字节流的 缓冲区完成复制

   public void method() throws IOException   {    BufferedInputStream bfis = new BufferedInputStream(new FileInputStream("D:\\123\\Honey.mp3"));    BufferedOutputStream bfos = new BufferedOutputStream(new FileOutputStream("D:\\123\\123.mp3"));     int by = 0;    while ( (by=bfis.read()) !=-1 )      {        bfos.write(by);    }        bfis.close();        bfos.close();   } 

例:复制一个图片,不用缓冲区,使用数组完成,

    public void method2() throws IOException    {      FileInputStream fis = new FileInputStream("D:\\123\\1.jpg");      FileOutputStream fos = new FileOutputStream("D:\\123\\2.jpg");          byte[] buf = new byte[1024];  // 这里数组其实就相当于是缓冲区      int len = 0;      while ((len=fis.read(buf))!=-1)      {          fos.write(buf,0,len);        }          fis.close();       fos.close();    }

 

自定义缓冲区技术:

实现原理:

使用底层InputStream  read 方法,将数据存入到缓冲区(数组)中,我们从缓冲区读数据是从数组中读取数据,当该数组中读完后,让read方法在读一次,把读到的数据存入到缓冲区中,。。。这样循环,直到,把数据源中的数据读完。

 

这里以定义 字节流缓冲区 为例

    class MyBufferedInputStream     {    private InputStream in;    private byte[] buf = new byte[1024];  //缓冲区,    private int pos = 0,count = 0;  //计数器,指针    MyBufferedInputStream(InputStream in)     {    this.in = in;    }    //调用一次 从缓冲区(字节数组)中读一个字节    public int myRead() throws IOException    {    //通过in对象读取硬盘上数据,并存储在缓冲区buf中    if(count==0)    {    count = in.read(buf);  //采用底层方法读取一批数据存入缓冲区,并返回其个数    if(count<0)    return -1;    pos = 0;   //指针归位,指向数组0角标开始    byte b = buf[pos];   // 指针指向的当前数据    count--;    pos++;    return b&255;  //返回读取到的数据    }    else if(count>0)  //如果缓冲区还有数据,则取缓冲区中的下一个数据,如缓冲区无数据(count=0时)则让底层read在去读一批数据存入缓冲区,直到读完    {    byte b = buf[pos];    count--;    pos++;    return b&255;    }    return -1;    }    public void myClose() throws IOException  //提供关闭流的方法    {    in.close();    }        }     /*    为什么要与255呢?    因为返回类型为int  而byte会自动提升    byte 1111  (-1)提升为:    int  1111 1111 1111 1111 (还是-1)                      前面填充了1使得一开始while ((by=bfis.myRead())!=-1)不满足没有进行循环    所以得填充0  只要与 0000 0000 0000 1111 进行与运算就能保证填充为0    1111 1111 1111 1111    &0000 0000 0000 1111       ----- -------------------------          0000 0000 0000 1111*/

 

流对象很多,使用时该用那一个呢?

流操作规律:通过两个明确来完成。

 

1,明确源和目的。

源:输入流。 InputStream(字节流)   Reader(字符流)

目的:输出流。  OutputStream(字节流)  Writer(字符流)

 

2,操作的数据是否是纯文本。

是:使用字符流。

不是:使用字节流。

 

1

将一个文本文件中的数据存储到别一个文件中(复制文件)

 

源: 

用读取流。InputStream   Reader

是文本文件 选Reader

操作文件对象的是 FileReader

 

要提高效率用:加入缓冲区

FileReader fr = new FileReader("a.txt");

BufferedReader bufr = new BufferedReader(fr);

 

目的: 

用 OutputStream   Writer

是纯文本 用Writer

操作文件 FileWriter

 

提高效率用:加入缓冲区

  FileWriter fw = new FileWriter("b.txt");

  BufferedWriter bufw = new BufferedWriter(fw);

 

2

把键盘输入的数据保存到一个文件中。 

 

源:  是纯文本,用Reader

设备:键盘,对应的对象是System.in(字节流)

为了操作键盘的文本数据方便,转成字符流按照字符串操作是最方便的

所以将System.in转换成Reader 即转换流InputStreamReader

InputStreadmReader isr = new InputStreamReader(System.in);

 

提高效率!->缓冲区

BufferedReader bufr = new BufferedReader(isr);

 

目的:是纯文本,用Writer

一个文件,使用FileWriter,当然也可以用OutputStreamWriter

FileWriter fw  = new FileWriter("c.txt");

BufferedWriter bufw = new BufferedWriter(fw);

 

*************************

扩展一下。

想要把录入的数据按照指定的编码表(UTF-8)存到文件中

目的:存储时,需要加入指定编码表。而指定的编码表只有转换流可以指定。

所以要使用的对象是OutputStreamWriter

而该转换流对象要接收一个字节输出流。而且还可以操作谁的的字节输出流FileOutputStream

OutputStreamWriter osw = new OutputStreamWriter( 

new FileOutputStream("d.txt"),"utf-8");

BufferedWriter bufw  = new BufferedWriter(osw);

 

Scanner

可以使用正则表达式来解析基本类型和字符串的简单文本扫描器

Scanner 使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空白匹配。然后可以使用不同的 next 方法将得到的标记转换为不同类型的值。

      Scanner sc = new Scanner(System.in);

      int i = sc.nextInt();

 

File

用于表示文件(目录),通过File类操作硬盘上的文件和目录。File类只用于表示文件的信息(名称,大小等),不能对文件的内容进行访问。

注意:File类的两个常量,如果想实现跨平台,那么最好使用下面的方法来代替分隔符

\ : File.separator

; : File.pathSeparator

 

在创建文件时,如果该目录下已有同名文件,将被覆盖。在写入数据的时候记得要将缓冲区的数据刷新到目的地中。

fw.flush();  //刷新流对象中的缓冲区中的数据,将数据刷新到目的地中

           fw.close();  //关闭流资源,但是关闭之前会刷新一次内部的缓冲区中的数据。

      //将数据刷到目的地中。流关闭后,不能在写入数据。

           closeflush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭

例:

//列出指定目录下的所有文件名称及其路径

     public static void method_2()     {     File f = new File("D:\\123");        File s[] = f.listFiles();    for(File fi : s)    {    System.out.println(fi);    }    }      //列出指定文件类型的文件(如:列出后缀名为.java的文件)    public static void method_3()    {    File f = new File("D:\\123");        File s[] = f.listFiles(new FilenameFilter()    {    public boolean accept(File dir,String name)    {    return name.endsWith(".txt");    }    });    for(File fi : s)    {    System.out.println(fi);    }    }

 

注意:在建立文件时,如果文件存在,继续往里面写入数据,

则传递一个true参数,代表不覆盖已有的文件 ,并在已有文件的末尾进行数据续写

如:fw = new FileWriter("D:\\123\\demo.txt",true);

文本文件中的换行语句  \r\n 

      FileDialog :选择文件对话框窗口 

System

System 类包含一些有用的类字段和方法。它不能被实例化。

在 System 类提供的设施中,有标准输入、标准输出和错误输出流;对外部定义的属性和环境变量的访问;加载文件和库的方法;还有快速复制数组的一部分的实用方法

 

System.in 默认是指键盘录入,还可以自己指定位置

    使用: System.setIn(InputStream in) ;

                如:System.setIn(new FileReader("123.txt")) ;

    源:就被设置成了一个文件

      System.out 输出位置也可设置

                 使用:setOut(PrintStream out) ;

                 如:System.setOut(new FileWriter("222.txt")) ;

     目的:输出位置设置成了一个文件

System.currentTimeMillis(); 返回当前系统时间,以毫秒计算。

 

常见的编码表

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

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

GB2312 : 中国的中文编码表。

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

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

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

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

注意:联通两个字,这两个字的GBK编码,UTF-8的规律相似


0 0