文件操作的字节流和字符流

在java.io包中流的操作主要有字节流、字符流两大类,两类都有输入和输出操作。在字节流中输出数据主要使用OutputStream类完成,输入使用的是InputStream类。

在字符流中输出主要是使用Writer类完成,输入主要是使用Reader类完成。

这四个类都是抽象类,使用中需通过子类进行实例化(向上转型),或者直接使用子类进行io操作。

文件操作的字节流 FileOutputStream,FileInputStream。文件操作的字符流 FileWriter,FileReader。

一.字节流

  字节流主要操作byte类型数据。

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

   public abstract class OutputStream implements Closeable, Flushable

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

   public abstract class InputStream implements Closeable

  1.文件字节输出流

    定义如下:

      public class FileOutputStream extends OutputStream

   核心方法:

    (1)核心构造方法:从源码分析,构造函数的核心作用对文件执行open操作。

 1     public FileOutputStream(File file, boolean append)
 2         throws FileNotFoundException
 3     {
 4         String name = (file != null ? file.getPath() : null);
 5         SecurityManager security = System.getSecurityManager();
 6         if (security != null) {
 7             security.checkWrite(name);
 8         }
 9         if (name == null) {
10             throw new NullPointerException();
11         }
12         if (file.isInvalid()) {
13             throw new FileNotFoundException("Invalid file path");
14         }
15         this.fd = new FileDescriptor();
16         fd.attach(this);
17         this.append = append;
18         this.path = name;
19         open(name, append);//继续向下看
20     }
1     private void open(String name, boolean append)
2         throws FileNotFoundException {
3         open0(name, append);//继续
4     }
1     private native void open0(String name, boolean append)
2         throws FileNotFoundException;
3 //到此在往下就是调用native层的open0函数了。

    (2)write和writeBytes函数最终调用的也是navite的write和writeBytes函数

1     private native void write(int b, boolean append) throws IOException;
2
3     private native void writeBytes(byte b[], int off, int len, boolean append)
4         throws IOException;

    2.文件字节输入流

    定义如下:

    (1)核心构造方法,从源码分析,构造函数的核心作用对文件执行open操作。

 1     public FileInputStream(File file) throws FileNotFoundException {
 2         String name = (file != null ? file.getPath() : null);
 3         SecurityManager security = System.getSecurityManager();
 4         if (security != null) {
 5             security.checkRead(name);
 6         }
 7         if (name == null) {
 8             throw new NullPointerException();
 9         }
10         if (file.isInvalid()) {
11             throw new FileNotFoundException("Invalid file path");
12         }
13         fd = new FileDescriptor();
14         fd.attach(this);
15         path = name;
16         open(name);//继续
17     }
1     private void open(String name) throws FileNotFoundException {
2         open0(name);
3     }
1     private native void open0(String name) throws FileNotFoundException;

    (2)read和readBytes函数最终调用的也是navite的read0和readBytes函数

1     private native int read0() throws IOException;
2
3     private native int readBytes(byte b[], int off, int len) throws IOException;

二.字符流

  程序中一个字符代表两个字节。

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

    public abstract class Writer implements Appendable, Closeable, Flushable

  Reader是整个IO包中字符输入流的最大父类,定义如下:

    public abstract class Reader implements Readable, Closeable

  1.文件字符输出流

    定义如下:

      public class FileWriter extends OutputStreamWriter // OutputStreamWriter是Writer的子类

    (1)源码:

 1 public class FileWriter extends OutputStreamWriter {
 2
 3     public FileWriter(String fileName) throws IOException {
 4         super(new FileOutputStream(fileName));
 5     }
 6
 7     public FileWriter(String fileName, boolean append) throws IOException {
 8         super(new FileOutputStream(fileName, append));
 9     }
10
11     public FileWriter(File file) throws IOException {
12         super(new FileOutputStream(file));
13     }
14
15     public FileWriter(File file, boolean append) throws IOException {
16         super(new FileOutputStream(file, append));
17     }
18
19     public FileWriter(FileDescriptor fd) {
20         super(new FileOutputStream(fd));
21     }
22
23 }

  可以看到它所有的构造方法调用的都是其父类的构造方法,并且传递一个FileOutputStream类的实例进去。

随便举一个父类构造方法的例子 (其他最终也是调用StreamEncoder.forOutputStreamWriter)

1    public OutputStreamWriter(OutputStream out, Charset cs) {
2         super(out);
3         if (cs == null)
4             throw new NullPointerException("charset");
5         se = StreamEncoder.forOutputStreamWriter(out, this, cs);//从字符到字节的编码过程,将字符流转换为字节流。
6     }

    (2)其write方法是继承其父类OutputStreamWriter的write方法

随便举一个例子(其他最终也是调用se.write)

    public void write(String str, int off, int len) throws IOException {
        se.write(str, off, len);
    }
/*其中se定义如下*/
    private final StreamEncoder se;//它由前面介绍的构造函数实例化

    2.文件字符输入流

    定义如下:

      public class FileReader extends InputStreamReader  // InputStreamReader 是 Reader的子类

    (1)源码

 1     public FileReader(String fileName) throws FileNotFoundException {
 2         super(new FileInputStream(fileName));
 3     }
 4
 5     public FileReader(File file) throws FileNotFoundException {
 6         super(new FileInputStream(file));
 7     }
 8
 9     public FileReader(FileDescriptor fd) {
10         super(new FileInputStream(fd));
11     }

  可以看到它所有的构造方法调用的都是其父类的构造方法,并且传递一个FileIntputStream类的实例进去。

随便举一个例子(其他最终调用也是StreamDecoder.forInputStreamReader)

1     public InputStreamReader(InputStream in, String charsetName)
2         throws UnsupportedEncodingException
3     {
4         super(in);
5         if (charsetName == null)
6             throw new NullPointerException("charsetName");
7         sd = StreamDecoder.forInputStreamReader(in, this, charsetName);//从字节到字符的解码过程,将字节流转换为字符流
8     }

来看一下StreamDecode的源码

 1 public class StreamDecoder extends Reader{
 2     private static final int MIN_BYTE_BUFFER_SIZE = 32;
 3     private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
 4     private Charset cs;
 5     private CharsetDecoder decoder;
 6     private ByteBuffer bb;
 7
 8     // 由上述的 forInputStreamReader方法的参数可知用的是下面这个方法
 9     public static StreamDecoder forInputStreamReader(InputStream in,Object lock,String charsetName) throws UnsupportedEncodingException {
10         String csn = charsetName;
11        if (csn == null) // 由于用的是默认编码,会执行这句
12        csn = Charset.defaultCharset().name();
13        try {
14         if (Charset.isSupported(csn))   // 检测JVM是否支持该编码集
15
16               return new StreamDecoder(in, lock, Charset.forName(csn));  //调用其构造方法实例化一个对象
17        } catch (IllegalCharsetNameException x) { }
18               throw new UnsupportedEncodingException (csn);
19     }
20
21     StreamDecoder(InputStream in, Object lock, Charset cs) {
22         this(in, lock, cs.newDecoder().onMalformedInput(CodingErrorAction
23                         .REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE));
24         // 额,说明它是在用Charset对象产生CharsetDecoder对象,目的是为了执行另一个构造函数
25     }
26
27     StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) {
28         //  CharsetDecoder:是一个引擎,可以将一个字节序列按照特定的字符集转换成一个16位的Unicode序列
29              super(lock);
30              this.cs = dec.charset();
31              this.decoder = dec;
32         // 下面的代码先不用管,我们这里用不上
33              // This path disabled until direct buffers are faster
34              if (false && in instanceof FileInputStream) {
35                     ch = getChannel((FileInputStream)in);
36                     if (ch != null)
37                         bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
38                 }
39                 if (ch == null) {
40                     this.in = in;
41                     this.ch = null;
42                     bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
43                 }
44                 bb.flip();                      // So that bb is initially empty
45     }
46     // 调用的就是这个函数吧
47     public int read() throws IOException {
48         return read0(); //额,又是假的;继续看
49     }
50     private int read0() throws IOException {
51         synchronized (lock) {
52             // Return the leftover char, if there is one
53             if (haveLeftoverChar) {
54                 haveLeftoverChar = false;
55                 return leftoverChar;
56             }
57             // Convert more bytessz
58             char cb[] = new char[2];    //一次读两个字节
59             int n = read(cb, 0, 2);
60             switch (n) {
61                 case -1:
62                     return -1;
63                 case 2:
64                     leftoverChar = cb[1];
65                     haveLeftoverChar = true;
66                 // FALL THROUGH
67                 case 1:
68                     return cb[0];
69                 default:
70                     assert false : n;
71                     return -1;
72             }// end of catch
73         }// end of  synchronized
74     }
75
76 }

    (2) read操作见上面的源码

时间: 2024-12-29 11:43:31

文件操作的字节流和字符流的相关文章

java的IO操作:字节流与字符流操作

流的概念 程序中的输入输出都是以流形式,流中保存的实际上都是字节文件. 字节流与字符流 字节流的操作: 1)输入:inputStream, 2)输出:outPutStream; 字符流的操作: 1)输入主要使用:write类. 2)输出主要使用:reader类. 内容操作就四个类. 操作流程: 使用File类操作一定有路径问题,注意分隔符: 实际上四个操作类都是抽象类(区别接口,抽象类的成员都是抽象,并且只能单继承,接口可以有全局变量,但是接口可以多继承) IO操作属于资源操作,对于资源操作,操

java 字节流与字符流的区别

字节流与和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的不同呢? 实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件,如图12-6所示.下面以两个写文件的操作为主进行比较,但是在操作时字节流和字符流的操作完成之后都不关闭输出流. 范例:使用字节流不关闭执行 package org.lxh.demo12.byteiodemo; import java.io.File; import java.io.FileO

转载:字节流与字符流的理解

字节流与字符流 先来看一下流的概念: 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件. 字节流与字符流 在java.io包中操作文件内容的主要有两大类:字节流.字符流,两类都分为输入和输出操作.在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成

字节流与字符流的区别详解

字节流与字符流 先来看一下流的概念: 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件. 字节流与字符流 在java.io包中操作文件内容的主要有两大类:字节流.字符流,两类都分为输入和输出操作.在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成

java 字节流和字符流的区别

转载自:http://blog.csdn.net/cynhafa/article/details/6882061 字节流与和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的不同呢?实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件,如图12-6所示.  下面以两个写文件的操作为主进行比较,但是在操作时字节流和字符流的操作完成之后都不关闭输出流.范例:使用字节流不关闭执行 package org.lxh.dem

Java核心知识点-字节流和字符流详解

字节流与和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的不同呢? 区别:实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件,如图12-6所示. 下面以两个写文件的操作为主进行比较,但是在操作时字节流和字符流的操作完成之后都不关闭输出流. 范例:使用字节流不关闭执行 Java代码   package org.lxh.demo12.byteiodemo; import java.io.File; import 

JAVA 字节流和字符流度读写的区别

java处理文件的类里面,stream结尾都是采用字节流,reader和writer结尾都是采用字符流.两者的区别就是读写的时候一个是按字节读写,一个是按字符. 字符流的底层就是字节流.而字符流主要是读取文本文件内容的,可以一个字符一个字符的读取,也可以一行一行的读取文本文件内容.而字节流读取单位为byte.byte作为计算机存储最基本单位,可以用字节流来读取很多其他格式的文件,比如图片视频等等.基于B/S和C/S的文件传输都可以采用字节流的形式.在读写文件需要对内容按行处理,比如比较特定字符,

字节流与字符流详解

字节流与字符流 先来看一下流的概念: 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件. 字节流与字符流 在java.io包中操作文件内容的主要有两大类:字节流.字符流,两类都分为输入和输出操作.在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成

字节流与字符流的区别详解(转)

转载:http://blog.csdn.net/zxman660/article/details/7875799 字节流与字符流 先来看一下流的概念: 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件. 字节流与字符流 在Java.io包中操作文件内容的主要有两大类:字节流.字符流,两类都分为输入和输出操作.在字节流中输出数据主