Java - 流操作

字节流

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

字节输出流:OutputStream

FileOutputStream类的定义:

public abstract class OutputStream extends Object implements Closeable,Flushable

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

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

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

FileOutputStream类的构造方法如下:

public FileOutputStream(File file)throws FileNotFoundException

使用不同输出流对同一文件进行输出会覆盖其他流的输出内容,如果要追加的话,请看FileOutputStream类的另一个构造方法:

public FileOutputStream(File file,boolean append)throws FileNotFoundException

它会锁定文件尾部添加。

字节输入流:InputStream

InputStream类的定义:

public abstract class InputStream extends Object implements Closeable

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

观察FileInputStream类的构造方法:

public FileInputStream(File file)throws FileNotFoundException

主要方法:
read():

public abstract int read() throws IOException;

read(byte b[]):相当于 read(b, 0, b.length)

public int read(byte b[]) throws IOException {
   return read(b, 0, b.length);
}

read(byte b[], int off, int len):返回 0 表示存放字节数组为空,返回 -1 表示流末尾无法读取,返回读取的字节数(i + 1)≤ 存放字节数组长度

public int read(byte b[], int off, int len) throws IOException {
    if (b == null) {
        throw new NullPointerException();
    } else if (off < 0 || len < 0 || len > b.length - off) {
        throw new IndexOutOfBoundsException();
    } else if (len == 0) {
        return 0;
    }

    int c = read();
    if (c == -1) {
        return -1;
    }
    b[off] = (byte)c;

    int i = 1;
    try {
        for (; i < len ; i++) {
            c = read();
            if (c == -1) {
                break;
            }
            b[off + i] = (byte)c;
        }
    } catch (IOException ee) {
    }
    return i;
}

Tips:根据文件的大小来定义字节数组的大小,使用 File类中的方法:public long length()

字符流

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

字符输出流:Writer

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

public abstract class Writer extends Object implements Appendable,Closeable,Flushable

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

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

public FileWriter(File file)throws IOException

使用 FileWriter(File file, boolean append) 在文件末尾输入

字符输入流:Reader

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

public abstract class Reader extends Objects implements Readable,Closeable

Reader本身也是抽象类,需要子类实现其功能,InputStreamReader 就是一个实现类

public class InputStreamReader extends Reader {

  • 使用方式 1:
reader = new InputStreamReader(fip, "UTF-8");
while (reader.ready()) {
    System.out.println((char) reader.read());
}
  • 使用方式 2:
InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
int in;
while ((in = reader.read()) != -1) {
    System.out.println((char) in);
}

ready() 的实现:

指示此流是否准备好读取。如果inputstreamreader的输入缓冲区不是空的,或者如果可以从底层字节流读取字节,那么它就准备好了。

public boolean ready() throws IOException {
    return sd.ready();
}
private final StreamDecoder sd;

StreamDecoder

public boolean ready() throws IOException {
    synchronized(this.lock) {
        this.ensureOpen();
        return this.haveLeftoverChar || this.implReady();
    }
}
boolean implReady() {
    return this.bb.hasRemaining() || this.inReady();
}
private boolean inReady() {
    try {
        return this.in != null && this.in.available() > 0 || this.ch instanceof FileChannel;
    } catch (IOException var2) {
        return false;
    }
}
private ByteBuffer bb;

ByteBuffer

缓存区当前位置和缓存限制位数之间是否至少有一个以上元素

public final boolean hasRemaining() {
    return position < limit;
}

如果现在要从文件中读取内容,则可以直接使用FileReader子类。
FileReader 类的定义:

public class FileReader extends InputStreamReader {

FileReader的构造方法定义如下:

public FileReader(File file)throws FileNotFoundException

使用方式:

Reader input=new FileReader(f);
int in;
while((in = input.read()) != -1){
	System.out.println((char) in);
}

字节流与字符流的区别

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

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

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

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

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

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


原文:字节流与字符流的区别详解

InputStreamReader

java.lang.Object  
	java.io.Reader  
		java.io.InputStreamReader

InputStreamReader 将字节流转换为字符流。是字节流通向字符流的桥梁。如果不指定字符集编码,该解码过程将使用平台默认的字符编码。
参数 in 对象通过 InputStream in = System.in 用来读取键盘上的数据。
或者 InputStream in = new FileInputStream(String fileName) 用来读取文件中的数据。可以看出 FileInputStream 为InputStream的子类。

主要方法:
int read(); //读取单个字符,返回值为字符 ASCII 码,-1 表示到达流的末尾。
int read(char []cbuf); //将读取到的字符存到数组中。返回读取的字符数。

BufferedReader

java.lang.Object  
	java.io.Reader  
		java.io.BufferedReader

提供缓存读取方式,提高效率。

FileReader

FileReader 继承 InputStreamReader,用来包装 FileInputStream 流:

public class FileReader extends InputStreamReader

实际是使用 InputStreamReader 的默认构造函数,传入新建 FileInputStream 流进行构造:

public FileReader(String fileName) throws FileNotFoundException {
    super(new FileInputStream(fileName));
}

public FileReader(File file) throws FileNotFoundException {
    super(new FileInputStream(file));
}

优点是减少代码,提高简洁性:不用新建 InputStreamReader
缺点是使用系统默认编码,指定编码还需新建 InputStreamReader:

InputStreamReader inReader = new InputStreamReader(file, "UTF-8"); 

OutputStreamWriter

java.lang.Object  
	java.io.Reader  
		java.io.OutputStreamReader

同 InputStreamReader,可以提供编码解码方式。

BufferedWriter

java.lang.Object  
	java.io.Reader  
		java.io.BufferedWriter

提供缓存写入方式,提高效率,降低硬盘的磨损。

FileWriter

java.lang.Object
	java.io.Writer
		java.io.OutputStreamWriter
			java.io.FileWriter

用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter(也就是说,使用默认字符编码,就不需要构造 OutputStreamWriter 而直接使用了)。

示例:

/** 
 * 使用 FileWriter 写入文件
 */  
public void writeToFileUseFileWriter(String fileName, String content) {  
    try {  
        // 打开一个写文件器,构造函数中的第二个参数 true 表示以追加形式写文件  
        FileWriter writer = new FileWriter(fileName, true);  
        writer.write(content);
        writer.close();
    } catch (IOException e) {  
        e.printStackTrace();  
    }  
}  

PrintWriter

java.lang.Object
	java.io.Writer
		java.io.PrintWriter

使用 println 方法用平台行分隔符自动换行。
PrintWriter有含有 OutputStream、File、Writer 的构造方法。BufferedWriter 只接受 writer。
基本上这两个类都差不多,用哪个都可以,PrintWriter 稍好

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值