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) .

从内存中出来,叫做输出(output)。或者叫做写(write) .

  • 另一种方式是按照读取薮据方式不同进行分类:

    • 有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制。
    • 这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频……
    • 有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯文本文件,连word文件都无法读取

总结:流的分类

输入流、输出流、字节流、字符流

Java IO流的四大家族

java.io.InputStream 字节输入流
java.io.OutputStream 字节输出流
java.io.Reader 字符输入流
java.io.Writer 字符输出流

注意:

  • 四个都是抽象类。
  • 所有流都是实现了java.io.Closeable接口,都是可关闭的
    • 流是一个管道,是内存和硬盘之间的通道。用完后一定要关闭,不然会占用很多资源。
  • 所有的输出流都实现了java.io.Flushable接口,都是可刷新的
    • 最终输出后,一定要记得调用flush()方法。目的是将管道中剩余未输出的数据强行输出完(清空管道)
    • 如果没有flash(),可能会导致丢失数据
  • 在java中只要”类名”以strean结尾的都是字节流。以"Reader/writer"结尾的都是字符流

java.io包下需要掌握的流有16个:

文件专属:

java . io.FileInputstream

java.io.FileOutputstream

java.io.FileReader

java.io.Filewriter

转换流:(将字节流转换成字符流)

java . io . InputstreamReader

java . io. outputstreamWriter

缓冲流专属:

java. io. BufferedReader

java.io.BufferedWriter

java.io. BufferedInputstream

java . io.Bufferedoutputstrean

数据流专属:

java . io . DataInputstream

java .io. Dataoutputstrean

标准输出流:

java . io . Printwriter

java . io . Printstream

对象专属流:

java.io.ObjectInputstream

java.io.ObjectOutputstream

一下子看到这么多流。不用怕,只需要掌握一组的使用方法就可以了,使用其他的都是一样,一通百通。

下面以万能的字节流(FileInputStream、FileOutputStream)来举例说明。

2.如何使用流

1、输入流(读文件):FileInputStream

方法一

使用FileInputStream的read()

步骤:

1、 创建流对象

​ new FileInputStream(参数)

​ 参数可以是一个File类、String字符串表示的文件路径

2、使用流的方法对文件进行读

输入流调用read()方法,每次从流中读取一个数据字节。返回值是读到的字节的ASCII值

读取一个后,他会指向下一个字符,如果到达末尾。返回-1,可以用while()来实现。

3、关闭流

调用close()方法

实例:

package com.io.stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestFileInputStream {
    //定义一个流对象
    private static FileInputStream fis;
    public static void main(String[] args) {
        try {
            //1、 创建流对象.参数可以是一个File类、String字符串表示的文件路径
            fis = new FileInputStream("E:\\aaa.txt");//在e盘下有一个aaa.txt的文件夹,内容为(abcdefg)
            //2、使用流的方法对文件进行读
            while (true) {
                int read = fis.read();//注意这里返回的是int类型,代表是字符的ASCII值
                if (read==-1) {//读到最后会返回-1,退出条件
                    break;
                }
                System.out.println(read);
            }
        } catch (FileNotFoundException e) {//异常细粒化,不同异常可以选择不同的处理方式
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //3、关闭流
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

/*输出
97
98
99
100
101
102
103
*/

int read()

该方法因为每次都是只读取一个字节,这样内存和硬盘交互太频繁 ,开销大且效率不高。一般不使用,但是要了解,这是基础。

方法二

一般使用这种方法

使用read(byte[] b)

一次读取最多 b.length 个字节,减少内存和硬盘交互,提高执行效率

该方法返回的是读到的字节的数量

使用步骤:和前面只有第二步有些差别

byte[] b= new byte[3];

int readNum = fis.read(b);

解析

  • 新建一个byte[]数组b,代表我们一次需要读多少个字符。读完这么多字符后,下次一读是从当前读到的位置开始,和上面一样
  • 将byte数组b传入read()方法中,返回一个我们byte数组的大小,此时readNum值为3

那么我们读出来的数据在哪里呢。自然是存放在byte数组里。我们打印b数组看,发现b数组里存放的读到的ascii值

细节:

因为数组的长度是我们设定的。如果文件读到最后,不一定刚好符合我们设定的长度,最后一组的长度只有小于或等于数组的长度。如果小于它会返回剩余的字符的数量,读不到返回-1,我们可以利用这个作为循环退出的条件。

另外一个,因为他的长度小于b数组,那么它的值也是无法填满b数组的,此时,它只更新b数组中前面的n个读到的值,b数组后面的是上一个读取时读取到的值。

实例:

仍然读取aaa.txt文件,内容为(abcdefg)

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class TestFileInputStream2 {
    private static FileInputStream fis;
    public static void main(String[] args) {
        try {
            fis = new FileInputStream("IO流\\aaa.txt");
            //准备一个byte数组
            byte[] b= new byte[3];
            int readNum = 0;
            while (true) {
                //先进行读操作。
                readNum=fis.read(b);
                //判断
                if (readNum == -1) {
                    break;
                }
                //将字符数组转为String,后面两个参数为起始位置,和长度
                String str = new String(b, 0, readNum);
                System.out.println(str);
            }
            /*输出
				abc
				def
				g
			*/
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //关闭流
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

其他常用的方法

int available()

返回流中还有多少个字符没有读。(相当于获得文件读到的位置到末尾字符的个数,如果没开始读,返回文件中总字符的数量)

使用这个可以对一些比较小的(字符长度)文件一次读完,如果不超过byte数组的范围的话

public class TestFileInputStream3 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("IO流\\aaa.txt");
        byte[] bytes = new byte[fis.available()];//创建一个和文件字符数量一样大的byte数组,文件不能太大。
        fis.read(bytes);
        System.out.println(new String(bytes));//b转为字符串,输出abcdefg
    }
}

skip(long n)

顾名思义:从输入流中跳过并丢弃 n 个字节的数据。

2、输出流(写文件):FileOutputStream

和输入的流程差不多,过程也基本相同

write(byte[] b)

注意:

  • byte的范围是-128~127,超过会报错
  • 写完之后,一定要刷新
  • 如果当前路径下文件已存在,会将原文件清空,再写入(慎用)。
    • 如果它是一个目录,而不是一个常规文件,会报错。
    • 或者该文件不存在,但无法创建它,会报错。
  • 如果当前路径下文件不存在,会新建文件。
package com.io.stream.output;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
 * @Author cyh
 * @Date 2021/8/7 17:21
 */
public class Test1 {
    private static FileOutputStream fos;
    public static void main(String[] args) {
        try {
            //新建一个输出流,参数是输出的路径,最后的为文件名。
            fos = new FileOutputStream("IO流\\bbb.txt");
            //新建一个byte数组,里面对应的是abcd的ascii值
            byte[] bytes = {97, 98, 99, 100,101,127}; //注意byte的范围是-128~127
            //输出流调用write方法写入byte数组,以文件形式保存到上面的路径
            fos.write(bytes);
            //写完之后,一定要刷新
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

追加写文件

想要追加写文件,则需要在新建流的的时候,加一个参数true。

表示将字节写入文件末尾处,而不是写入文件开始处

//新建一个输出流,参数是输出的路径,最后的为文件名。增加true表示开启追加写
fos = new FileOutputStream("IO流\\bbb.txt",true);

注意:和上面一样,不一样的点只是追加写。

write(byte[] b, int off, int len)

将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流.

意思就是,写入的内容为off~len。如果off是0,len是数组长度,那就全部写入;如果off是数组长度-1,len是数组长度,那就只写入了一个字符

3.文件的拷贝

  • 使用FileInputStream+FileOutputStream即可完成文件的拷贝
  • 拷贝的过程应该是一边读、一边写
  • 使用上面的字节流拷贝文件的时候,文件类型随意,是万能的。什么文件都可以拷贝

实例

package com.io.stream.copy;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
 * @Author cyh
 * @Date 2021/8/7 17:53
 */
public class TestCopy {
    private static FileInputStream fis;
    private static FileOutputStream fos;
    public static void main(String[] args) {
        try {
            //创建一个输入流
            fis = new FileInputStream("D:\\edgeDownload\\VSCodeUserSetup-x64-1.55.0.exe");
            //创建一个输出流
            fos = new FileOutputStream("C:\\Users\\PC\\Desktop\\copy\\b\\VSCodeUserSetup-x64-1.55.0.exe");
            //核心,一边读、一边写
            byte[] bytes = new byte[1024*1024];//1MB,一次最多拷贝1MB
            int readNum=0;
            while((readNum=fis.read(bytes))!=-1){
                fos.write(bytes,0,readNum);//将bytes全部写入
            }
            //刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //资源要分开释放,不然一个出错会导致另一个无法释放
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Java 中IO流字符流详解及实例

    Java-IO流 字符流 java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码). 文件是byte byte byte ... 的数据序列. 文本文件是文本(char)序列按照某种编码方案(uft-8.utf-16be.gbk)序列化为byte的存储结果. 字符流(Reader.Writer)-->操作的是文本.文本文件 1.字符的处理,一次处理一个字符 2.字符的底层仍然是基本的字节序列 3.字符流的基本实现: InputStreamReader是字节流通向字符

  • Java中IO流 字节流实例详解

    Java中IO流 字节流实例详解 IO流(输入流.输出流),又分为字节流.字符流. 流是磁盘或其它外围设备中存储的数据的源点或终点. 输入流:程序从输入流读取数据源.数据源包括外界(键盘.文件.网络-),即是将数据源读入到程序的通信通道. 输出流:程序向输出流写入数据.将程序中的数据输出到外界(显示器.打印机.文件.网络-)的通信通道. 字节流 1.InputStream.OutputStream InputStream抽象了应用程序读取数据的方式 OutputStream抽象了应用程序写出数据

  • Java中IO流 RandomAccessFile类实例详解

    Java中IO流 RandomAccessFile类实例详解 RandomAccessFile java提供的对文件内容的访问,既可以读文件,也可以写文件. 支持随机访问文件,可以访问文件的任意位置. java文件模型,在硬盘上的文件是byte byte byte存储的,是数据的集合 打开文件,有两种模式,"rw"读写."r"只读:RandomAccessFile raf = new RandomAccessFile(file, "rw");,文

  • Java IO流对象的序列化和反序列化实例详解

    Java-IO流 对象的序列化和反序列化 序列化的基本操作 1.对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化. 2.序列化流(ObjectOutputStream),writeObject 方法用于将对象写入输出流中: 反序列化流(ObjectInputStream),readObject 方法用于从输入流中读取对象. 3.序列化接口(Serializeable) 对象必须实现序列化接口,才能进行序列化,否则会出现异常.这个接口没有任何方法,只是一个标准. packag

  • Java IO流之字符缓冲流实例详解

    字符流: 1.加入字符缓存流,增强读取功能(readLine) 2.更高效的读取数据 BufferedReader 从字符输入流读取文本,缓冲各个字符,从而实现字符.数组和行的高效读取. FileReader:内部使用InputStreamReader,解码过程,byte->char,默认缓存大小为8k BufferReader:默认缓存大小为8k,但可以手动指定缓存大小,把数据读取到缓存中,减少每次转换过程,效率更高 /字符输入缓冲流 private static void charReade

  • 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)

  • Java中io流解析及代码实例

    IO流 Java中IO流分为两种,字节流和字符流,顾名思义字节流就是按照字节来读取和写入的,字符刘是按照字符来存取的:常用的文件读取用的就是字符流,在网络通信里面用的就是字节流 下面这张图是Java中IO流的总体框架: 字节流 Java中字节流一般都是以stream结尾的,输入的字节流叫InputStream,输出字节流叫OutputStream;InputStream和OutputStream是表示自己输入/输出的所有类的超类,是抽象类(abstract) 常用的字节流有: 1.FileInp

  • java中压缩文件并下载的实例详解

    当我们对一些需要用到的资料进行整理时,会发现文件的内存占用很大,不过是下载或者存储,都不是很方便,这时候我们会想到把文件变成zip格式,即进行压缩.在正式开始压缩和下载文件之前,我们可以先对zip的格式进行一个了解,然后再就具体的方法给大家带来分享. 1.ZIP文件格式 [local file header + file data + data descriptor]{1,n} + central directory + end of central directory record 即 [文件

  • java 中Excel转shape file的实例详解

    java  中Excel转shape file的实例详解 概述: 本文讲述如何结合geotools和POI实现Excel到shp的转换,再结合前文shp到geojson数据的转换,即可实现用户上传excel数据并在web端的展示功能. 截图: 原始Excel文件 运行耗时 运行结果 代码: package com.lzugis.geotools; import com.lzugis.CommonMethod; import com.vividsolutions.jts.geom.Coordina

  • Java中常见死锁与活锁的实例详解

    本文介绍了Java中常见死锁与活锁的实例详解,分享给大家,具体如下: 顺序死锁:过度加锁,导致由于执行顺序的原因,互相持有对方正在等待的锁 资源死锁:多个线程在相同的资源上发生等待 由于调用顺序而产生的死锁 public class Test { Object leftLock = new Object(); Object rightLock = new Object(); public static void main(String[] args) { final Test test = ne

  • java  中Excel转shape file的实例详解

    java  中Excel转shape file的实例详解 概述: 本文讲述如何结合geotools和POI实现Excel到shp的转换,再结合前文shp到geojson数据的转换,即可实现用户上传excel数据并在web端的展示功能. 截图: 原始Excel文件 运行耗时 运行结果 代码: package com.lzugis.geotools; import com.lzugis.CommonMethod; import com.vividsolutions.jts.geom.Coordina

  • JAVA 中解密RSA算法JS加密实例详解

    JAVA 中解密RSA算法JS加密实例详解 有这样一个需求,前端登录的用户名密码,密码必需加密,但不可使用MD5,因为后台要检测密码的复杂度,那么在保证安全的前提下将密码传到后台呢,答案就是使用RSA非对称加密算法解决 . java代码 需要依赖 commons-codec 包 RSACoder.Java import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import java.security.

  • java 中序列化与readResolve()方法的实例详解

    java 中序列化与readResolve()方法的实例详解 readResolve方法是作用是什么?这个方法跟对象的序列化相关(这样倒是解释了为什么 readResolve方法是private修饰的). 怎么跟对象的序列化相关了? 下面我们先简要地回顾下对象的序列化.一般来说,一个类实现了 Serializable接口,我们就可以把它往内存地写再从内存里读出而"组装"成一个跟原来一模一样的对象.不过当序列化遇到单例时,里边就有了个问题:从内存读出而组装的对象破坏了单例的规则.单例是要

  • Java中JDBC实现动态查询的实例详解

    一 概述 1.什么是动态查询? 从多个查询条件中随机选择若干个组合成一个DQL语句进行查询,这一过程叫做动态查询. 2.动态查询的难点 可供选择的查询条件多,组合情况多,难以一一列举. 3.最终查询语句的构成 一旦用户向查询条件中输入数据,该查询条件就成为最终条件的一部分. 二 基本原理 1.SQL基本框架 无论查询条件如何,查询字段与数据库是固定不变的,这些固定不变的内容构成SQL语句的基本框架,如 select column... from table. 2.StringBuilder形成D

  • Java 中DateUtils日期工具类的实例详解

    Java 中DateUtils日期工具类的实例详解 介绍 在java中队日期类型的处理并不方便,通常都需要借助java.text.SimpleDateFormat类来实现日期类型 和字符串类型之间的转换,但是在jdk1.8之后有所改善,jdk1.7以及之前的版本处理日期类型并不方便, 可以借助Joda Time组件来处理,尤其是日期类型的一些数学操作就更是不方便. java代码 /** * * 日期工具类 java对日期的操作一直都很不理想,直到jdk1.8之后才有了本质的改变. * 如果使用的

随机推荐