Java IO:字节流与字符流

转自:http://www.cnblogs.com/lich/archive/2011/12/11/2283700.html

一般自己读取文件的方法:

FIle file=new FIle("path");

FileReader input=new FileReader(file);
BufferedReader buffer=new BufferedReader(input);
String temp;  //String 是一个最终类,如果字符串经常变化,需要使用StringBuffer类。新建一个temp的时候以前的tem对象依旧存在。(不知为何此处不定义StringBuffer)

//修改为:StringBuffer temp;  会报如下错;    其他人代码以及课本中都是使用string temp(能否使用StringBuffer)
while((temp=buffer.readLine())!= null){
i++;
}

input.close();  //一定要记得关闭,以前自己从来没关闭


和下文中的FileReader读取文件方法相比,主要区别:是自己的方法多了一个BufferedReader。BufferedReader将数据读取到缓冲区。这样子更方便操作。

字节流输出:

OutputStream out=new FileOutputStream(f);//如果文件不存在会自动创建
10 String str="Hello World";
11 byte[] b=str.getBytes();
12 out.write(b);//因为是字节流,所以要转化成字节数组进行输出
字节流输入:

File f = new File("d:" + File.separator+"test.txt");
9 InputStream in=new FileInputStream(f);
10 byte[] b=new byte[1024];
11 int len=in.read(b);
12 in.close();
13 System.out.println(new String(b,0,len));
字符流输出:

File f = new File("d:" + File.separator+"test.txt");
9 Writer out=new FileWriter(f);
10 String str="Hello World";
11 out.write(str);
12 out.close();
字符流输入:

 File f = new File("d:" + File.separator+"test.txt");
9 Reader input=new FileReader(f);
10 char[] c=new char[1024];
11 int len=input.read(c);
12 input.close();
13 System.out.println(new String(c,0,len));

System.in本身表示的是InputStream(字节流),现在要求接收的是一个字符流,需要将字节流变成字符流才可以,所以要用InputStreamReader

InputStreamReader:是Reader的子类,将输入的字节流变为字符流,即:将一个字节流的输入对象变成字符流的输入对象。

OutputStreamWriter:是Writer的子类,将输出的字符流变为字节流,即:将一个字符流的输出对象变成字节流的输出对象。

(上边这三个是如何将字节流转换为字符流 。)(关键的两种读取和写入的的方法,以及从System.in中读取的字节流,使用InputStreamReader转换为字符流)


先来看一下流的概念:

在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成。

程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。

字节流与字符流

在java.io包中操作文件内容的主要有两大类:字节流、字符流,两类都分为输入和输出操作。在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成。(这四个都是抽象类)

操作流程

在Java中IO操作也是有相应步骤的,以文件操作为例,主要的操作流程如下:

  1. 使用File类打开一个文件
  2. 通过字节流或字符流的子类,指定输出的位置
  3. 进行读/写操作
  4. 关闭输入/输出

IO操作属于资源操作,一定要记得关闭


字节流

字节流主要是操作byte类型数据,以byte数组为准,主要操作类就是OutputStream、InputStream

 

字节输出流:OutputStream

OutputStream是整个IO包中字节输出流的最大父类,此类的定义如下:

public abstract class OutputStream extends Objectimplements Closeable,Flushable

从以上的定义可以发现,此类是一个抽象类,如果想要使用此类的话,则首先必须通过子类实例化对象,那么如果现在要操作的是一个文件,则可以使用:FileOutputStream类。通过向上转型之后,可以为OutputStream实例化

Closeable表示可以关闭的操作,因为程序运行到最后肯定要关闭

Flushable:表示刷新,清空内存中的数据

FileOutputStream类的构造方法如下:

public FileOutputStream(File file)throws FileNotFoundException

写数据:

复制代码
 1 import java.io.File;
2 import java.io.FileOutputStream;
3 import java.io.IOException;
4 import java.io.OutputStream;
5
6 public class Test11 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 OutputStream out=new FileOutputStream(f);//如果文件不存在会自动创建
10 String str="Hello World";
11 byte[] b=str.getBytes();
12 out.write(b);//因为是字节流,所以要转化成字节数组进行输出
13 out.close();
14 }
15 }
复制代码

也可以一个字节一个字节进行输出,如下:

 

复制代码
 1 import java.io.File;
2 import java.io.FileOutputStream;
3 import java.io.IOException;
4 import java.io.OutputStream;
5
6 public class Test11 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 OutputStream out=new FileOutputStream(f);//如果文件不存在会自动创建
10 String str="Hello World";
11 byte[] b=str.getBytes();
12 for(int i=0;i<b.length;i++){
13 out.write(b[i]);
14 }
15 out.close();
16 }
17 }
复制代码

以上输出只会进行覆盖,如果要追加的话,请看FileOutputStream类的另一个构造方法:

public FileOutputStream(File file,boolean append)throws FileNotFoundException

在构造方法中,如果将append的值设置为true,则表示在文件的末尾追加内容。

 

复制代码
 1 import java.io.File;
2 import java.io.FileOutputStream;
3 import java.io.IOException;
4 import java.io.OutputStream;
5
6 public class Test11 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 OutputStream out=new FileOutputStream(f,true);//追加内容
10 String str="\r\nHello World";
11 byte[] b=str.getBytes();
12 for(int i=0;i<b.length;i++){
13 out.write(b[i]);
14 }
15 out.close();
16 }
17 }
复制代码

文件中换行为:\r\n

字节输入流:InputStream

既然程序可以向文件中写入内容,则就可以通过InputStream从文件中把内容读取进来,首先来看InputStream类的定义:

public abstract class InputStream extends Object implements Closeable

与OutputStream类一样,InputStream本身也是一个抽象类,必须依靠其子类,如果现在是从文件中读取,就用FileInputStream来实现。

观察FileInputStream类的构造方法:

public FileInputStream(File file)throws FileNotFoundException

读文件:

 

复制代码
 1 import java.io.File;
2 import java.io.FileInputStream;
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 public class Test12 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 InputStream in=new FileInputStream(f);
10 byte[] b=new byte[1024];
11 int len=in.read(b);
12 in.close();
13 System.out.println(new String(b,0,len));
14 }
15 }
复制代码

但以上方法是有问题的,用不用开辟这么大的一个字节数组,明显是浪费嘛,我们可以根据文件的大小来定义字节数组的大小,File类中的方法:public long length()

 

复制代码
 1 import java.io.File;
2 import java.io.FileInputStream;
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 public class Test13 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 InputStream in=new FileInputStream(f);
10 byte[] b=new byte[(int) f.length()];
11 in.read(b);
12 in.close();
13 System.out.println(new String(b));
14 }
15 }
复制代码

我们换种方式,一个字节一个字节读入~

 

复制代码
 1 import java.io.File;
2 import java.io.FileInputStream;
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 public class Test14 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 InputStream in=new FileInputStream(f);
10 byte[] b=new byte[(int) f.length()];
11 for(int i=0;i<b.length;i++){
12 b[i]=(byte) in.read();
13 }
14 in.close();
15 System.out.println(new String(b));
16 }
17 }
复制代码

但以上情况只适合知道输入文件的大小,不知道的话用如下方法:

 

复制代码
 1 import java.io.File;
2 import java.io.FileInputStream;
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 public class Test15 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 InputStream in=new FileInputStream(f);
10 byte[] b=new byte[1024];
11 int temp=0;
12 int len=0;
13 while((temp=in.read())!=-1){//-1为文件读完的标志
14 b[len]=(byte) temp;
15 len++;
16 }
17 in.close();
18 System.out.println(new String(b,0,len));
19 }
20 }
复制代码


字符流

在程序中一个字符等于两个字节,那么java提供了Reader、Writer两个专门操作字符流的类。


字符输出流:Writer

Writer本身是一个字符流的输出类,此类的定义如下:

public abstract class Writer extends Object implementsAppendable,Closeable,Flushable

此类本身也是一个抽象类,如果要使用此类,则肯定要使用其子类,此时如果是向文件中写入内容,所以应该使用FileWriter的子类。

FileWriter类的构造方法定义如下:

public FileWriter(File file)throws IOException

字符流的操作比字节流操作好在一点,就是可以直接输出字符串了,不用再像之前那样进行转换操作了。

写文件:

 

复制代码
 1 import java.io.File;
2 import java.io.FileWriter;
3 import java.io.IOException;
4 import java.io.Writer;
5
6 public class Test16 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 Writer out=new FileWriter(f);
10 String str="Hello World";
11 out.write(str);
12 out.close();
13 }
14 }
复制代码

在默认情况下再次输出会覆盖,追加的方法也是在构造函数上加上追加标记

 

复制代码
 1 import java.io.File;
2 import java.io.FileWriter;
3 import java.io.IOException;
4 import java.io.Writer;
5
6 public class Test17 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 Writer out=new FileWriter(f,true);//追加
10 String str="\r\nHello World";
11 out.write(str);
12 out.close();
13 }
14 }
复制代码


字符输入流:Reader

Reader是使用字符的方式从文件中取出数据,Reader类的定义如下:

public abstract class Reader extends Objects implements Readable,Closeable

Reader本身也是抽象类,如果现在要从文件中读取内容,则可以直接使用FileReader子类。

FileReader的构造方法定义如下:

public FileReader(File file)throws FileNotFoundException

以字符数组的形式读取出数据:

 

复制代码
 1 import java.io.File;
2 import java.io.FileReader;
3 import java.io.IOException;
4 import java.io.Reader;
5
6 public class Test18 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 Reader input=new FileReader(f);
10 char[] c=new char[1024];
11 int len=input.read(c);
12 input.close();
13 System.out.println(new String(c,0,len));
14 }
15 }
复制代码

也可以用循环方式,判断是否读到底:

 

复制代码
 1 import java.io.File;
2 import java.io.FileReader;
3 import java.io.IOException;
4 import java.io.Reader;
5
6 public class Test19 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 Reader input=new FileReader(f);
10 char[] c=new char[1024];
11 int temp=0;
12 int len=0;
13 while((temp=input.read())!=-1){
14 c[len]=(char) temp;
15 len++;
16 }
17 input.close();
18 System.out.println(new String(c,0,len));
19 }
20 }
复制代码


字节流与字符流的区别

字节流和字符流使用是非常相似的,那么除了操作代码的不同之外,还有哪些不同呢?

字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的

字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容(如下代码:确实没有输出内容),说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容

FileReader input=new FileReader(file);
BufferedReader buffer=new BufferedReader(input);
// String file1="C:\\Users\\Administrator\\Desktop\\1.txt";
FileWriter out=new FileWriter(file1,true);
String temp;
StringBuffer tes=new StringBuffer();
while((temp=buffer.readLine())!= null){
i++;
System.out.println(temp);
out.write(temp);
}
input.close();
// out.close();
   注释掉以后输出文件中没有内容


那开发中究竟用字节流好还是用字符流好呢?

在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。

如果要java程序实现一个拷贝功能,应该选用字节流进行操作(可能拷贝的是图片),并且采用边读边写的方式(节省内存)。


由于输入文件中包含的是字符数据,所以采用字符流更加方便。那么为什么还要使用字节流,因为所有其他流都是建立在字节流的基础之上。字符流的工作是建立在字节流的基础之上的,比如读入数据的Reader,首先使用InputStream流读入字节,然后完成字节到字符的转换,所有物理层的I/O由字节流来完成。可以这么理解,字符流只是把字节流做了包装,加入一些转换功能,但是这样我们使用起来具更方便。面向字节的可以被封装成面向字符,同样的,面向字符的也可以进一步封装成面向行的

2.1 为何需要缓冲流

因为每一次读取、写入操作都操作一次磁盘的话,会很耗时。

3. Scanning and formatting

在有些情况下,一次读入一个字节、一个字符或者一行都不能满足我们的要求,比如对于一个英文文本,我们想要一次读入一个单词,这时候需要更高级的流来满足要求,Java提供了一个Scanner类来完成这一功能。同样的,对于输出我们可能也想要按照一定的格式输出,格式化流(stream that implement formatting)提供这一功能,PrintWriter提供字符流的格式化输出,PrintStream实现字节流的格式化输出。

3.2 formatting: PrintWriter & PrintStream

这两个类允许我们在写入数据的时候,指定各种输出格式。除了基本的写入功能外,最主要的是三个方法:print、println、format。具体参考API文档。

一下参考自:http://blog.csdn.net/u011393661/article/details/15699051

Java的io包主要包括: 

1. 两种流:字节流(byte Stream)和字符流(character stream),这两种流不存在所谓的谁代替谁、谁比谁高级之说,它们互为补充,只是侧重点不同而已。

2. 两种对称:1.字节流、字符流的对称;2.输入、输出的对称。 

3. 一个桥梁:将字节流转变为字符流的InputStreamReader和OutputStreamWriter。 

其中必须注意: 

1. PipedInputStream和PipedOutputStrem是两个比较有趣的类。 

2. 支持Buffered的流是我们经常使用的类。 

3. 装饰器(Decorator)模式在java最著名的应用就是用于io的设计。仔细研究各个Filter流与具体流的关系,多看设计模式的书籍。相信你会有所所获。 

4. 学习好io包,是研究net包,rmi包……的基础哦!



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值