前言----
本来不想写前言了,但是写完,发现写得太好了,遇到就好好看一看啊!!!!
注:欢迎转载,转载请注明来处
目录
一. 简单理解什么是流?
我是把流理解成一个导管,这个导管连接了硬盘中的某个文件和程序.
输入流:输入数据到程序(既从文件中读)
输出流; 程序输出数据到文件(既写到文件)
二.字节输入流
正如我们所知, 计算机底层都是0和1, 有很多种编码规则, 其作用就是将各自字符定义成特定的01串.,方便计算机识别.我们如果要从文件中读取字符,可以按字节来进行读取,这边我们用FileInputStream来进行读取,字节流,按字面意思我们就知道要用byte或者byte数组来进行读取.
FileInputStream:
FileInputStream是继承了抽象类InputStream。FileInputStream可以通过
1.int read() 从此输入流中读取一个字节。
2int read(byte[] b ) 从此输入流中将最多 b.length 个字节的数据读入一个 byte数组中。
测试文件:
:
demo(请细看代码和注释)
package Test;
import java.io.*;
public class ByteStream {
public static void main(String[] args) {
// TODO Auto-generated method stub
ByteStream myTest = new ByteStream();
myTest.testInputStream();
}
public void creatFile(File f) {
if(!f.exists()) {//先判断文件存不存在
//不存在的话,判断判断目录存不存在
if(f.getParentFile().exists()!=true) {
f.getParentFile().mkdirs();//不存在就创建
}
//创建该文件
try {
f.createNewFile();
}catch(Exception e) {
e.printStackTrace();
}
}
}
public void testInputStream() {
File f = new File("D:/data.txt");
creatFile(f);//若不存在可以自动创建
FileInputStream fis =null;// 先创建一个输入流,初始为null
try { //流创建失败时会抛出异常,应该try...catch或者throws
fis = new FileInputStream(f);
//创建一个大小等于文件字节大小的byte[]数组
byte [] myByte = new byte[(int)f.length()];
//从文件中一次读取多个字节
fis.read(myByte);
//将byte字节转化为对应的字符
String str =new String(myByte);
System.out.println(str);
}catch(Exception e) {
e.printStackTrace();
}finally {
if(fis!=null) {
try {
fis.close();//记得关闭流,可能会关闭失败,所以也要捕获或者throws
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
}
结果:
三.字节输出流
FileOutputStream 继承了抽象类OutputStream, 意为文件输出流,是用于将数据写入File,通过write方法将数据写到文件
1.void write(byte[] b)
将 b.length 个字节从指定 byte 数组写入此文件中。
2.void write(int b) 将指定字节写入此文件。
- 写入时不设置追写 的话, 会先清空文件再写入
测试文件:
demo(不要错过注释)
public void testOutputStream() {
File f = new File("D:data.txt");
creatFile(f);
try( FileOutputStream fos = new FileOutputStream(f) ){
//用输出字节流写入文件的时候,如果文件不存在,但是父路径存在,此时会自动创建对应的文件
//如果对应的父目录不存在的话就会抛出异常
byte [] myByte = { 97,32,98,32,99};
fos.write(myByte);//一次写到文件的字节长度为myByte的长度
/*
for(int i = 0 ;i <myByte.length; i++) {
fos.write(myByte[i] );//一个字节一个字节的写入
fos.write("\r\n".getBytes());//换行写入,在Windows写换行符为"\r\n"
}
*/
}catch(Exception e) {
e.printStackTrace();
}
}
测试结果:原先的内容被清空了, 97,98,99对应的字符是abc, 32对应空格符
- 在原文件的基础上追加写入( 使用FileOutputStream(f, true) )
测试文本:
demo:
//字节输出流,追加写入
public void testOutputStream() {
File f = new File("D:/data.txt");
creatFile(f);
//追加写入
try( FileOutputStream fos = new FileOutputStream(f,true) ){
//用输出字节流写入文件的时候,如果文件不存在,但是父路径存在,此时会自动创建对应的文件
//如果对应的父目录不存在的话就会抛出异常
//参数为true代表追加写入
byte [] myByte = { 97,32,98,32,99};
fos.write(myByte);//一次写到文件的字节长度为myByte的长度
/*
for(int i = 0 ;i <myByte.length; i++) {
fos.write(myByte[i] );//一个字节一个字节的写入
fos.write("\r\n".getBytes());//换行写入,在Windows写换行符为"\r\n"
}
*/
}catch(Exception e) {
e.printStackTrace();
}
}
测试结果:在原文件的内容上成功追加写入,而不会覆盖掉
四.流的正确关闭方式
无论是输入流还是输出流,在使用完毕之后都应该进行关闭,否则会占有资源, 如果为关闭的流很多的话,对程序的性能会有影响
1.在try{}内关闭,是不安全的关闭方式
2.在finally内关闭-----安全的写法
3.用try-with-resource自动关闭
在JDK7以前,Java没有自动关闭外部资源的语法特性,直到JDK7中新增了try-with-resource语法,才实现了这一功能.
五.字符输入流
在不同的编码规则下:一个字符可以占多个字节,那么能不能一个字符一个字符地读取到文件呢?当然是可以的,我们用FileReader的read()进行读取字符, 由于是字符流,自然是用char或char数组来存储读取的字符
1.public int read(char[] cbuf) 一次性读取cbuf.length个字符到cbuf中
2.public int read(char c) 一次读取一个字符
测试文件:
demo:
public void testFileReader() {
File f = new File("D:/data.txt");
try(FileReader fRe = new FileReader(f)){
//由于一个字符有多个字符,长度设为文件的字节长度,肯定够用
char [] myChar =new char[(int)f.length()];
fRe.read(myChar);
for(char i : myChar) {
System.out.print(i);
}
}catch(Exception e) {
e.printStackTrace();
}
}
测试结果:
六.字符输出流
用FileWriter把字符写到文件中, 用到它的write()方法:
- demo(不进行追写,覆盖掉原文件)
测试之前:
public void testFileWriter() {
File f = new File("D:/data.txt");
isCreatFile(f);
try (FileWriter fWr = new FileWriter(f)){
char [] myChar= {'1','2','3','4','5'};
String myChar2 = "234324 34343";
fWr.write(myChar);
fWr.write("\r\n");//写入换行符
fWr.write(myChar2);
}catch(Exception e) {
e.printStackTrace();
}
}
测试结果:
- demo( 用new FileWriter(f,true) 在原文件的基础上追写,不覆盖掉原文件 )
测试之前:
public void testFileWriter() {
File f = new File("D:/data.txt");
isCreatFile(f);
try (FileWriter fWr = new FileWriter(f,true)){
char [] myChar= {'1','2','3','4','5'};
String myChar2 = "234324 34343";
fWr.write(myChar);
fWr.write("\r\n");
fWr.write(myChar2);
}catch(Exception e) {
e.printStackTrace();
}
}
测试结果:
七.字节流和字符流的比较
问:字符流和字节流的差别在哪里,为什么它能做到按字符读取
答:
1.字符流的本质还是字节流,文件的底层存储中都是01数字串,不存在字符的,我们打开文件看到的字符都是经过解码后呈现出来的.
2.字符流的本质用到缓冲区,二者的工作示意图如下所示:
大概就是说字符流可以在缓冲区的byte数组里面形成一个byte数组,然后直接传byte数组给程序,而字节流每次只能传一个字节而已