黑马程序员——Java基础---io(上)
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! ------
一、概述
Java I/O系统负责处理程序的输入和输出,I/O类库位于java.io包中,它对各种常见的输入流和输出流进行了抽象。如果数据流中最小的数据单元是字节,那么称这种流为字节流;如果数据流中最小的数据单元是字符,那么称这种流为字符流。在I/O类库中, java.io.InputStream 和 java.io.OutputStream 分别表示字节输入流和字节输出流,java.io.Reader 和 java.io.Writer分别表示字符输入流和字符输出流。我们有的时候把InputStream 和 OutputStream 直接称为输入流和输出流,而对于 Reader 和 Writer,则直接使用它们的英文类名。 IO流的常用基类如下:
字节流的抽象基类 :InputStream ,OutputStream
字符流的抽象基类 :Reader ,Writer
字节流和字符流的区别 :早期都是字节流,数据的体现形式都是字节(二进制数据),为了方便对“文本数据”的处理,解决编码表查询的问题,就产生了字符流。字符流基于字节流,并在字符流对象中融合了编码表。因此,字节流可以处理媒体文件(如:图片,视频);字符流只用来处理文本文件(即文字数据)。
一、正文
1、字节流
1.1 InputStream
InputStream是抽象类,本身并不能创建实例来执行输入,它里面包含如下几个方法:
1.Int read():从输入流中读取单个字节,返回所读取的字节数据。 2.int read(byte[] b):从输入流中最多读取b.length个字节的数据,并将其存储在字节数组b中,返回实际读取的字节数。 3.int read(byte[] b,int off,int len):从输入流中最多读取len个字节的数据,并将其存储在数组b中,放入数组b中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字节数。 4. int available() throws IOException:返回流中的有效字节数。 5 .long skip(long n) throws IOException: 忽略numBytes个字节,返回实际忽略的字节数 6.abstract void close() throws IOException: 关闭输入流
FileInputStream类(文件输入类)是实现子类:其创建一个能从文件读取字节的InputStream类,常用构造方法是:
FileInputStream(String filepath);
FileInputStream(File fileObject);
下面是一段代码,利用FileInputStream显示一个指定文本文件“read.txt”的内容。
class Test1{ Text1(InputStream in) throws Exception{ int len = in.available(); byte[ ] b = new byte[len]; in.read(b); System.out.println(new String(b)); in.close(); } public static void main(String[] args) throws Exception{ new Text1(new FileInputStream("read.txt")); } }
1.2 OutputStream
此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器,它的常用方法如下:
1.void close() :关闭此输出流并释放与此流有关的所有系统资源。 2.void flush() :刷新此输出流并强制写出所有缓冲的输出字节。 3.void write(byte[] b): 将 b.length 个字节从指定的字节数组写入此输 出流。 4.void write(byte[] b, int off, int len: 将指定字节数组中从偏移量 off 开始的 len 个字节写入此输出流。 5.abstract void write(int b) :将指定的字节写入此输出流。
FileOutputStream类(文件输出类)是常用实现子类:其创建一个可以向文件写入的类OutputStream,常用构造方法是:
FileOutputStream(String filepath);
FileOutputStream(File fileObject);
FileOutputStream(String filepath,boolean append);其中append为true时,表示向原文件追加写,即在文件的末尾处开始写。否则则从文件的开始处开始写。
下面是一段简单的练习代码:
class Copy{ Copy(InputStream in,OutputStream out) throws IOException{ int b; while((b = in.read()) != -1){ out.write(b); } in.close(); out.close(); } public static void main(String[] args)throws IOException{ new Copy(System.in, System.out); } }
1.3 字节流缓冲区
缓冲区技术提高了字节流的读写效率。它的两个方法:
1. read():会将字节byte型值提升为int型值
2. write():会将int型强转为byte型,即保留二进制数的最后八位。
具体的操作步骤如下:
- 先从数据中抓取固定数组长度的字节,存入定义的数组中,再通过然后再通过read()方法读取数组中的元素,存入缓冲区。
- 循环这个动作,直到最后取出一组数据存入数组,可能数组并未填满,同样也取出包含的元素。
- 每次取出的时候,都有一个指针在移动,取到数组结尾就自动回到数组头部,这样指针在自增。
- 取出的时候,数组中的元素在减少,取出一个,就减少一个,直到减到0即元素取完。
- 当文件中的全部数据都被读取出时,read()方法就返回-1。
2、字符流
2.1 Reader
Reader是字义Java的流式字符输入模式的抽象类,主要有以下几个方法
1.abstract void close():功能:关闭输入源。进一步的读取将会产生IOException; 2.void mark(int numChars):功能:在输入流的当前位置设置一个标志。该输入在numChars个字符被读取之前有效; 3.boolean markSupported():功能:该流支持mark()/reset()则返回true; 4.int read():功能:如果调用的输入流的下一个字符可读则返回一个整型。遇到文件末尾时返回-1; 5.int read( char buffer[]):功能:试图读取buffer中的buffer.length个字符地,返回实际成功读取的字符数。遇到文件末尾时返回-1; 6.abstract int read(char buffer[],int offset,int numChars):功能:试图读取buffer中从buffer[offset]开始的numChars个字符,返回实际成功读取的字符数。遇到文件尾返回-1; 7.boolean ready():功能:如果下一个输入请求不等待则返回true,否则返回false; 8.long skip(long numChars):功能:跳过numChars个输入字符,返回跳过的字符设置输入指针到先前设立的标志处。
FileReader类创建了一个可以读取文件内容的Reader类。构造方法:
FileReader(String filepath);
FileReader(File fileObject);
下面是一段练习代码:
public class WriterReaderTest { File f=new File("E:\\abc.txt"); public static void main(String[] args) throws IOException{ WriterReaderTest test=new WriterReaderTest(); test.writeFile("Java字符流读写文件测试!"); test.readFile(); } private void readFile() throws IOException{ Reader r=new BufferedReader(new FileReader(f)); int temp=0; String str=""; while ((temp=r.read())!=-1) { str+=(char)temp; } System.out.println("文件内容:"+str); } private void writeFile(String content) throws IOException { if (f.exists()==false) { f.createNewFile(); } Writer w=new FileWriter(f); w.write(content); w.flush(); w.close(); } }
2.2 Writer
Write是定义流式字符输出的抽象类,所有该类的方法都返回一个void值并在出错的条件下引IOException异常。其主要有以下几个方法:
1.void close():功能:关闭输出流 2.void flush():功能:刷新输出缓冲 3.void write(int ch):功能:向输出定稿单个字符地。注意参数是一个整型,它设计者不必把参数转换成字符型转换成字符型就可以调用write()方法 4.void write(char buffer[]):功能:向一个输出流写一个完整的字符数组 5.void wirte(char buffer[],int offset,int numChars):功能:向调用的输出流写入数组buffer以buffer[offset]为起点白N个numChars区域内的内容。 6.void write(String str):功能:向调用的流中写入字符串str; 7.void write(String str,int offset,int numChars):功能:写数组str中以指定的offset为起点的长度为numChars个字符区域内的内容
FileWriter类创建一个可以写文件的Writer类,构造方法:
FileWriter(String filePath)
FileWriter(String filePath,boolean append)
FileWrite(File fileObj);
下面是一段练习代码:
public static void main(String[] args) throws IOException { String str = "hello world!!!"; char[] buffer = new char[str.length()]; str.getChars(0, str.length(), buffer, 0); FileWriter fw = new FileWriter("D:/itzhai/arthinking.txt"); for(int i=0; i<buffer.length; i++){ fw.write(buffer[i]); } fw.close(); //创建FileReader BufferedReader br = new BufferedReader( new FileReader("D:/itzhai/arthinking.txt")); //使用BufferedReader提供的逐行读取函数读取文件 while(null != (str = br.readLine())){ System.out.println(str); } br.close(); }
2.3字符流的缓冲区——BufferedReader和BufferedWriter
缓冲区提高了流的读写效率,所以在缓冲区创建前,要先创建流对象。即先将流对象初始化到构造函数中。
缓冲技术具体实现步骤如下:
- 写入流缓冲区BufferedWriter的步骤:
1.1 创建一个字符写入流对象。
如:FileWriter fw=newFileWriter("buf.txt");
1.2 为了提高字符写入流效率。加入缓冲技术。只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
如: BufferedWriter bufw =new BufferedWriter(fw);
1.3 调用write方法写入数据到指定文件
如:bufw.write("adfg");
1.4 其实关闭缓冲区,就是在关闭缓冲区中的流对象。
如: bufw.close();
2.读取流缓冲区BufferedReader步骤
2.1 创建一个读取流对象和文件相关联
如: FileReader fr=newFileReader("buf.txt");
2.2 为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲区对象的构造函数。
如: BufferedReader bufr=new BufferedReader(fr);
2.3 调用该缓冲区提供的readLine方法一行一行读取,如果到达文件末尾,则返回null
如: String s=bufr.readLine();
2.4 关闭流资源
如: bufr.close();、
3、转换流
转换流是字符流与字节流之间的桥梁,方便了字符流与字节流之间的操作。转换流的应用:字节流中的数据都是字符时,转成字符流操作更高效。
InputStreamReader是将字节流通向字符流,例如键盘录入最常见写法是:
BufferedReaderin=newBufferedReader(new InputStreamReader(System.in));;
OutputStreamWriter是将字符流通向字节流。通常,涉及到字符编码转换时,需要用到转换流。
那么该怎样进行流操作,通过三个明确来完成:
1. 明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer
2. 操作的数据是否是纯文本。
是:字符流
否:字节流
3. 当体系明确后,再明确要使用哪个具体的对象。通过设备来进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
下面是一段简单的练习代码:
public class InputStreamReaderDemo { public static void main(String[] args) throws IOException { //获取标准输入流 InputStream in = System.in; //将字节流转换为字符流 InputStreamReader isr = new InputStreamReader(in); //将字符流装饰 BufferedReader br = new BufferedReader(isr); String string =null; while ((string=br.readLine())!=null) { if ("over".equals(string)) { break; } System.out.println(string.toUpperCase()); } }
三、总结
本文主要介绍了IO流的基本框架,即四个基类InputStream、OutputStream和Reader、Writer,以及它们分别对应的缓存技术,也就是所谓的装饰者模式,提高了IO的效率。最后简单的说下了转换流,它能够使字节流和字符流相互的转换。