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]); //将单个字节写入输出流中,写入:h
fos.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]); //将单个字节写入输出流中,写入:h
fos.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 》
J03-Java IO流总结三 《 FileInputStream和FileOutputStream 》的更多相关文章
- java中OutputStream字节流与字符流InputStreamReader 每一种基本IO流BufferedOutputStream,FileInputStream,FileOutputStream,BufferedInputStream,BufferedReader,BufferedWriter,FileInputStream,FileReader,FileWriter,InputStr
BufferedOutputStream,FileInputStream,FileOutputStream,BufferedInputStream,BufferedReader,BufferedWri ...
- java IO流 (三) 节点流(或文件流)
1.FileReader/FileWriter的使用:1.1 FileReader的使用 /* 将day09下的hello.txt文件内容读入程序中,并输出到控制台 说明点: 1. read()的理解 ...
- java io系列07之 FileInputStream和FileOutputStream
本章介绍FileInputStream 和 FileOutputStream 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_07.html File ...
- IO流9 --- 使用FileInputStream和FileOutputStream读写非文本文件 --- 技术搬运工(尚硅谷)
字节流读写非文本文件(图片.视频等) @Test public void test5(){ File srcFile = new File("FLAMING MOUNTAIN.JPG&quo ...
- Java IO流学习总结三:缓冲流-BufferedInputStream、BufferedOutputStream
Java IO流学习总结三:缓冲流-BufferedInputStream.BufferedOutputStream 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/ ...
- Java:IO流与文件基础
Java:IO流与文件基础 说明: 本章内容将会持续更新,大家可以关注一下并给我提供建议,谢谢啦. 走进流 什么是流 流:从源到目的地的字节的有序序列. 在Java中,可以从其中读取一个字节序列的对象 ...
- java IO流详解
流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...
- Java IO流学习总结
Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...
- Java IO流题库
一. 填空题 Java IO流可以分为 节点流 和处理流两大类,其中前者处于IO操作的第一线,所有操作必须通过他们进行. 输入流的唯一目的是提供通往数据的通道,程序可以通过这个通道读取数 ...
- Java IO流系统整理
Java IO流的分类 Java中的流,可以从不同的角度进行分类. 按流向分类: 输入流: 程序可以从中读取数据的流.输出流: 程序能向其中写入数据的流. 按数据传输单位分类: 字节流:以字节(8位二 ...
随机推荐
- 2018.09.22 atcoder Integers on a Tree(构造)
传送门 先考虑什么时候不合法. 第一是考虑任意两个特殊点的权值的奇偶性是否满足条件. 第二是考虑每个点的取值范围是否合法. 如果上述条件都满足的话就可以随便构造出一组解. 代码: #include&l ...
- 被弃用的php函数以及被那个代替
原文链接 http://blog.csdn.net/a11085013/article/details/8937848 下面列举了部分被弃用的函数: call_user_method ...
- mysql 查询表 的所有字段名称
select COLUMN_NAME from information_schema.COLUMNS where table_name = 'your_table_name' and table_sc ...
- Intelj IDEA的pom.xml显示错误can not reconnect
从GitHub上边down下来的开源项目,报错莫名其妙,后来发现是跟本地hosts文件有关系 hosts文件加上 127.0.0.1 localhost 然后pom文件reload一下就
- UVa 12034 Race (递推+组合数学)
题意:A,B两个人比赛,名次有三种情况(并列第一,AB,BA).输入n,求n个人比赛时最后名次的可能数. 析:本来以为是数学题,排列组合,后来怎么想也不对.原来这是一个递推... 设n个人时答案为f( ...
- 有关在 Word 中撰写博客的帮助
目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...
- 20155225 2016-2017-2 《Java程序设计》第九周学习总结
20155225 2016-2017-2 <Java程序设计>第九周学习总结 教材学习内容总结 JDBC入门 了解JDBC架构 使用JDBC API JDBC是用于执行SQL的解决方案,开 ...
- hdu 5046 二分+DLX模板
http://acm.hdu.edu.cn/showproblem.php?pid=5046 n城市建k机场使得,是每个城市最近机场的距离的最大值最小化 二分+DLX 模板题 #include < ...
- ploymer
developer guide 接下来看声明属性 声明属性 声明属性时,可设定的参数 type:属性反序列化 value:[function(){}],配置属性默认值 readonly refle ...
- x13 vs md5
x13 vs md5 阅读: 评论: 作者:Rybby 日期: 来源:rybby.com 最近在设计巴巴变时想对用户设计的节点模块添加锁定功能,比如你的网站可以让用户发表文章或评论,而你想让用 ...