专栏首页bingfeng-技术【云+社区年度征文】Java-IO流-FileInputStream学习(一)
原创

【云+社区年度征文】Java-IO流-FileInputStream学习(一)

字节输入流

「FileInputSteam」

1、构造方法:

public FileInputStream(File file) {}
public FileInputStream(FileDescriptor fdObj){}
public FileInputStream(String name){}

2、read方法:

// 每次读取一个字节
public int read(){}

// 读取b.length个字节到byte数组中
public int read(byte b[]){}

// 从输入流中读取len个字节到字节数组中
public int read(byte b[], int off, int len){}

3、文件读取:

1、read()

「每次读取一个字节数据,返回字节数,如果到达文件末尾,返回-1。」

「文本」

abc
public static void method_01(String filePath) throws IOException {
  FileInputStream inputStream = null;
  try {
    inputStream = new FileInputStream(filePath);
  // 每次读取一个字节
    for (int i = 0; i < 4; i++) {
      int read = inputStream.read();
      System.out.println(read);
    }
  } catch (FileNotFoundException e) {
    e.printStackTrace();
  } finally {
    if (null != inputStream) {
      // 关闭IO流
      inputStream.close();
    }
  }
}

「执行结果:」

97
98
99
-1

从执行结果可以看出,前三次读取到了数据,返回了对应的ASCII码,当读取到文件末尾的时候,则返回-1。


2、read(byte[] b)

「读入缓冲区的字节总数,如果到达文件末尾,则返回-1。」

「文本:」

abcdefg

声明一个大于真实数据的byte数组读取数据。

public static void method_02(String filePath) throws IOException {

  FileInputStream inputStream = null;
  try {
    inputStream = new FileInputStream(filePath);

    // 声明的长度大于真实数据长度
    byte[] bytes = new byte[20];

    int length = inputStream.read(bytes);

    System.out.println("字节数组长度:" + bytes.length + "  读取到的数据字节长度:" + length);

    for (byte b : bytes) {
      System.out.print(b + " | ");
    }
  } catch (FileNotFoundException e) {
    e.printStackTrace();
  } finally {
    if (null != inputStream) {
      inputStream.close();
    }
  }
}

「执行结果:」

字节数组长度:20  读取到的数据字节长度:7
97 | 98 | 99 | 100 | 101 | 102 | 103 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 

可以看出,当我们byte数组的长度大于字节数组的真实长度之后,那么后面的空间全部使用0做补位,这也恰恰反映了另外一个问题,我们在使用byte[]数组读取文件的时候,千万不要说我设置足够大的长度,就可以高枕无忧提高读取效率,如果遇到小文件,那么也是很容易造成效率低下的。


3、read(byte b[], int off, int len)

读入缓冲区的字节总数,如果读取到文件末尾,则返回-1;

「文本:」

abcdefg

声明一个固定大小的byte数组,循环读取数据

我们的文本有七个字节,声明了一个2个长度的数组,应该循环四次,第五次读取的时候返回-1。

public static void method_03(String filePath) throws IOException {

  FileInputStream inputStream = null;
  try {
    inputStream = new FileInputStream(filePath);

    // 声明2个长度
    byte[] bytes = new byte[2];

    int i = 0;
    while (i < 5) {
      int length = inputStream.read(bytes, 0, bytes.length);
      System.out.println("第" + (i + 1) + "次读取,length: " + length);
      System.out.println("开始输出:");
      for (int j = 0; j < length; j++) {
        System.out.print(bytes[j] + " | ");
      }
      System.out.println();
      i++;
    }
  } catch (FileNotFoundException e) {
    e.printStackTrace();
  } finally {
    if (null != inputStream) {
      inputStream.close();
    }
  }
}

「执行结果:」

第1次读取,length: 2
开始输出:
97 | 98 | 
第2次读取,length: 2
开始输出:
99 | 100 | 
第3次读取,length: 2
开始输出:
101 | 102 | 
第4次读取,length: 1
开始输出:
103 | 
第5次读取,length: -1
开始输出:

「注意:」

可能有的朋友会遇到我之前遇到的问题,他的文本里面写了汉字或者标点符号,「会出现乱码」,我们给文本最后再追加一个中文,并且把每次读取到的byte数组转换成String进行输出,看会出现什么情况。

public static void method_03(String filePath) throws IOException {
  FileInputStream inputStream = null;
  try {
    inputStream = new FileInputStream(filePath);

    byte[] bytes = new byte[2];

    int i = 0;
    while (i < 5) {
      inputStream.read(bytes, 0, bytes.length);
      
      // 将byte[]转换成string
      String s = new String(bytes, StandardCharsets.UTF_8);
      System.out.println(s);
      i++;
    }
  } catch (FileNotFoundException e) {
    e.printStackTrace();
  } finally {
    if (null != inputStream) {
      inputStream.close();
    }
  }
}

「结果:」

ab
cd
ef
g�
��

刚开始脑子抽了,感觉这是什么问题,怎么会乱码呢,如果稍微上点心的都会发现,中文占3个byte字节,你用2个存储那铁定乱码呀。那么你肯定想过那我把数组声明大一点不就好了,如果你这么想过,那你可能还不知道社会的险恶。

那么到底怎么办呢?真的就没办法了吗?接下来我们用一个例子来学习如何解决这种问题。

一个🌰:

将文本中的内容读取出来,输出到控制台。

既然我们知道,上面的乱码是因为英文和中文占用的字节数不同引起的,那我们要是知道了整个文件占用的字节长度,那么不就一次性可以读取出来了。恰好FileInputStream提供了这样一个方法(available),让我们可以获取到整个文件所占用的字节数。

public static void printConsole(String filePath) throws IOException {

  FileInputStream inputStream = null;
  try {
    inputStream = new FileInputStream(filePath);

    // 获取到整个文本占用的整个字节数
    int available = inputStream.available();

    // 声明数组
    byte[] bytes = new byte[available];

    // 读取数据
    int readLength = inputStream.read(bytes, 0, available);
    String s = new String(bytes, StandardCharsets.UTF_8);

    System.out.println("读取到的长度:" + readLength + "  available:" + available);
    System.out.println("读取到的内容: " + s);
  } catch (FileNotFoundException e) {
    e.printStackTrace();
  } finally {
    if (null != inputStream) {
      inputStream.close();
    }
  }
}

「结果:」

读取到的长度:30  available:30
读取到的内容: abcdef一个程序员的成长

这样的话,我们就可以读取到文本中完整的内容了。只有了解了这些,那么才会了解我们的写文件下载的时候为什么要判断 读取到的字节数 !=-1 这样的操作,不然真的很难记住。

更多内容请关注微信公众号:一个程序员的成长

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 用户输入的虎狼之词,怎么校验之后不见了?

    不知道你们有没有对用户输入的东西进行过敏感校验,如果不进行校验,用户属于一些攻击脚本,那么我们的服务就挂逼啦!所以我们首先需要通过过滤器将用户的数据读出来进行安...

    一个程序员的成长
  • SpringBoot整合easyexcel实现Excel导入

    上篇写了Excel如何导出,那么其实在提供的那几个工具类中已经有了导入的方法,只需要直接调用即可。下面我们来简单演示一下,如何导入。

    一个程序员的成长
  • 「分布式」实现分布式锁的正确姿势

    最近看到好多博主都在推分布式锁,实现方式很多,基于db、redis、zookeeper。zookeeper方式实现起来比较繁琐,这里我们就谈谈基于redis实现...

    一个程序员的成长
  • Java习惯用法总结

    在Java编程中,有些知识 并不能仅通过语言规范或者标准API文档就能学到的。在本文中,我会尽量收集一些最常用的习惯用法,特别是很难猜到的用法。

    Java团长
  • AtCoder Beginner Contest 160 A ~ E

    C 水题 题意:一开始没看懂题,就是围绕园的最北的那个点的距离,我一直看成了点都在池塘北面,在一条直线上!害

    杨鹏伟
  • 力扣(LeetCode)刷题,简单题(第18期)

    力扣(LeetCode)定期刷题,每期10道题,业务繁重的同志可以看看我分享的思路,不是最高效解决方案,只求互相提升。

    不脱发的程序猿
  • 宝塔面板数据库备份为20b解决办法

    近期发现宝塔面板内的计划任务中的数据库备份出现了错误,备份文件大小一直是20b,网上的各种办法都试过了,最后由宝塔官方运维-大炮出面解决,在此记录表示感谢。

    小白程序猿
  • LeetCode 945. 使数组唯一的最小增量(贪心)

    来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/minimum-increment-to-make-a...

    Michael阿明
  • 【剑指Offer】17. 打印从1到最大的n位数

    输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

    瑞新
  • [Laravel] Laravel的基本数据库操作部分

    使用DB类的静态方法select来查询数据库,DB::select(),参数:sql语句,参数值数组

    陶士涵

扫码关注云+社区

领取腾讯云代金券