J03-Java IO流总结三 《 FileInputStream和FileOutputStream 》
1. FileInputStream
FileInputStream是一个文件输入节点流,它是一个字节流,它的作用是将磁盘文件的内容读取到内存中。
FileInputStream的父类是InputStream。
该类的源码感觉不用细看,因为它是节点流,已经是相对底层的了,读源码没法读出来它是怎么实现的。
下面是该类的两种简单用法,分别是使用read()和read(byte[] buf)方法来读取流数据。
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException;public class FileInputStreamTest {public static void main(String[] args) {System.out.println("一个一个字节地读取的效果:");test1();System.out.println("\n通过字节数组读取的效果:");test2();}// /*** 使用read()方法,一个字节一个字节地读取*/private static void test1() {FileInputStream fis = null;try {fis = new FileInputStream("./src/res/1.txt");int value = 0;while(-1 != (value = fis.read())) {System.out.print((char)value);//转换为字符并打印出来 }} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if(null != fis) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}// /*** 使用read(byte b[])方法,一次最多读取b.length个字节到b字节数组中*/private static void test2() {FileInputStream fis= null;try {fis = new FileInputStream("./src/res/1.txt");int len = 0;byte[] buf = new byte[1024];while(-1 != (len = fis.read(buf))) {System.out.println(new String(buf, 0, len));}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if(null != fis) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}} }
代码运行效果:
一个一个字节地读取的效果: hello java hello hello ???ú 通过字节数组读取的效果: hello java hello hello 中国
由上面的运行效果可以看到,当读取的文件中存在中文时,若使用read()方法一个字节一个字节地读取,并且每取到一个字节就打印出来,这个时候就会出现乱码,这是因为中文字符一般都不止占用一个字节(GBK编码时占用2个字节,UTF-8编码时占用3个字节),当取到一个字节时,有可能该字节只是一个中文字符的一部分,将中文截断了,这时打印出来肯定就是乱码的了。而第2种方法先将数据读取到字节数组,再用String的String(byte bytes[], int offset, int length)构造方法还原成字符串,则可以一定程度上避免了中文被截断的隐患,所以该方法可以正确的读取到文件内容,并且咩有出现乱码。
在上面的示例中,文件1.txt使用的是GBK编码,而使用方法2中的String(byte bytes[], int offset, int length)方法使用的也是平台的默认字符集GBK来进行解码的,因此可以正确地读取出文件内容,不会有乱码。倘若将1.txt的编码修改为UTF-8编码,此时还用方法2去读取,则会出现如下所示的乱码情况:
通过字节数组读取的效果: hello java hello hello 涓浗
这种情况也很好理解,源文件1.txt是使用GBK编码的,我们使用UTF-8去解码,编码和解码使用的字符集不一致,得到的结果自然是乱码了。这时如果还想将源文件中的内容正确打印到控制台,可以将方法2修改下面所示的方法3:
private static void test3() {FileInputStream fis= null;try {fis = new FileInputStream("./src/res/1.txt");int len = 0;byte[] buf = new byte[1024];while(-1 != (len = fis.read(buf))) {System.out.println(new String(buf, 0, len, "utf-8"));}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if(null != fis) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}
上面代码中,我们通过String的String(byte bytes[], int offset, int length, String charsetName)构造方法,以显式指定字符集的方式来解码字节数组。如此,同样可以正确读出文件中的内容。综上,可知还原字符串的时候,必须保证编码的统一!
2. FileOutputStream
FileOutputStream是文件输出节点流,同样它也是个字节流。根据API文档可知,FileOutputStream文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。
首先该类的几个构造方法需要注意一下:
FileOutputStream(String name) throws FileNotFoundException
该方法创建一个向具有指定名称的文件中写入数据的输出文件流,事实上该方法的底层会调用重载的构造方法来创建指向文件的输出流。由源码可以看出它的实现思路:
public FileOutputStream(String name) throws FileNotFoundException {this(name != null ? new File(name) : null, false);}
另外,需要注意的是,使用该方法指向的文件,若文件已存在,则通过该输出流写入时会覆盖文件中的原有内容;若文件不存在,则会先创建文件,再向文件中写入数据。即便如此,该方法还是有可能会抛出FileNotFoundException,这是因为,假如你传入的是一个根本不存在的文件路径(如:suhaha/xxx…/2.txt),那么jvm无法在一个不存在的路径上创建文件,这个时候就会报FileNotFoundException异常。
FileOutputStream(String name, boolean append) throws FileNotFoundException
该方法的功能跟上面的差不多一样,只不过它可以通过第二个参数append,来决定是追加还是覆盖目标文件中的内容,若传入true,则是追加,若传入false,则是覆盖。
示例代码:
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;public class FileOutputStreamTest {public static void main(String[] args) {FileOutputStream fos = null;try {fos = new FileOutputStream("./src/res/2.txt"); //路径正确时,若文件不存在,则自动创建 // fos = new FileOutputStream("suhaha/xxx"); //如果是随便乱写一个压根不存在的路径,则会报FileNotFoundException异常String str1 = "hello java";String str2 = "中国";//将字符串转换为字节数组byte[] bytes1 = str1.getBytes();byte[] bytes2 = str2.getBytes();fos.write(bytes1[0]); //将单个字节写入输出流中,写入:hfos.write(bytes2); //将整个字节数组写入,写入:中国fos.write(bytes1, 6, 4);//将字节数组bytes1中从索引6开始的4个字节写入输出流中,写入:java } catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if(null != fos) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}}} }
代码运行效果:
同样,在通过FileOutputStream将数据写入目标文件时,也有可能存在由编码引起的乱码问题。
在上面的示例中,在使用str1.getBytes()方法将字符串转换为字节数组时,由getBytes()方法的源码可以看出,它使用的是平台默认的字符集进行编码,我在windows平台上默认是使用GBK字符集。然后,最后通过输出流写入的文件也是使用GBK进行编码的,因此最后写入的数据没有出现乱码,倘若目标文件2.txt是UTF-8编码,则使用上面的代码进行写入就会出现如下所示的乱码:
此时可以通过手动将2.txt文件的编码由UTF-8改为GBK,来将数据正确显式出来。
然而,如果我们的需求就是需要将数据写入一个用UTF-8编码的目标文件中,则可用通过使用String类的byte[] getBytes(String charsetName)方法显式指定字符集来将字符串转换为字节数组,这样就可以将数据正确写入一个UTF-8目标文件中。示例代码如下所示:
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;public class FileOutputStreamTest {public static void main(String[] args) {FileOutputStream fos = null;try {fos = new FileOutputStream("./src/res/2.txt"); //路径正确时,若文件不存在,则自动创建 // fos = new FileOutputStream("suhaha/xxx"); //如果是随便乱写一个压根不存在的路径,则会报FileNotFoundException异常String str1 = "hello java";String str2 = "中国";//将字符串转换为字节数组byte[] bytes1 = str1.getBytes();byte[] bytes2 = str2.getBytes("utf-8");fos.write(bytes1[0]); //将单个字节写入输出流中,写入:hfos.write(bytes2); //将整个字节数组写入,写入:中国fos.write(bytes1, 6, 4);//将字节数组bytes1中从索引6开始的4个字节写入输出流中,写入:java } catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if(null != fos) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}}} }
3. FileInputStream和FileOutputStream综合使用示例
下面的代码中定义了两个方法,test1()和test2(),test1()方法从一个GBK编码的源文件中读取数据,复制到一个以UTF-8编码的目标文件中;test2()则正好反之,它从一个UTF-8编码的源文件中读取数据,复制到一个以GBK编码的目标文件中。
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;public class FileInOutStreamTest {public static void main(String[] args) {// test1(); test2();}//*** 从1.txt文件中读取数据,复制到2.txt文件中* 其中,1.txt是用GBK编码的,2.txt使用UTF-8编码的*/private static void test1() {FileInputStream fis = null;FileOutputStream fos = null;try {fis = new FileInputStream("./src/res/1.txt");fos = new FileOutputStream("./src/res/2.txt");int len = 0;byte[] buf = new byte[1024];while(-1 != (len = fis.read(buf))) { //从源文件1.txt读取到字节数组中的数据是GBK编码的String str = new String(buf, 0, len); //先转为字符串,这里默认使用GBK进行解码byte[] bytes = str.getBytes("utf-8"); //再显式指定以utf-8字符集进行编码fos.write(bytes); //将字节数组数据写入到以utf-8编码的目标文件2.txt中 fos.flush();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if(null != fos) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}if(null != fis) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}//*** 从2.txt文件中读取数据,复制到1.txt文件中* 其中,1.txt是用GBK编码的,2.txt使用UTF-8编码的*/private static void test2() {FileInputStream fis = null;FileOutputStream fos = null;try {fis = new FileInputStream("./src/res/2.txt");fos = new FileOutputStream("./src/res/1.txt");int len = 0;byte[] buf = new byte[1024];while(-1 != (len = fis.read(buf))) { //从源文件2.txt读取到字节数组中的数据是utf-8编码的String str = new String(buf, 0, len, "utf-8"); //先转为字符串,这里显式指定使用utf-8进行解码byte[] bytes = str.getBytes(); //再以默认字符集GBK进行编码fos.write(bytes); //将字节数组数据写入到以GBK编码的目标文件1.txt中 fos.flush();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if(null != fos) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}if(null != fis) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}} }
注:上面演示的方法可能比较low,但是如果只使用目前的这两个文件输入输出流的话,这是我能想到的一个解决办法。
通过转换流InputStreamReader和OutputStreamWriter也可以实现该功能,可以参考J07-Java IO流总结七 《 InputStreamReader和OutputStreamWriter 》
转载于:https://www.cnblogs.com/suhaha/p/9651421.html
J03-Java IO流总结三 《 FileInputStream和FileOutputStream 》相关推荐
- Java IO流(三)
字节 字符 输入 InputStream Reader 输出 OutputStream Writer **********************字节写************************ ...
- Java IO流学习总结三:缓冲流-BufferedInputStream、BufferedOutputStream
Java IO流学习总结三:缓冲流-BufferedInputStream.BufferedOutputStream 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/ ...
- Java基础之IO流(三)
IO流(三) Properties集合:是Map集合 Properties 类表示了一个持久的属性集 Properties 可保存在流中或从流中加载 特点: 1,该集合中的键和值都是字符串类型. 2, ...
- Java基础—IO流(三)
IO流(三) File类 一.概述 File类用于将文件或文件夹封装成对象,方便对文件和文件夹的属性信息进行操作.该类可以作为参数传递给IO流的构造函数,弥补流对象在操作文件和文件夹上的缺陷. 二.F ...
- Java读取文件流用什么对象_使用Java IO流实现对文本文件的读写过程中,通常需要处理下列( )异常。_学小易找答案...
[论述题]请根据第一次平时作业的选题,结合第二次课内容,自拟一个论文提纲. [单选题]在 switch ( expression )语句中, expression 的数据类型不能是 ( ) [单选题] ...
- java io流大全_Java IO流系统整理
Java IO流的分类 Java中的流,可以从不同的角度进行分类. 按流向分类: 输入流: 程序可以从中读取数据的流. 输出流: 程序能向其中写入数据的流. 按数据传输单位分类: 字节流:以字节(8位 ...
- Java IO流学习总结七:Commons IO 2.5-FileUtils
Java IO流学习总结七:Commons IO 2.5-FileUtils 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/5497 ...
- java io流 教程_Java基础教程:IO流与文件基础
Java:IO流与文件基础 说明: 本章内容将会持续更新,大家可以关注一下并给我提供建议,谢谢啦. 走进流 什么是流 流:指的是从源到目的地的字节的有序序列. 在Java中,可以从其中读取一个字节序列 ...
- java IO流小结
Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...
- java io流的学习总结~~
java io流的学习总结~~ 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类, ...
最新文章
- 湖南长郡2021高考成绩查询时间,2021年湖南新高考六校、长郡十五校联考时间公布...
- 全球芯片行业现状分析:大家都在依赖美国 未来如何破局?
- 返回一个整数数组中最大子数组的和
- chrome无法登陆账号,显示操作超时的解决方案
- 基本的输入输出函数介绍
- 盘点2021:数据中心行业迎来转折点
- xcopy复制文件夹及其子文件_嗨学习:如何给电脑中文件夹设置密码
- 前端基础到进阶(1):HTML基础入门
- Mybatis的复习
- 机器学习笔记(十一):优化梯度公式 | 凌云时刻
- DWS自动化包裹称重扫码测体积快手台的开发和源码
- Python3之excel操作--xlsxwriter模块
- Android自定义View,仿QQ显示用户等级
- servlet会话技术 cookie和session
- Mysql 8.0 安装详细教程、问题处理、卸载(亲测可用)
- 微软服务器上市时间,微软Office 2010全球发布会时间确定
- 特征工程之特征分箱(决策树分箱、卡方分箱、bestks以及评价标准WOE和IV)
- 移动宽带虚拟网服务器设置,移动宽带路由器怎么设置?
- 【Linux 中国】最适合程序员的 10 款 Linux 发行版
- 禁用Windows10系统驱动程序强制签名的简单方法