- IO的相关概念
- 什么时候使用字节流,什么时候使用字符流?
- 字节输入流FileInputStream
- 读取方式:
- 字节输出流 FileOutputStream
- 写入方式
- 实现数据的追加
- 字节缓冲输入流 BufferedInputStream
- 字节缓冲输出流 BufferedOutputStream
- 转换流
- 字符输出流 OutputStreamWriter(字符转换流)
- 字符输入流 InputStreamReader
- 字符转换流的简便写法
- 字符缓冲输入流 BufferedReader
- 字符缓冲输出流 BufferedWriter
- 特殊方法
IO:是用来解决设备之间数据传输的问题
流(Stream)是一个抽象、动态的概念,是一连串连续动态的数据集合,是一组有顺序的,有起点和终点的字节集合。流就像是一个连接了文件和程序的水管中的水,是对数据传输的抽象。
Java对数据的 *** 作是通过流的方式。用于 *** 作流的对象都在IO包中
按照流向进行划分:
- 输入流 InputStream
- 输出流 OuputStream
按照数据类型划分:
- 字节流 InputStream / OutputStream
字节流以byte(字节)为单位,进行输入或输出 *** 作
InputStream字节输入流:读取数据。抽象类,是所有输入流的父类。定义了所有输入流都具有的共同特征。
OutputStream字节输出流:写出数据。抽象类,是所有输出流的父类。定义了所有输出流都具有的共同特征。 - 字符流 Reader / Writer
字符流以字符为单位,根据ASCII码表映射字符
Reader字符输入流:读取数据,抽象类
Writer字符输出流:写出数据,抽象类
只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
文本文件,视频图片等在计算机中的存储方式都是字节,因此可以用windows自带的记事本打开需要上传或者下载的数据文件,如果里面的内容可以看懂,那么就用字符流。看不懂就用字节流。
FileInputStream是InputStream的子类,可以从文件流中读取数据。
这是jdk文档中对FileInputStream的作用的描述
构造方法:
FileInputStream(File file)
FileInputStream(String name)
- int read()
从该输入流读取一个字节的数据。
读取输入流的下一个字节,并返回字节表示的int值(0~255)。一个字节是八位,二进制的11111111转为十进制是255 - int read(byte[] b)
从该输入流读取最多 b.length个字节的数据为字节数组。
package review.IO; import java.io.FileInputStream; import java.io.IOException; public class Demo1 { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("a.txt"); System.out.println(fis.read()); //97 System.out.println((char)fis.read()); //b,已经读取过的字节a不会被反复读取,因此是b //像上面这样读取太慢,用while循环改进 //当读到末尾时,fis.read()语句返回-1 int n = 0; while((n=fis.read())!=-1){ System.out.print((char)n); //cdefg } //关闭流 fis.close(); } }
package review.IO; import java.io.FileInputStream; import java.io.IOException; public class Demo2 { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("a.txt"); //数组长度用1024,这样比较合适,不会太长浪费资源,也不会太短 byte[] bytes = new byte[1024]; int len; //用len接收fis.read(byte[] b)实际读取的字节长度 //读到文件末尾时返回-1 //(len =fis.read(bytes)注意这里用括号括住 //这里不会读取一个字节就打印s,因为是一次性读取一个字节数组 while((len =fis.read(bytes))!=-1){ //这里的长度是从0到len,按实际读取的字节数将数组转为String类型 String s = new String(bytes,0,len); System.out.println(s); //结果为abcdefg } fis.close(); } }字节输出流 FileOutputStream
FileOutputStream是OutputStream的具体实现类
构造方法:
FileOutputStream(File file)
FileOutputStream(String name)
- void write(int b) 将指定的字节写入此文件输出流。
- void write(byte[] b) 将 b.length个字节从指定的字节数组写入此文件输出流。
- write(byte[] b, int off, int len) 将 len字节从位于偏移量 off的指定字节数组写入此文件输出流。
package review.IO; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public class Demo3 { public static void main(String[] args) throws IOException { //构造方法一,通常使用这种构造方式 FileOutputStream fos = new FileOutputStream("b.txt"); //构造方法二 File f = new File("a.txt"); FileOutputStream fos1 = new FileOutputStream(f); //write(int b) fos.write(97); fos.write(98); //写入换行符,否则写入的所有字符都在同一行 fos.write("rn".getBytes()); //getBytes()将字符串存入字符数组中 //write(byte[] b) fos.write("hello java".getBytes()); fos.write("rn".getBytes()); byte[] bys = {97,98,99,100,101}; //从数组的索引1位置读取三个字节写入文件 fos.write(bys,1,3); fos.close(); } }实现数据的追加
FileOutputStream(File file, boolean append)
FileOutputStream里面的append参数默认是false,即每次往文件中写入数据时,都会覆盖文件中原来的内容
将append参数改为true后,就会修改为往文件中原来的内容后面追加内容
FileOutputStream fos = new FileOutputStream("b.txt",true);
将上面的代码里面,构造FileOutputStream对象的代码修改一下
结果为
在原来内容的后面追加,而不是覆盖原有的内容
在我们之前用InputStream读取文件中的数据的时候就发现,用一个字节数组取读取,比每次单个读取一个个的字节要高效快速很多。这种思想被java用到了字节缓冲流里面,缓冲流的存在就是先将数据读取到缓冲流(内存中),然后一次性从内存中读取多个字符,从而提高读取的效率。
这里实际上用到了装饰者模式,详细内容可以看这篇博客
Java IO流之FilterInputStream和FilterOutputStream分析
BufferedInputStream本质上是通过一个内部缓冲区数组实现的。当我们通过read()读取输入流的数据时,BufferedInputStream会将该输入流的数据分批的填入到缓冲区中。每当缓冲区中的数据被读完之后,输入流会再次填充数据缓冲区;如此反复,直到我们读完输入流数据位置。
构造方法:
- BufferedInputStream(InputStream in)
- BufferedInputStream(InputStream in, int size) 指定缓冲区大小size
这里的InputStream in参数,在创建对象时实际传入的是InputStream的具体实现类
package review.IO; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; public class Demo4 { public static void main(String[] args)throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt")); int len = 0; byte[] bytes = new byte[1024]; while((len=bis.read(bytes))!=-1){ String s = new String(bytes,0,len); System.out.println(s); //读取结果为abcdefg } bis.close(); } }字节缓冲输出流 BufferedOutputStream
flush()的作用:刷新缓冲区,将缓冲区的内容写入到文件中
flush()与close()的区别:
1、close()方法调用是关闭流对象,但是呢,会先刷新一次缓冲区,关闭之后,就不能继续使用该流对象了
2、flush()方法调用后,刷新一次缓冲区,但是流对象可以继续使用
使用缓冲输出流往文件里面写入数据的时候,flush和close至少有一个才能将数据写入文件,否则数据将一直存在缓冲区,直到缓冲区满,然后自动写入
package review.IO; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; public class Demo5 { public static void main(String[] args) throws IOException { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt")); bos.write("你好,hello".getBytes()); //flush将缓冲区里面的内容直接输出,而不用等待缓冲区满 bos.flush(); bos.close(); } }转换流
当文件内容中有中文的时候,如果我们只读取一个字节,然后输出这个字节,就会发现输出的结果是乱码
package review.IO; import java.io.FileInputStream; import java.io.IOException; public class Demo6 { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("a.txt"); int b = 0; while((b=fis.read())!=-1){ System.out.print((char)b); } } }
读取的结果为
是一串乱码,这是因为中文占用的字节数不止一个,多个字节才能组成一个中文汉字。如果单独拆出一个字节,就会发现输出的就是乱码
正因为这样,字节流 *** 作中文很不方便,所以需要用到字符流
字符流是建立在字节流之上的,它能够提供字符层次的编码和解码
转换流为我们建立了字节流到字符流的桥梁,其本身是一种处理流,提供了字节流和字符流之间的转换。
Java中提供了两个转换流:InputStreamReader 和 OutputStreamWriter,这两个类都属于字符流。
InputStreamReader将字节输入流转为字符输入流,继承自Reader。
OutputStreamWriter是将字符输出流转为字节输出流,继承自Writer。
在计算机中是以二进制的形式存储的数据,我们实际看到的文字信息都是讲二进制数据转换之后显示而来的。这两者之间存在着一种编码与解码的关系。
编码:类似与加密的过程,把能看懂的字符或字符串转成看不懂的字节。 String – byte[]
解码:类似于解密的过程,把看不懂的字节转成看得懂的字符或字符串。 byte[] – String
字符流其实可以理解为转换流。字符流=字节流+编码表。
package review.IO; import java.io.IOException; import java.util.Arrays; public class Demo7 { public static void main(String[] args) throws IOException { String s = "你好世界"; //byte[] getBytes(Charset charset) //使用给定的charset将该String编码为字节序列,将结果存储到新的字节数组中。 //String -- byte[] byte[] bytes =s.getBytes("UTF-8"); System.out.println(Arrays.toString(bytes)); //String(byte[] bytes, Charset charset) //构造一个新的String由指定用指定的字节的数组解码charset //byte[] -- String String ss = new String(bytes,"UTF-8"); System.out.println(ss); } }
结果为
括号里面的UTF-8可以换成Unicode或者GBK等都可以,但是要注意编码和解码用的charset编码表要一样
OutputStreamWriter写数据方法
public void write(int c)
public void write(char[] cbuf)
public void write(char[] cbuf,int off,int len)
public void write(String str)
public void write(String str,int off,int len)
注意:从字符流开始,一次性读取一个字符数组,而不是一个字节数组。用char[] 数组
package review.IO; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; public class Demo8 { public static void main(String[] args) throws IOException { OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt")); //write(int c) osw.write(97); //a //write(char[] cbuf) 写入一个字符数组 char[] chars = {'a','b','c','d','e'}; osw.write(chars); //abcde //write(char[] cbuf,int off,int len) 将字符数组中的一部分写到文件中 char[] chars1 = {'a','b','c','d','e'}; //从下标1开始读取两个字符 osw.write(chars1,1,2); //bc //write(String str) 将字符串写入到文件中 osw.write("hello"); //hello //write(String str,int off,int len) 将字符串的一部分写入到文件中 String s2 = "hadoop"; osw.write("hadoop",1,2); //ad osw.flush(); osw.close(); } }字符输入流 InputStreamReader
- InputStreamReader(InputStream in)
读取数据,根据默认的编码将字节流转换为字符流
创建一个使用默认字符集的InputStreamReader。 - InputStreamReader(InputStream in, String charsetName)
读取数据,根据指定的编码将字节流转换为字符流
创建一个使用指定字符集的InputStreamReader。
读取数据的方法:
- public int read():一次只读一个字符
- public int read(char[] cbuf):一次读取一个字符数组
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class Demo9 { public static void main(String[] args) throws IOException { //InputStream in = new FileInputStream("a.txt) InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt")); //一次只读取一个字符 int ch = 0; while((ch=isr.read())!=-1){ System.out.println((char)ch); } isr.close(); } }
结果为
可以发现控制台这里输出的是中文字符,而不再是int类型的数字
public class Demo9 { public static void main(String[] args) throws IOException { //InputStream in = new FileInputStream("a.txt) InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt")); //一次读取多个字符,也就是读取一个字符数组 char[] chars = new char[1024]; int len = 0; while((len=isr.read(chars))!=-1){ System.out.println(new String(chars,0,len)); } isr.close(); } }字符转换流的简便写法
字符流 = 字节流 + 编码表
OutputStreamWriter = FileOutputStream + 编码表(Unicode)
InputStreamReader = FileInputStream + 编码表(Unicode)
字符输出流 OutputStreamWriter 简便写法 FileWriter
字符输入流 InputStreamReader 简便写法 FileReader
package review.IO; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class Demo11 { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("a.txt"); FileWriter fw = new FileWriter("b.txt"); int len = 0; char[] chars = new char[1024]; while((len=fr.read(chars))!=-1){ fw.write(chars,0,len); fw.flush(); } fw.close(); fr.close(); } }
结果成功将a.txt里面的内容写入到b.txt里面
注意:当程序中有多个流需要关闭的时候,按照从下到上的顺序关闭。
比如这里先打开的fr,后打开的fw。关闭的时候则先关fw后关fr
字符流为了高效读写,也提供了相对应的字符缓冲流
BufferedWriter:字符缓冲输出流
BufferedReader:字符缓冲输入流
BufferedReader(Reader in) 创建使用默认大小的输入缓冲区的缓冲字符输入流。
package review.IO; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class Demo10 { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader("a.txt")); //一、一次读取一个字符 int ch = 0; while((ch=br.read())!=-1){ System.out.println((char)ch); } //二、一次读取一个字符数组 int len = 0; char[] chars = new char[1024]; while((len=br.read(chars))!=-1){ System.out.println(new String(chars,0,len)); } br.close(); } }
结果分别是(注意两段代码要分开运行,否则第二段代码读取内容为空,这里是为了直观所以放在了一起)
BufferedWriter:字符缓冲输出流
将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。
可以指定缓冲区大小,或者可以接受默认大小。
默认值足够大,可用于大多数用途。
创建方式:
- BufferedWriter(Writer out) 创建使用默认大小的输出缓冲区的缓冲字符输出流
- BufferedWriter(Writer out, int sz) 创建一个新的缓冲字符输出流,使用给定大小的输出缓冲区。
package review.IO; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class Demo12 { public static void main(String[] args) throws IOException { BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")); bw.write(97); //a bw.write(98); //b bw.write("hello"); //hello bw.write("hadoop",1,2); //ad char[] chars = {'a','b','c','d'}; bw.write(chars); //abcd bw.write(chars,1,2); //bc bw.flush(); bw.close(); } }特殊方法
字符缓冲流的特殊方法:
BufferedWriter —— public void newline()写一行行分隔符,用于换行
BufferedReader —— public String readLine()读一行文字,到换行符终止,然后转而读取下一行
package review.IO; import java.io.*; public class Demo13 { public static void main(String[] args) throws IOException { write(); read(); } public static void read() throws IOException{ BufferedReader br = new BufferedReader(new FileReader("a.txt")); String line = null; //(line=br.readLine())每次读取文件的一行给line,然后执行while循环体中的打印语句 //所以每次打印一行内容 while((line=br.readLine())!=null){ System.out.println(line); } br.close(); } public static void write() throws IOException{ BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")); for(int i=0;i<10;i++){ bw.write("学习大数据的第 "+i+" 天"); //newline()每写完一句就换到下一行 bw.newline(); bw.flush(); } } }
运行write()方法的结果
使用read()方法的结果
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)