「FileInputSteam」
public FileInputStream(File file) {} public FileInputStream(FileDescriptor fdObj){} public FileInputStream(String name){}
// 每次读取一个字节 public int read(){} // 读取b.length个字节到byte数组中 public int read(byte b[]){} // 从输入流中读取len个字节到字节数组中 public int read(byte b[], int off, int len){}
「每次读取一个字节数据,返回字节数,如果到达文件末尾,返回-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。
「读入缓冲区的字节总数,如果到达文件末尾,则返回-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[]数组读取文件的时候,千万不要说我设置足够大的长度,就可以高枕无忧提高读取效率,如果遇到小文件,那么也是很容易造成效率低下的。
读入缓冲区的字节总数,如果读取到文件末尾,则返回-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 删除。
我来说两句