关键词搜索

源码搜索 ×
×

一篇文章带你搞定 Java 中字节流的基本操作(InputStream / OutputStream)

发布2020-02-08浏览820次

详情内容

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

输入流和输出流的关系:
在这里插入图片描述
java.io 包中流的操作主要有字节流、字符流两大类,两类都有输入和输出操作。在字符流中输出主要是使用 Writer 类完成,输入主要是使用 Reader 类完成。

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

字节流主要操作 byte 类型数据,以 byte 数组为准,输出数据主要使用 OutputStream 类完成,输入使用的是 InputStream

一、 字节输出流:OutputStream

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

public abstract class OutputStream extends Object
implements Closeable,Flushable

    可以看出OutputStream 类是一个抽象类,如果要使用此类,需要先通过子类实例化对象。
    如果现在要操作的是一个文件,则可以使用 FileOutputStream 类,通过向上转型,可以为 OutputStream 实例化。
    在 OutputStream 类中的主要操作方法:
    在这里插入图片描述

    1. 向文件中写入字符串

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.OutputStream;
    
    public class Root{
        //异常抛出不处理
        public static void main(String[] args) throws Exception{
            //第1步:使用File类找到一个文件
            File f = new File("D:" + File.separator + "test.txt");//声明File对象
            //第2步:通过子类实例化父类对象
            OutputStream out = null;//准备好一个输出的对象
            out = new FileOutputStream(f);//通过对象多态性,进行实例化,这里是向上转型
            //第3步:进行写操作
            String str = "Hello World!!!";
            byte b[] = str.getBytes();//只能输出byte数组,所以将字符串变为byte数组
            out.write(b);//将内容输出,保存文件
            //第4步:关闭输出流
            out.close();
        }
    }
    
      3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    程序在实例化、写、关闭时都有异常发生,为了方便起见,需要在主方法上使用 throws 关键字抛出异常,减少 try...catch 语句

    如果文件不存在则会自动创建

    也可以将 byte 数组中的内容一个个写入到文件之中:

    byte b[] = str.getBytes();
    for(int i=0;i<b.length;i++){
    	out.write(b[i]);//将内容按字节输出
    }
    
      3
    • 4

    2. 追加新内容

    可以通过FileOutputStream 向文件中追加内容,FileOutputStream的另一个构造方法:

    public FileOutputStream(File file,boolean append) throws FileNotFoundException
    
    • 1

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

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.OutputStream;
    
    public class Root{
        //异常抛出不处理
        public static void main(String[] args) throws Exception{
            //第1步:使用File类找到一个文件
            File f = new File("D:" + File.separator + "test.txt");//声明File对象
            //第2步:通过子类实例化父类对象
            OutputStream out = null;//准备好一个输出的对象
            out = new FileOutputStream(f,true);//表示在文件末尾追加内容
            //第3步:进行写操作
            String str = "Good Morning !!!";
            byte b[] = str.getBytes();//只能输出byte数组,所以将字符串变为byte数组
            out.write(b);//将内容输出,保存文件
            //第4步:关闭输出流
            out.close();
        }
    }
    
      3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    如果要使用换行可以通过 \r\n 增加换行

    String str = "\r\n Hello World!!!"
    
    • 1

    二、字节输入流 InputStream

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

    public abstract class InputStream extends Object implements Closeable
    
    • 1

    与OutputStream 类一样,InputStream 也是一个抽象类,必须依靠其子类,如果现在从文件中读取,子类肯定是 FileInputStream。

    在这里插入图片描述

    1. 从文件中读取内容

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    
    public class Test{
        public static void main(String[] args) throws Exception{//异常抛出不处理
            //第1步:使用 File 类找到一个文件
            File f = new File("D:" + File.separator + "test.txt");
    //        第2步:通过子类实例化父类对象
            InputStream input = null;
            input = new FileInputStream(f);//通过多态进行实例化
    //        第3步:进行读操作
            byte b[] = new byte[1024];//将所有内容读到此数组中
            input.read(b);//将内容取出,内如读到 byte 数组中
    //        第4步:关闭输入流
            input.close();
            System.out.println("内容为:" + new String(b));//把 byte 数组变为字符串输出
        }
    }
    
      3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    此时由于开辟的 byte 数组大小为1024,实际内容只有14个字节所以存在多余的空白空间,造成输出的结果含有大量空格,修改如下:

    		byte b[] = new byte[1024];//将所有内容读到此数组中
            int len = input.read(b);//将内容取出,内如读到 byte 数组中
    //        第4步:关闭输入流
            input.close();
            System.out.println("读入数据的长度:" + len);
            System.out.println("内容为:" + new String(b,0,len));//把 byte 数组变为字符串输出
    
      3
    • 4
    • 5
    • 6

    在这里插入图片描述
    此时将将byte数组中指定范围的内容变成了字符串

    2. 开辟指定大小的 byte 数组

    byte b[] = new byte[(int)f.length()];//将所有内容读到此数组中,数组大小由文件制定input.read(b);//将内容取出,内如读到 byte 数组中
    //        第4步:关闭输入流
    input.close();
    System.out.println("内容为:" + new String(b));//把 byte 数组变为字符串输出
    
      3
    • 4

    3. 通过 read() 循环读取

    byte b[] = new byte[(int)f.length()];//将所有内容读到此数组中,数组大小由文件制定
    for (int i=0;i<b.length;i++){
                b[i] = (byte)input.read();//将内容读出
            }
    //        第4步:关闭输入流
    input.close();
    System.out.println("内容为:" + new String(b));//把 byte 数组变为字符串输出
    
      3
    • 4
    • 5
    • 6
    • 7

    当不知道具体数组大小时,可以通过判断是否读到文件末尾来读取文件:

    //        第3步:进行读操作
            byte b[] = new byte[1024];//将所有内容读到此数组中,数组大小由文件制定
            int temp = 0;
            int len = 0;
            while ((temp = input.read())!= -1){
                //将每次的读取内容给 temp 变量,如果temp的值不是 -1,则表示文件没有读完
                b[len] = (byte)temp;
                len++;
            }
    //        第4步:关闭输入流
            input.close();
            System.out.println("内容为:" + new String(b,0,len));//把 byte 数组变为字符串输出
    
      3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    只有当文件读到末尾时,才会返回 -1

    三、文件复制

    程序运行时可以按照如下格式:

    java Copy 源文件 目标文件
    
    • 1

    此时想要完成将D盘中的test.txt文件复制到D盘中的 demo.txt 文件
    此时要完成这样的复制程序,可以用两种方式操作:
    (1)将源文件中的内容全部读取到内存,并一次性写入到目标文件中
    (2)不讲源文件中的内容全部读取进来,采用边读边写的方式

    很明显,第(2)种方法更好合理,因为如果内容过多,则整个内存是无法装下的,程序肯定会出现异常,而如果采用边读边写的方式,肯定比全部读进来性能高很多

    import java.io.*;
    
    public class Copy {
        public static void main(String[] args) throws Exception{
            if (args.length != 2) {
    //            判断是否是两个参数
                System.out.println("输入的参数不正确!");
                System.out.println("例:java Copy 源文件路径 目标文件路径");
                System.exit(1);//系统退出
            }
            File f1 = new File(args[0]);//源文件的 File 对象
            File f2 = new File(args[1]);//目标文件的File对象
            if (!f1.exists()) {
                System.out.println("源文件不存在!");
                System.exit(1);
            }
            InputStream input = new FileInputStream(f1);//准备好输入流对象,读取源文件
            OutputStream out = new FileOutputStream(f2);//准备好输出流对象,写入目标文件
            if (input != null && out != null) {//判断输入或输出是否准备好
                int temp =0;
                try{
                    while ((temp=input.read())!=-1){//开始复制
                        out.write(temp);//边读边写
                    }
                    System.out.println("复制完成");
                }catch (IOException e){
                    e.printStackTrace();
                }
                input.close();
                out.close();
            }
    
        }
    }
    
      3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    相关技术文章

    点击QQ咨询
    开通会员
    返回顶部
    ×
    微信扫码支付
    微信扫码支付
    确定支付下载
    请使用微信描二维码支付
    ×

    提示信息

    ×

    选择支付方式

    • 微信支付
    • 支付宝付款
    确定支付下载