--------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Unity开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------
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(); //关闭流资源,但是关闭之前会刷新一次内部的缓冲区中的数据。
//将数据刷到目的地中。流关闭后,不能在写入数据。
close和flush区别: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的规律相似
---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Unity开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ---------------------