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

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

输入流和输出流的关系:
在这里插入图片描述
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();
    }
}

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

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

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

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

2. 追加新内容

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

public FileOutputStream(File file,boolean append) throws FileNotFoundException

在构造方法中,如果将 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();
    }
}

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

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

二、字节输入流 InputStream

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

public abstract class InputStream extends Object implements Closeable

与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 数组变为字符串输出
    }
}

此时由于开辟的 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 数组变为字符串输出

在这里插入图片描述
此时将将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. 通过 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步:进行读操作
        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 数组变为字符串输出

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

三、文件复制

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

java Copy 源文件 目标文件

此时想要完成将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();
        }

    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南淮北安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值