java中的IO流

目录
  • java中的IO流
    • 1.普通字节流
    • 2.字节缓冲流
    • 3.转换流
    • 4.常用的IO类FileReader和BufferedReader
    • 5.总结

java中的IO流

前言:

在java中IO类很庞大,初学的时候觉得傻傻分不清楚。其实java流归根结底的原理是普通字节流,字节缓冲流,转换流。最基础的是普通字节流,即从硬盘读取字节写入到内存中,但在实际使用中又发现一些特殊的需求,所以java语言的设计者这引入了字节缓冲流和转换流。所有的java IO类对IO的处理都是基于这三种流中的一种或多种;在介绍完三种流的概念之后,会对IO流的部分java类做介绍。

1.普通字节流

以FileInputStream为例子。FileInputStream的硬盘读取方式分为两种,一次读取一个字节和一次读取一个字节数组。字节数组的大小不同,实际IO耗时也不同,1为示例代码,3展示了1代码中读写耗时随字节数组大小的变化趋势。随着字节数组的增大,读写耗时减小,主要是硬盘寻道时间(seek time)和旋转时间(rotational latency)的减少。在硬盘读写耗时很长时,内存读写的耗时相比硬盘读写可以忽略,硬盘读写的耗时分为寻道时间(seek time)、旋转时间(rotational latency)和传输时间(transfer time),传输时间相对于寻道时间和旋转时间(寻道时间和旋转时间后合并称为寻址时间)可以忽略【1】。硬盘的寻址时间在一个块中的第一个字节耗时长,一个块中的其余字节可以忽略。当字节数组增大时(从32增加到1024*16 byte),寻址一个块中的第一个字节的场景线性减少,寻址时间也线性减少,因此IO耗时呈线性减少趋势。当字节数组大小继续增大(从1024 * 8增加到1024 * 1024 * 16),此时寻址时间已降到很低,相比传输时间可以忽略时,IO耗时的变化趋于平稳。当字节数组大小继续增大时,读写耗时又出现增大的趋势,这个我还没找到原因。当在数组较大(大于1024 *1024 *4)时,read(byte[])方法中除去读写之外也会有其它耗时,测试代码如2,测试数据如图3附表,这个机制我还不清楚(可能需要深入了解jvm的底层实现了),3中在计算读写耗时时应减去这部分时间。

示例代码

public class Demo01_Copy {

 public static void main(String[] args) throws IOException {
  File src = new File ("e:\\foxit_Offline_FoxitInst.exe");
  File dest = new File("e:\\ithema\\foxit_Offline_FoxitInst.exe");

  byte[] bytes = new byte[1024*128];//调整字节数组的大小,看IO耗时的变化
  long time1 = System.currentTimeMillis();
  copyFile2(src,dest,bytes);
  long time2 = System.currentTimeMillis();
  System.out.println(time2 -time1);
 }

 public static void copyFile2(File src,File dest,byte[] bytes) throws IOException{
  InputStream in = new FileInputStream(src);
  OutputStream os = new FileOutputStream(dest);

  int len = 0;
  while((len = in.read(bytes))!=-1){
   os.write(bytes,0,len);
  }
  in.close();
  os.close();
 }
}

1.通过FileInputStream一次读取一个字节数组

public class Demo02_Copy {
    public static void main(String[] args) throws IOException {
        File src = new File ("e:\\1.txt");
        File dest = new File("e:\\ithema\\1.txt");

        byte[] bytes = new byte[1024*128];//调整字节数组的大小,看IO耗时的变化
        long time1 = System.currentTimeMillis();
        copyFile2(src,dest,bytes);
        long time2 = System.currentTimeMillis();
        System.out.println(time2 -time1);
    }

    public static void copyFile2(File src,File dest,byte[] bytes) throws IOException{
        InputStream in = new FileInputStream(src);
        OutputStream os = new FileOutputStream(dest);

        int len = 0;
        while((len = in.read(bytes))!=-1){
            os.write(bytes,0,len);
        }
        in.close();
        os.close();
    }
}

2.测试除硬盘内存读写外的其它耗时(1.txt文件为空)

3.当字节数组大小变化,读写总耗时的变化趋势(折线图数据来源于表格中蓝色背景填充的数据)

当数组大小从32逐渐增大到1024*16byte时,IO耗时呈线性减少,这基于FileInputStream的read(byte[])实现。read(byte[])的源码如4所示,read(byte b[])是一个本地方法,它保证了硬盘的寻址时间在读取一个数组大小的字节块的第一个字节耗时较长,字节块的其余字节可以忽略。而相对于read()方法,一个字节一个字节读取,每读取一个字节都要重新进行硬盘寻址。

public class FileInputStream extends InputStream
{
    public int read(byte b[]) throws IOException {
        return readBytes(b, 0, b.length);
    }

     /**
     * Reads a subarray as a sequence of bytes.
     * @param b the data to be written
     * @param off the start offset in the data
     * @param len the number of bytes that are written
     * @exception IOException If an I/O error has occurred.
     */
    private native int readBytes(byte b[], int off, int len) throws IOException;
}

4.FileInputStream 的 read(byte[]) 方法源码

2.字节缓冲流

假设现在你要写一个程序以计算一个text文件的行数。一种方法是使用read()方法从硬盘中一次读取1个字节到内存中,并检查该字节是不是换行符“\n”【2】。这种方法已被证明是低效的。

更好的方法是使用字节缓冲流,先将字节从硬盘一次读取一个缓冲区大小的字节到内存中的读缓冲区,然后在从读缓冲区中一次读取一个字节。在逐字节读取读取缓冲区时,检查字节是不是换行符'\n'。字节缓冲流BufferedInputStream的源码如5所示,先从硬盘读取一个缓冲大小的字节块到缓冲区,然后逐个读取缓冲区的字节;当缓冲区的字节读取完毕后,在调用fill()方法填充缓冲区。字节缓冲流BufferedInputStream的缓冲区大小为8192。6中对比了字节缓冲流和普通字节流的读写效率;字节缓冲流的读耗时仅为8ms,而没有缓冲区的普通字节流的耗时为567ms。图7中展示了6中字节缓冲流读写文件的示意图。

public class BufferedInputStream extends FilterInputStream {
    private static int DEFAULT_BUFFER_SIZE = 8192;

 public synchronized int read() throws IOException {
        //当缓冲区的字节已被读取完毕后,调用fill()方法从硬盘读取字节块填充缓冲区;
        if (pos >= count) {
            fill();
            if (pos >= count)
                return -1;
        }
        //返回缓冲区的一个字节
        return getBufIfOpen()[pos++] & 0xff;
    }

 private void fill() throws IOException {
        byte[] buffer = getBufIfOpen();
        //初始定义int markpos = -1;
        if (markpos < 0)
            pos = 0;            /* no mark: throw away the buffer */
        else if (pos >= buffer.length)  /* no room left in buffer */
            if (markpos > 0) {  /* can throw away early part of the buffer */
                int sz = pos - markpos;
                System.arraycopy(buffer, markpos, buffer, 0, sz);
                pos = sz;
                markpos = 0;
            } else if (buffer.length >= marklimit) {
                markpos = -1;   /* buffer got too big, invalidate mark */
                pos = 0;        /* drop buffer contents */
            } else if (buffer.length >= MAX_BUFFER_SIZE) {
                throw new OutOfMemoryError("Required array size too large");
            } else {            /* grow buffer */
                int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
                        pos * 2 : MAX_BUFFER_SIZE;
                if (nsz > marklimit)
                    nsz = marklimit;
                byte nbuf[] = new byte[nsz];
                System.arraycopy(buffer, 0, nbuf, 0, pos);
                if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
                    // Can't replace buf if there was an async close.
                    // Note: This would need to be changed if fill()
                    // is ever made accessible to multiple threads.
                    // But for now, the only way CAS can fail is via close.
                    // assert buf == null;
                    throw new IOException("Stream closed");
                }
                buffer = nbuf;
            }
        count = pos;
        //从硬盘读取一个缓冲区大小的块到缓冲区
        int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
        if (n > 0)
            count = n + pos;
    }
}

5.BufferedInputStream的read()方法源码

public class Demo03_Copy {

 public static void main(String[] args) throws IOException {
  File src = new File ("e:\\settings.xml");
  File dest = new File("e:\\ithema\\settings.xml");

  byte[] bytes = new byte[1024*128];
  long time1 = System.currentTimeMillis();
  //耗时:567 ms
        //copyFile1(src,dest);
  //耗时:8 ms
  copyFile3(src,dest);
  long time2 = System.currentTimeMillis();
  System.out.println(time2 -time1);
 }

    //使用普通字节流
 public static void copyFile1(File src,File dest) throws IOException{
  InputStream in = new FileInputStream(src);
  OutputStream os = new FileOutputStream(dest);
  int len = 0;
  int lineSum = 1;
  while((len = in.read())!= -1){
   if(len == '\n'){
    lineSum++;
   }
   os.write(len);
  }
  System.out.println("lineSum:"+lineSum);
  in.close();
  os.close();
 }

    //使用字节缓冲流
 public static void copyFile3(File src,File dest) throws IOException{

  InputStream in = new BufferedInputStream(new FileInputStream(src));
  OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));

  int len = 0;
  int lineSum = 1;
  while((len = in.read())!=-1){
   if(len == '\n'){
    lineSum ++;
   }
   os.write(len);
  }
  System.out.println("lineSum:"+lineSum);
  in.close();
  os.close();
 }
}

6.字节缓冲流和普通字节流的读写效率对比

7.使用字节缓冲流在图6中读写文件的示意图

3.转换流

转换流实现了在指定的编码方式下进行字节编码和字符编码的转换。转换流如果直接从硬盘一次一个字节读取的转换流效率也很低,所以转换流一般都是基于字节缓冲流的。转换流InputStreamReader的使用如8所示,图中代码底层的执行流程图如9所示。InputStreamReader 的源码解析图如10所示,转码的关键代码如11所示。如11,一个字符的字符编码所占字节个数固定为2个字节,但一个字符的字符编码经过转换流按UTF-8格式转换为字节编码后,字节编码所占字节个数为1~4个。

public class Demo01_InputStreamReader {
 public static void main(String[] args) throws IOException {
  readUTF();
 }

    //一次读取一个字符
 public static void readUTF() throws IOException{
  InputStreamReader isr = new InputStreamReader(new FileInputStream("e:\\2.txt"),"UTF-8");
  int ch = 0;
  while((ch = isr.read())!=-1){
   System.out.println((char)ch);
  }
  isr.close();
 }
}

8. 使用转换流InputStreamReader一次读取一个字符

9 .InputStreamReader在read()时的底层流程图(文件中的字节编码可通过FileInputStream读取查看)

10 .InputStreamReader的read()源码解析图

class UTF_8 extends Unicode{
    private CoderResult decodeArrayLoop(ByteBuffer paramByteBuffer, CharBuffer paramCharBuffer)
    {
      byte[] arrayOfByte = paramByteBuffer.array();
      int i = paramByteBuffer.arrayOffset() + paramByteBuffer.position();
      int j = paramByteBuffer.arrayOffset() + paramByteBuffer.limit();
      char[] arrayOfChar = paramCharBuffer.array();
      int k = paramCharBuffer.arrayOffset() + paramCharBuffer.position();
      int m = paramCharBuffer.arrayOffset() + paramCharBuffer.limit();
      int n = k + Math.min(j - i, m - k);
      while ((k < n) && (arrayOfByte[i] >= 0))
        arrayOfChar[(k++)] = (char)arrayOfByte[(i++)];
      while (i < j)
      {
        int i1 = arrayOfByte[i];
        if (i1 >= 0)
        {
          if (k >= m)
            return xflow(paramByteBuffer, i, j, paramCharBuffer, k, 1);
          arrayOfChar[(k++)] = (char)i1;
          i++;
        }
        else
        {
          int i2;
          if ((i1 >> 5 == -2) && ((i1 & 0x1E) != 0))
          {
            if ((j - i < 2) || (k >= m))
              return xflow(paramByteBuffer, i, j, paramCharBuffer, k, 2);
            i2 = arrayOfByte[(i + 1)];
            if (isNotContinuation(i2))
              return malformedForLength(paramByteBuffer, i, paramCharBuffer, k, 1);
            arrayOfChar[(k++)] = (char)(i1 << 6 ^ i2 ^ 0xF80);
            i += 2;
          }
          else
          {
            int i3;
            int i4;
            if (i1 >> 4 == -2)
            {
              i2 = j - i;
              if ((i2 < 3) || (k >= m))
              {
                if ((i2 > 1) && (isMalformed3_2(i1, arrayOfByte[(i + 1)])))
                  return malformedForLength(paramByteBuffer, i, paramCharBuffer, k, 1);
                return xflow(paramByteBuffer, i, j, paramCharBuffer, k, 3);
              }
              i3 = arrayOfByte[(i + 1)];
              i4 = arrayOfByte[(i + 2)];
              if (isMalformed3(i1, i3, i4))
                return malformed(paramByteBuffer, i, paramCharBuffer, k, 3);
              char c = (char)(i1 << 12 ^ i3 << 6 ^ (i4 ^ 0xFFFE1F80));
              if (Character.isSurrogate(c))
                return malformedForLength(paramByteBuffer, i, paramCharBuffer, k, 3);
              arrayOfChar[(k++)] = c;
              i += 3;
            }
            else if (i1 >> 3 == -2)
            {
              i2 = j - i;
              if ((i2 < 4) || (m - k < 2))
              {
                i1 &= 255;
                if ((i1 > 244) || ((i2 > 1) && (isMalformed4_2(i1, arrayOfByte[(i + 1)] & 0xFF))))
                  return malformedForLength(paramByteBuffer, i, paramCharBuffer, k, 1);
                if ((i2 > 2) && (isMalformed4_3(arrayOfByte[(i + 2)])))
                  return malformedForLength(paramByteBuffer, i, paramCharBuffer, k, 2);
                return xflow(paramByteBuffer, i, j, paramCharBuffer, k, 4);
              }
              i3 = arrayOfByte[(i + 1)];
              i4 = arrayOfByte[(i + 2)];
              int i5 = arrayOfByte[(i + 3)];
              int i6 = i1 << 18 ^ i3 << 12 ^ i4 << 6 ^ (i5 ^ 0x381F80);
              if ((isMalformed4(i3, i4, i5)) || (!Character.isSupplementaryCodePoint(i6)))
                return malformed(paramByteBuffer, i, paramCharBuffer, k, 4);
              arrayOfChar[(k++)] = Character.highSurrogate(i6);
              arrayOfChar[(k++)] = Character.lowSurrogate(i6);
              i += 4;
            }
            else
            {
              return malformed(paramByteBuffer, i, paramCharBuffer, k, 1);
            }
          }
        }
      }
      return xflow(paramByteBuffer, i, j, paramCharBuffer, k, 0);
    }
}

11 .UTF_8中将字节编码解码为字符编码的方法decodeArrayLoop()

4.常用的IO类FileReader和BufferedReader

FileReader(String fileName)和InputStreamReader(new FileInputStream(String fileName))是等价的,如12所示,具体实现参见第3节。BufferedReader的实现与FileReader不同,它们的性能对比如13所示。14展示了BufferedReader的使用,这为了和7中InputStreamReader(new FileInputStream(String fileName))的使用做对比。14中代码底层的执行流程图如15所示。BufferedReader的方法read()的源码解析如16所示。BufferedReader和FileReader在字符编码和字节编码的转换时都调用了CharsetDecoder.decode()方法;不同的是BufferedReader一次转换了8192个字符(15),而FileReader一次只转换了2个字符(9)。但由于BufferedReader和FileReader的字节缓冲区大小于均为8192个字节,因此BufferedReader与FileReader效率相差不大。

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

12.FileReader(String filePath)的构造方法

public class Demo01_Copy {

 public static void main(String[] args) throws IOException {
  File src = new File ("e:\\foxit_Offline_FoxitInst.exe");
  File dest = new File("e:\\ithema\\foxit_Offline_FoxitInst.exe");

  long time1 = System.currentTimeMillis();
        //耗时:3801 ms
  //copyFile5(src,dest,bytes);
  //耗时:2938 ms
  copyFile6(src,dest);
  long time2 = System.currentTimeMillis();
  System.out.println(time2 -time1);
 }

 public static void copyFile5(File src ,File dest) throws IOException {
  FileReader fr = new FileReader(src);
  FileWriter fw = new FileWriter(dest);
  int len = 0;
  while((len=fr.read())!=-1){
   fw.write(len);
  }
  fr.close();
  fw.close();
 }

 public static void copyFile6(File src,File dest) throws IOException{
  BufferedReader br = new BufferedReader(new FileReader(src));
  BufferedWriter bw = new BufferedWriter(new FileWriter(dest));
  int len = 0;
  while((len=br.read())!=-1){
   bw.write(len);
  }
  br.close();
  bw.close();
 }
}

13.FileReader和BufferedReader的性能对比

public class Demo01_BufferedReader {
 public static void main(String[] args) throws IOException {
  readUTF();
 }

    //一次读取一个字符
 public static void readUTF() throws IOException{
  BufferedReader br = new BufferedReader(
            new InputStreamReader(new FileInputStream("e:\\2.txt"),"UTF-8"));
  int ch = 0;
  while((ch = br.read())!=-1){
   System.out.println((char)ch);
  }
  br.close();
 }
}

14.使用BufferedReader一次读取一个字符(与图7做对比)

15.BufferedReader在read()时的底层流程图(与图8做对比)

16.BufferedReader的read()源码解析图(与图9做对比)

5.总结

普通字节流是基础,是最简单高效的流。如果没有特殊的需求,只是高效的进行文件读写,选择合适的字节数组大小,一次从硬盘读取一个字节数组大小的字节块,其效率是最高的。

字节缓冲流是为行数统计,按行读取等特殊需求而设计的。相比于直接从硬盘一次读取一个字节;先从硬盘一次读取一个缓冲区大小的字节块到缓冲区(位于内存),再从缓冲区一个字节一个字节的读取并判断是不是行末尾('\n')的效率更高。

转换流实现了在指定的编码方式下进行字节编码和字符编码的转换。转换流如果直接从硬盘一次一个字节读取的转换流效率也很低,所以转换流一般都是基于字节缓冲流的。

以上就是java中的IO流的详细内容,更多关于java中的IO流的资料请关注我们其它相关文章!,希望大家以后多多支持我们!

(0)

相关推荐

  • Java IO流之节点流与字符流的相关知识总结

    一.File file是文件和目录路径名的抽象表示 1.1 File的用法 用法: File file = new File("路径名"); //如 File file = new File("L:\\FileTestDemo\\AAA\\aaa.txt"); 注意:在windows中,路径名不能使用单个的\,单个的\为转义字符,可以使用\\,//或/ 1.2 File的常用方法 1.boolean createNewFile() 当且仅当具有此名称的文件尚不存在时

  • java基础入门之IO流

    目录 io学习框架: 文件: Io流的原理: 节点流和处理流: BufferWriter: 处理字节的处理流: 标准输入和输出: 转换流: 打印流: Properties类: 总结 io学习框架: 文件: 保存数据的地方. 1)常见文件对象的相关构造器和方法: 当进行File file = new File(filePath);只是在内存上有一个文件对象: 只有file.createNewFile();才会在磁盘创建文件 获取文件的相关信息: utf8中,一个汉字是三个字节,所以当用字节流的re

  • Java IO流和文件操作实现过程解析

    Java.io 包几乎包含了所有操作输入.输出需要的类.所有这些流类代表了输入源和输出目标. Java.io 包中的流支持很多种格式,比如:基本类型.对象.本地化字符集等等. 一个流可以理解为一个数据的序列.输入流表示从一个源读取数据,输出流表示向一个目标写数据. Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中. 控制台输入 BufferedReader br = new BufferedReader(new InputStreamReader(Syste

  • Java如何基于IO流实现同一文件读写操作

    1.注意事项 众所周知,对一个文件进行读写操作时,我们需要创建对应的输入流和输出流 但需要注意的是,读写操作不能同时进行(边读边写),即不能同时打开输入流和输出流,直白一点说就是不能同时对同一个文件的输入流和输出流进行赋值,否则影响文件进行正常的读写操作.如果是不同的文件,则可以边读边写. 2.那么我们怎么对同一个文件进行读写操作呢? 不能边读边写,但是可以先读后写,先写后读. a.先读后写 打开输入流,对文件进行读操作,操作完成之后把输入流关掉(注意一定要关掉).然后再打开输出流,对文件进行写

  • Java-IO流实验

    目录 前言 一.资源管理器 [1]. 题目 [2]. 实例 [3]. 代码 二.文件复制与剪切 [1]. 题目 [2]. 复制 [3]. 剪切 [4]. 代码 三.文件数据读写 [1]. 题目 [2]. 实例 [3]. 代码 总结 前言 项目结构如下,在使用代码的时候注意修改成你自己的包名和类名 一.资源管理器 [1]. 题目 设计一个用于显示指定目录下所有文件与文件夹的资源管理器类,要求包括: 从命令行输入一个路径,如果不是目录,则输出提示信息 如果是目录且存在,则显示该目录下,所有的文件与文

  • Java字节流和字符流总结IO流!

    目录 从接收输入值说起 字节流读取 字符流读取 Scanner 读取 什么是 IO 流 字节流和字符流 字节流 字节输入流 字节输出流 缓冲流的原理 字符流 字符输入流 字符输出流 RandomAccessFile 总结 从接收输入值说起 在日常的开发应用中,有时候需要直接接收外部设备如键盘等的输入值,而对于这种数据的接收方式,我们一般有三种方法:字节流读取,字符流读取,Scanner 工具类读取. 字节流读取 直接看一个例子: public class Demo01SystemIn { pub

  • java使用IO流对数组排序实例讲解

    在学会了java中io流的使用后,我们对于数组的排序,又多了一种使用方法.大家知道流处理数据的效率是比较理想的,那么在具体操作数组排序上,很多人对于排序的方法还没有明确.下面我们先java使用流对数组排序的思路为大家进行梳理,然后带来对应的实例代码方法. 1.排序思路 (1)从字符输入流中读取文本,缓冲各个字符,从而实现字符.数组和行的高效读取 (2)询问用户需要多少位数的数组 (3)转换为数字类型 (4)将用户输入数字存入数组 (5)把数组按排序需求并打印出来 2.实例 public stat

  • Java全面解析IO流相关知识

    目录 前言 一.File 1.File类的概述和构造方法 2.File类创建功能 3.File类判断和获取功能 4.File类删除功能 二.字节流 1.IO流的概述和分类 2.字节流写数据 3.字节流写数据的两个小问题 字节流写数据如何换行 字节流写数据如何实现追加写入 4.字节流写入数据假异常处理 5.字节流读数据(重点) 6.字节缓冲流 7.如何选择怎样得数据读取呢? 三.字符流 1.为什么会出现字符流? 2.字符串中的编码解码问题 3.如何实现解决编译解码的问题 4.字符流写数据的方法 5

  • Java IO流深入理解

    目录 阻塞(Block)和非阻塞(Non-Block) 同步(Synchronization)和异步(Asynchronous) BIO与NIO对比 面向流与面向缓冲 阻塞与非阻塞 选择器的问世 Java NIO三件套 缓冲区Buffer Buffer的基本的原理 缓冲区分配 选择器Selector 通道Channel 使用NIO读取数据 使用NIO写入数据 IO多路复用 总结 阻塞(Block)和非阻塞(Non-Block) 阻塞和非阻塞是进程在访问数据的时候,数据是否准备就绪的一种处理方式,

  • Java IO流学习总结之文件传输基础

    一.Java IO流总览 二.File类 2.1 常用API package pkg1; import java.io.File; import java.io.IOException; /** * @author Administrator * @date 2021/4/2 */ public class FileDemo { public static void main(String[] args) { // 了解构造函数,可查看API File file = new File("d:\\

  • 新手小白看过来学JAVA必过IO流File字节流字符流

    目录 IO简介 1.流Stream 2.IO流的继承结构 3 File文件类 3.1概述 3.2创建对象 3.3常用方法 3.4 练习:测试常用方法 4.字节流读取 4.1 InputStream抽象类 4.2 FileInputStream子类 4.3 BufferedInputStream子类 4.4 练习:字节流读取案例 5.字符流读取 5.1 Reader抽象类 5.2 FileReader子类 5.3 BufferedReader子类 5.4 练习:字符流读取案例 6.字节流写出 6.

  • Java之IO流面试题案例讲解

    一.Java中IO流分为几种? 按照流的流向分,可以分为输入流和输出流: 按照操作单元分,可以分为字节流和字符流(字节流可以读写任何单位的数据,字符流只可以读写txt数据): 按照流的角色分,可以分为节点流和处理流: 二.IO中flush()和close()的区别 close()方法具备刷新功能,在关闭流之前就会先刷新缓冲区,将缓冲区的字节全部刷新到文件上,在关闭流.(close()方法包含一次flush()方法) flush()方法可以刷新,并且刷新之后可以继续写,而close()方法刷新之后

  • Java IO流常用字节字符流原理解析

    Java的流体系十分庞大,我们来看看体系图: 这么庞大的体系里面,常用的就那么几个,我们把它们抽取出来,如下图: 一:字节流 1:字节输入流 字节输入流的抽象基类是InputStream,常用的子类是 FileInputStream和BufferedInputStream. 1)FileInputStream 文件字节输入流:一切文件在系统中都是以字节的形式保存的,无论你是文档文件.视频文件.音频文件...,需要读取这些文件都可以用FileInputStream去读取其保存在存储介质(磁盘等)上

  • Java中IO流解析及代码实例详解

    目录 1.IO流 1.流和流的分类 什么是IO流? IO流的分类? java.io包下需要掌握的流有16个: 2.如何使用流 1.输入流(读文件):FileInputStream 2.输出流(写文件):FileOutputStream 3.文件的拷贝 总结 1.IO流 1.流和流的分类 什么是IO流? I:Input (输入) O: Ouput(输出) IO流的分类? 有多种分类方式: 一种方式是按照流的方向进行分类: 以内存作为参照物 往内存中去,叫做输入(Input).或者叫做读(Read)

随机推荐