Java byte stream 字节流


字节流

  • 字节流(byte stream)类以字节为单位处理数据;
  • 字节流不会对数据进行任何转换,因此可以用来处理二进制数据;
  • 一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都是一个一个的字节,那么传输时一样如此,所以,字节流可以传输任意文件数据。注意,在操作流的时候,无论使用什么样的流对象,底层传输的始终为二进制数据;
  • 字节输入流 FileInputStream 和字节输出流 FileOutputStream 分别是抽象类输入流 InputStream 和输出流 OutputStream 的子类,InputStream 和 OutputStream 主要用于操作系统的输入输出,管理声音、键盘输入等功能;

1. 输入流 InputStream

  • 字节输入流的作用是从数据输入源(例如磁盘、网络等)获取字节数据到应用程序(内存)中;
  • InputStream 是一个定义了 Java 流式字节输入模式的抽象类,该类的所有方法在出错时都会引发一个 IOException 异常;

a. InputStream 的常用方法

类型方法说明
intavailable()返回当前可读的输入字节数
voidclose()关闭输入流,关闭后再读取会抛出 IOException 异常
voidmark(int numBytes)在输入流的当前点设置一个标记,该流在读取 numBytes 个字节前都保持有效
booleanmarkSupported()如果调用的流支持 mark()/reset() 就返回 true
intread()如果下一个字节可读则返回一个整型,遇到文件结尾时返回 -1
intread(byte buffer[])尝试读取 buffer.length 个字节到 buffer 中,返回实际读取的字节数,遇到文件结尾时返回 -1
intread(byte buffer[], int offset, int numBytes)尝试读取 buffer[offset] 开始的 numBytes 个字节,返回实际读取的字节数,遇到文件结尾时返回 -1
voidreset()重新设置输入指针到先前设置的标志处
longskip(long numBytes)忽略 numBytes 个输入字节,返回实际忽略的字节数

b. FileInputStream 类

构造方法说明
FileInputStream(String filepath)文件的绝对路径,比较常用
FileInputStream(File fileObj)fileObj 是描述该文件的 File 对象,允许在把文件赋给输入流之前用 File 方法更进一步检查文件
i. 读取字节
  • read 方法,每次可以读取一个字节的数据,提升为 int 类型,读取到文件末尾,返回 -1;
import java.io.FileInputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        //使用文件名称创建流对象
        FileInputStream fis = new FileInputStream("C:\\Users\\80626\\Desktop\\1.txt");
        //文件内容: abcde
        //定义变量,保存数据
        int b;
        //循环读取
        while ((b = fis.read()) != -1) {
            System.out.println((char) b);
        }
        //关闭资源
        fis.close();
    }
}
/*
输出
a
b
c
d
e
*/
  • 虽然读取了一个字节,但是会自动提升为 int 类型;
ii. 读取字节数组
  • read(byte[] b),每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回 -1;
import java.io.FileInputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        //使用文件名称创建流对象.
        FileInputStream fis = new FileInputStream("C:\\Users\\80626\\Desktop\\1.txt"); 
        //文件中为abcde
        //定义变量,作为有效个数
        int len;
        //定义字节数组,作为装字节数据的容器
        byte[] b = new byte[2];
        //循环读取
        while ((len = fis.read(b)) != -1) {
            //每次读取后,把数组变成字符串打印
            System.out.println(new String(b));
        }
        //关闭资源
        fis.close();
    }
}
/*
输出
ab
cd
ed
 */
  • 使用数组读取,每次读取多个字节,减少了系统间的IO操作次数,从而提高了读写的效率,建议开发中使用;
  • 错误数据 d ,是由于最后一次读取时,只读取一个字节 e ,数组中,上次读取的数据没有被完全替换,所以要通
    过 len ,获取有效的字节:
import java.io.FileInputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        //使用文件名称创建流对象.
        FileInputStream fis = new FileInputStream("C:\\Users\\80626\\Desktop\\1.txt"); 
        //文件中为abcde
        //定义变量,作为有效个数
        int len;
        //定义字节数组,作为装字节数据的容器
        byte[] b = new byte[2];
        //循环读取
        while ((len = fis.read(b)) != -1) {
            //每次读取后,把数组的有效字节部分,变成字符串打印
            System.out.println(new String(b, 0, len));// len 每次读取的有效字节个数
        }
        //关闭资源
        fis.close();
    }
}
/*
输出
ab
cd
e
 */

c. FileInputStream 类读取并显示文件

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        byte[] b = new byte[1024];//设置字节缓冲区
        int n = -1;
        System.out.println("请输入要读取的文件名:(例如:d:\\hello.txt)");
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();//获取要读取的文件名

        try {
            FileInputStream in = new FileInputStream(str);//创建字节输入流
            while ((n = in.read(b, 0, 1024)) != -1) {//读取文件内容到缓冲区,并显示
                String s = new String(b, 0, n);
                System.out.println(s);
            }
            in.close();//读取文件结束,关闭文件
        } catch (IOException e) {
            System.out.println("文件读取失败");
        }
    }
}
/*
输出
请输入要读取的文件名:(例如:d:\hello.txt)
C:\Users\80626\Desktop\1.txt
ssssaaa手动阀阿斯顿发
 */


2. 输出流 OutputStream

  • 字节输出流的作用是将字节数据从应用程序(内存)中传送到输出目标,如外部设备、 网络等;
  • OutputStream 是一个定义了 Java 流式字节输出模式的抽象类,该类的所有方法都会返回一个 void 值,并在出错时都会引发一个 IOException 异常;

a. OutputStream 的常用方法

类型方法说明
voidclose()关闭输出流并释放与此流相关联的任何系统资源,关闭后再操作会抛出 IOException 异常
voidflush()刷新输出缓冲区,并强制任何缓冲的输出字节被写出
voidwrite(int b)向输出流写入单个字节,参数是个整型数
voidwrite(byte buffer[])向一个输出流写一个完整的字节数组
voidwrite(byte buffer[], int offset, int numBytes)写数组 buffer 以 buffer[offset] 为起点的 numBytes 个字节区域内的内容
abstract voidwrite(int b)将指定的字节输出流
  • close() 方法,当完成流的操作时,必须调用此方法,释放系统资源;

b. FileOutputStream 类

构造方法说明
FileOutputStream(String filepath)文件的绝对路径
FileOutputStream(File fileObj)fileObj 是描述该文件的 File 对象
FileOutputStream(String filePath, boolean append)如果 append 为 true,文件则以设置搜索路径模式打开
  • FileOutputStream 的创建不依赖于文件是否存在,它会在打开输出文件后就创建它,如果尝试打开一个只读文件,则会引发 IOException 异常;
  • 在完成操作过程中,系统会将数据暂存到缓冲区,缓冲区满了后再一次性写入到输出流中,执行 close() 方法时,不管缓冲区是否已满,都会把其中的数据写到输出流;
i. 写入字节
  • write(int b) 方法,每次可以写出一个字节数据;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        //使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("C:\\Users\\80626\\Desktop\\1.txt");
        //写出数据
        fos.write(97); //写出第1个字节
        fos.write(98); //写出第2个字节
        fos.write(99); //写出第3个字节
        //关闭资源
        fos.close();
    }
}
/*
文件
abc
 */        
  • 虽然参数为 int 类型四个字节,但是只会保留一个字节的信息写出;
ii. 写入字节数组
  • write(byte[] b),每次可以写出数组中的数据;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        //使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("C:\\Users\\80626\\Desktop\\1.txt");
        //字符串转换为字节数组
        byte[] b = "abcde".getBytes();
        //写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
        fos.write(b, 2, 2);
        //关闭资源
        fos.close();
    }
}
/*
文件
cd
 */
iii. 写入指定长度数组
  • write(byte[] b, int off, int len) ,每次写出从 off 索引开始,len 个字节;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        //使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");
        //字符串转换为字节数组
        byte[] b = "abcde".getBytes();
        //写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
        fos.write(b, 2, 2);
        //关闭资源
        fos.close();
    }
}

/*
文件
cd
 */
iv. 数据追加续写
  • 以上的演示,每次程序运行,创建输出流对象,都会清空目标文件中的数据;
  • 下列两个构造方法,参数中都需要传入一个 boolean 类型的值, true 表示追加数据, false 表示清空原有数据;
    • public FileOutputStream(File file, boolean append) 创建文件输出流以写入由指定的 File 对象表示的文件;
    • public FileOutputStream(String name, boolean append) 创建文件输出流以指定的名称写入文件;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        //使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt",true);
        //字符串转换为字节数组
        byte[] b = "abcde".getBytes();
        //写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
        fos.write(b);
        //关闭资源
        fos.close();
    }
}
/*
文件操作前:cd
文件操作后:cdabcde
 */
v. 写出换行
  • Windows 系统里,换行符号是 \r\n;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");
        // 定义字节数组
        byte[] words = {97, 98, 99, 100, 101};
        // 遍历数组
        for (int i = 0; i < words.length; i++) {
            // 写出一个字节
            fos.write(words[i]);
            // 写出一个换行, 换行符号转成数组写出
            fos.write("\r\n".getBytes());
        }
        // 关闭资源
        fos.close();
    }
}
/*
文件
a
b
c
d
e
*/

回车符 \r 和换行符 \n :

  • 回车符:回到一行的开头(return);
  • 换行符:下一行(newline);

系统中的换行:

  • Windows 系统里,每行结尾是 回车 + 换行 ,即 \r\n ;
  • Unix\Linux 系统里,每行结尾只有换行 ,即 \n ;
  • Mac 系统里,每行结尾是 回车 ,即 \r,从 Mac OS X 开始与 Linux 统一

c. FileOutputStream 类写入数据

  • 第二次操作采用追加方式完成:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        String content;//待输出字符串
        byte[] b;//输出字节流
        FileOutputStream out;//文件输出流
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入文件名:(例如,d:\\hello.txt)");
        String filename = scanner.nextLine();
        File file = new File(filename);//创建文件对象

        if (!file.exists()) {//判断文件是否存在
            System.out.println("文件不存在,是否创建?(y/n)");
            String f = scanner.nextLine();
            if (f.equalsIgnoreCase("n"))
                System.exit(0);//不创建,退出
            else {
                try {
                    file.createNewFile();//创建新文件
                } catch (IOException e) {
                    System.out.println("创建失败");
                    System.exit(0);
                }
            }
        }

        try {//向文件中写内容
            content = "Hello";
            b = content.getBytes();
            out = new FileOutputStream(file);//建立文件输出流
            out.write(b);//完成写操作
            out.close();//关闭输出流
            System.out.println("文件写操作成功!");
        } catch (IOException e) {
            e.getMessage();
        }

        try {//向文件中追加内容
            System.out.println("请输入追加的内容:");
            content = scanner.nextLine();
            b = content.getBytes();
            out = new FileOutputStream(file, true);//创建可追加内容的输出流
            out.write(b);//完成追加写操作
            out.close();//关闭输出流
            System.out.println("文件追加写操作成功!");
            scanner.close();
        } catch (IOException e) {
            e.getMessage();
        }
    }
}
/*
输出
请输入文件名:(例如,d:\hello.txt)
C:\Users\80626\Desktop\1.txt
文件写操作成功!
请输入追加的内容:
fsfad
文件追加写操作成功!

文件
Hellofsfad
 */

3. 综合应用

a. 写入并读出数据

import java.io.*;

public class Test {
    public static void main(String args[]) {
        File f = new File("C:\\Users\\80626\\Desktop\\1.txt");
        OutputStream out = null;
        try {
            out = new FileOutputStream(f);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 将字符串转成字节数组
        byte b[] = "Hello World!!!".getBytes();
        try {
            // 将byte数组写入到文件之中
            out.write(b);
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        try {
            out.close();
        } catch (IOException e2) {
            e2.printStackTrace();
        }

        // 以下为读文件操作
        InputStream in = null;
        try {
            in = new FileInputStream(f);
        } catch (FileNotFoundException e3) {
            e3.printStackTrace();
        }
        // 开辟一个空间用于接收文件读进来的数据
        byte b1[] = new byte[1024];
        int i = 0;
        try {
            // 将b1的引用传递到read()方法之中,同时此方法返回读入数据的个数
            i = in.read(b1);
        } catch (IOException e4) {
            e4.printStackTrace();
        }
        try {
            in.close();
        } catch (IOException e5) {
            e5.printStackTrace();
        }
        //将byte数组转换为字符串输出
        System.out.println(new String(b1, 0, i));
    }
}
/*
输出
Hello World!!!

文件
Hello World!!!
 */

b. 图片复制

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        // 1.创建流对象
        // 1.1 指定数据源
        FileInputStream fis = new FileInputStream("C:\\Users\\80626\\Desktop\\test.jpg");
        // 1.2 指定目的地
        FileOutputStream fos = new FileOutputStream("C:\\Users\\80626\\Desktop\\test_copy.jpg");
        // 2.读写数据
        // 2.1 定义数组
        byte[] b = new byte[1024];//一次拿1024个字节,即1KB,上限与CPU高速缓存的处理能力有关,一般不要超过8KB
        // 2.2 定义长度
        int len;
        // 2.3 循环读取
        while ((len = fis.read(b)) != -1) {//避免了代码冗余
            // 2.4 写出数据
            fos.write(b, 0, len);
        }
        // 3.关闭资源
        fos.close();
        fis.close();
    }
}
  • 流的关闭原则:先开后关,后开先关,调整顺序无影响;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值