Java 输入输出相关概念介绍(File、IO 流)(四)

150 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

前面的文章Java 输入输出相关概念介绍(File、IO 流)(三)介绍了File 类、IO 流的相关基础概念及信息。

本篇将对InputStream 的使用做详细的介绍。

这里只挑选几个常用的功能做展开介绍。

几个常用的接口api

read 函数

  • public abstract int read()

这个方法的作用是是对某个流,逐个字节读取,返回值的int,就是读取到的这个字节的int 类型表示方式。

  • public int read(byte[] bytes)

此方法的作用是先初始化一个数组,然后将这个流中的字节缓冲至byte 数组中,返回的这个数组中的字节个数,如果这个数组没有被填满,那么返回真实的字节个数,当读取到数据流的未尾时,返回-1

public static void main(String[] args) throws IOException {
    File file = new File("copy.txt");
    InputStream inputStream = new FileInputStream(file);
    byte[] bytes = new byte[32];
    int b;
    while ((nums = inputStream.read(bytes)) != -1) {
        String s = new String(bytes);
        System.out.println(s);
    }
}

上面的写法其实是有问题的,读者可以自行发现。这里仅仅为了演示方便,简化了代码。

  • public int read(byte[] bytes,int off,int len)

这个方法同上,区别就是多了个off 参数和len 参数。off 代表写入byte 数组的起始位置,len 代表读取指定长度的字节数量。

available 函数

  • public int available()

代表在程序不阻塞的情况下,程序中的数据流里,有多少个字节可以读取。

使用时,如果是本地文件,一般不会有什么问题。

但是如果用在网络数据的读取,有时候可能发生异常。比如说在Socket 通讯时,我们收到对方发来的数据明明是1024个字节,但是自己的程序调用available() 函数之后,却发现只有10,甚至得到了0。

读取文件

在Java 中可以使用InputStream 对文件进行读取,对应的实现类就是FileInputStream,也就是字节流的输入。

在读取文件的内容加载到程序中时,我们需要使用一个byte 数组进行存储。

如我们知道这个文件的大小,可以使用一个确定大小的byte 数组,代码如下

public static void main(String[] args) throws Exception {
    File file = new File("/abc/def/ghi.txt");
    byte[] content = new byte[(int) file.length()];
    FileInputStream fileInputStream = new FileInputStream(file)
    fileInputStream.read(content);
    fileInputStream.close();
    String stringContent = new String(content);
    System.out.println(stringContent);
}

如果我们不知道这个文件的大小,那么我们可以这么做,进行循环读取。这里假设文件大小小于1024

public static void main(String args[]) throws Exception { 
    File file = new File("/abc/def/ghi.txt");
    InputStream fileInputStream =new FileInputStream(file);
    byte[] bytes = new byte[1024];
    int len = 0;
    int temp;
    while ((temp = fileInputStream.read()) != -1) {
        bytes[len] = (byte) temp;
        len++;
    }
    fileInputStream .close();
    System.out.println(new String(bytes, 0, len));
}

读取网络上的图片

在Java 中同样可以使用InputStream 读取网络上的图片,以数据流的方式进行加载,并输出到目标文件中。

话不多说,直接上示例代码。

public class Test {
    public static void main(String[] args) throws Exception {
        URL url = new URL("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png");
        // 获取图片连接
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setConnectTimeout(5 * 1000);
        // 获取连接的输入流的数据
        InputStream inStream = conn.getInputStream();
        // 将输入流数据存到byte 数组中
        byte[] data = readInputStream(inStream);
        File imageFile = new File("baidu.jpg");
        //创建输出流
        FileOutputStream fileOutputStream = new FileOutputStream(imageFile);
        fileOutputStream.write(data);
        fileOutputStream.close();
    }
    public static byte[] readInputStream(InputStream inputStream) throws Exception {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        OutputStream outputStream = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        //每次读取的字符串长度,如果为-1,代表全部读取完毕
        int len = 0;
        //使用一个输入流从buffer里把数据读取出来
        while ((len = inputStream.read(bytes)) != -1) {
            //用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
            byteArrayOutputStream.write(bytes, 0, len);
        }
        inputStream.close();
        //把outStream里的数据写入内存
        return byteArrayOutputStream.toByteArray();
    }
}

上述整体思路其实就是首先从网络上读到图片数据,转成InputStream,然后将得到的InputStream 转换成输出流OutputStream(在后文会讲到),写入文件中去。

总结

对于InputStream,大概讲解如上。总结下来就是:

  • 首先得到一个目标源,可以是文件(File),可以是网络URI
  • 然后通过InputStream 进行加载读取
  • 然后声明一个byte 数组,将读取到的数据放入缓冲区byte 数组中
  • 最后可以对此数组做一些业务逻辑操作

接下来文章继续讲解Java IO 的其他几个抽象类及其拓展。