IO流
来源:互联网 发布:未妨惆怅是清狂 知乎 编辑:程序博客网 时间:2024/05/18 02:36
IO流
字节流
在计算机中,所有文件都是以字节形式存在的,IO流中针对字节的输入输出提供了一系列的流,统称为字节流。
InputStream
- int read():从输入流读取一个字节,把它转换为0~255之间的整数,并返回这一整数,返回读取到的内容。如果因为已经到达流末尾而没有可用的字节,则返回值-1。
- int read(byte[ ] b):从输入流读取若干字节,把它们保存到参数b指定的字节数组中,返回整数表示读取到的字节数。如果因为已经到达流末尾而没有可用的字节,则返回值-1。
- void close():关闭此输入流并释放与该留关联的所有系统资源
第一个read()方法是从输入流中逐个读入字节,而第二个read()方法则将若干个字节以字节数组的形式一次性读入,从而提高读数据的效率。在进行IO流操作时,当前IO流会占用
OutputStream
- void write(int b):将指定的字节写入此流。一次写一个字节(比如我传入97,则会把对应的字母a写进去)虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前三个8位。
- void write(byte[ ] b):把字节数组中的所有数据都写入输出流
- void write(byte [ ] b,int off,int len):将指定byte数组中从偏移量off开始的len个字节写入输出流。(从数组b的off位置开始写入len个字节)
- void close():关闭此输出流并释放与该留关联的所有系统资源
第一个方法逐个写入字节,后两个方法是将若干个字节以字节数组的形式一次性写入,提高写数据的效率
InputStream和OutputStream这两个类是抽象类,不能被实例化。
字节流读写文件
针对文件的读写,提供了两个类,FileInputStream和FileOutputStream
FileInputStream
FileInputStream用于读取文件中的数据
构造方法:
- FileInputStream(String name)
- FileInputStream(File file)
public class Demo { public static void main(String[] args) throws IOException{ //a.txt中的内容为ab FileInputStream fis=new FileInputStream("a.txt");//相当于在内存和硬盘之间建立一条通道 int x=fis.read();//从硬盘上读取一个字节 System.out.println(x);//97 int y=fis.read(); System.out.println(y);//98 int z=fis.read(); System.out.println(z);//-1 结束标记为-1 fis.close(); //------------------------------ FileInputStream fiss=new FileInputStream("a.txt"); int b=-1; while ((b=fiss.read())!=-1) { System.out.println(b); } fiss.close(); }}
FileOutputStream
构造方法:
- FileOutputStream(String name):如果没有这个文件,会创建一个。如果有,会先将这个文件的内容清空
- FileOutputStream(String name,boolean append):如果append的值为true,则将字节写入文件末尾,而不是先将文件的内容清空。
- FileOutputStream(File file)
- FileOutputStream(File file)
public class Demo { public static void main(String[] args) throws IOException{ FileOutputStream fos=new FileOutputStream("b.txt");//创建字节流输出对象,如果没有就自动创建一个 fos.write(97);//虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前三个8位 fos.write(98); fos.close(); FileOutputStream foss=new FileOutputStream("b.txt",true);//如果想续写就在第二个参数传true foss.write(97); foss.close(); }}
拷贝文件
新建一个文件a.txt,里边填写abc
public class Demo { public static void main(String[] args) throws IOException{ FileInputStream fis=new FileInputStream("a.txt"); FileOutputStream fos=new FileOutputStream("b.txt",true); int num1=fis.read();//从a.txt中读取一个字节,存到num1中 fos.write(num1);//向b.txt中写入一个字节,把num1中的字节写入 System.out.println((char)num1);//a int num2=fis.read(); fos.write(num2); System.out.println((char)num2);//b int num3=fis.read(); fos.write(num3); System.out.println((char)num3);//c int num4=fis.read(); System.out.println(num4);//-1 }}
上面可以简写为
public class Demo { public static void main(String[] args) throws IOException{ FileInputStream fis=new FileInputStream("a.txt"); FileOutputStream fos=new FileOutputStream("b.txt",true); int num=-1; while ((num=fis.read())!=-1) { fos.write(num); System.out.println((char)num); } }}
这样一个字节一个字节的读,一个字节一个字节的写,效率很低。就相当于我从车上往下搬饮料是一瓶一瓶的搬。
定义一个数组,把字节存入到数组中,一个数组,一个数组的读写。这就相当于一箱一箱的搬饮料。字节流一次读写一个数组的速度肯定比一次读写一个快。
public class Demo { public static void main(String[] args) throws IOException{ FileInputStream fis=new FileInputStream("a.txt"); FileOutputStream fos=new FileOutputStream("b.txt",true); byte[] arr=new byte[2];//定义一个2个字节大小的数组 while (fis.read(arr)!=-1) {//读取2个字节到arr中 fos.write(arr);//将arr中的字节写入到流中 for (byte b : arr) { System.out.println((char)b); } System.out.println("-----------------"); } }}
运行结果为
ab-----------------cb-----------------
a.txt文件中有abc三个字节,第一次读取两个字节ab,第二次的cb是什么鬼?
第一次读取了ab到数组arr中,然后接着往下读取,这时候就还剩一个c。第二次把c读取到数组arr中,覆盖了原来的a,现在数组中的数据就变为了cb。然后b.txt中的内容就变为了abcb
如何解决这个问题?
public class Demo { public static void main(String[] args) throws IOException{ FileInputStream fis=new FileInputStream("a.txt"); FileOutputStream fos=new FileOutputStream("b.txt",true); byte[] arr=new byte[2];//定义一个2个字节大小的数组 int len=-1; while ((len=fis.read(arr))!=-1) {//读取arr个字节 fos.write(arr,0,len); for (byte b : arr) { System.out.println((char)b); } System.out.println("-----------------"); } }}
运行结果为
ab-----------------cb-----------------
别的地方都一样,但这次运行完之后,b.txt中的内容为abc了。符合最终的目标。
len=fis.read(arr)
其中len记录了这次读取的字节数。
fos.write(arr,0,len);
这句话的意思是,从arr数组的0下标开始写入len个字节,而len为这次读取的字节数,这次只读取了c,所以len为1。也就是说这此只写入了c这个字符。
BufferedInputStream和BufferOutputStream
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快。Java本身设计的时候,也考虑到了这样的设计思想,提供了字节缓冲区流。
BufferedInputStream内置了一个缓冲区(数组),BufferedInputStream会一次性从文件中读取8192个,存在缓冲区中。直到缓冲区中所有的都被使用过,才重新从文件中读取8192个。
BufferedOutputStream也内置了一个缓冲区,程序向流中写出字节时,不会直接写到文件,先写到缓冲区中。直到缓冲区写满,才会把缓冲区中的数据一次性写到文件里。
bis对fis装饰了一下,功能更强大了。
先将a.txt中的东西都读到bis内置的数组中,再将数组中的字节一个一个的赋给b,b再将他的值一个一个的存到bos的内置数组中。当bos中的内置数组满了之后会自动将数据写入b.txt。
虽然步骤更加繁琐但因为操作都是在内存中完成的,所以和之前一个一个字节的读速度快(只要降低到硬盘的读写次数就会提高效率)。但和自己定义一个数组来做缓冲区相比,慢。自己定义的那个只用了一个数组,而这个用了两个数组。
public class Demo { public static void main(String[] args) throws IOException { FileInputStream fis=new FileInputStream("a.txt"); FileOutputStream fos=new FileOutputStream("b.txt"); BufferedInputStream bis=new BufferedInputStream(fis);//将fis装饰一下 BufferedOutputStream bos=new BufferedOutputStream(fos); int b=-1; while ((b=bis.read())!=-1) { bos.write(b); } }}
运行完这段代码会发现,b.txt中并没有把abc拷贝过去。
在代码末尾加一句bos.flush(),abc就都拷过去了。因为BufferedOutputStream中的内置缓冲区,是直到缓冲区写满,才会把缓冲区中的数据一次性写到文件里。这才3个字节,没有填满数组。数组中的数据不会写到b.txt中。
flush()方法可以将数组中的数据强制写入目标设备,此过程称为刷新。
而close()方法会在关闭资源之前刷新一遍(看其源码可知,在其内部调用了flush()方法)。
IO异常的处理方式
public class Demo { public static void main(String[] args){ FileInputStream fis=new FileInputStream("a.txt");//可能路径中有不存在的盘符 FileOutputStream fos=new FileOutputStream("b.txt",true);//可能路径中有不存在的盘符 byte[] arr=new byte[2]; int len=-1; while ((len=fis.read(arr))!=-1) {//可能文件不可读 fos.write(arr,0,len);//可能文件不可写 } fis.close();//可能没有正常关闭 fos.close(); }}
每句话都可能报错,之前是直接抛出去,但抛出去之后,流就关闭不了了,浪费系统资源。
jdk1.6版本之前的解决办法
public class Demo { public static void main(String[] args) throws IOException { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream("a.txt"); fos = new FileOutputStream("b.txt", true); byte[] arr = new byte[2]; int len=-1; while ((len = fis.read(arr)) != -1) { fos.write(arr, 0, len); } } finally { try { if (fis != null) fis.close(); } finally { //try finally的嵌套的目的是能关一个尽量关一个 if (fos != null) fos.close(); } } }}
jdk1.7版本处理异常
public class Demo { public static void main(String[] args) throws IOException { try ( FileInputStream fis = new FileInputStream("a.txt"); FileOutputStream fos = new FileOutputStream("b.txt", true); ) { byte[] arr = new byte[2]; int len=-1; while ((len = fis.read(arr)) != -1) { fos.write(arr, 0, len); } } }}
当写在try的小括号里,在执行完大括号里边的内容后,会自动调用其close方法。
字符流
当用字节流读取中文的时候,很可能读到半个中文,造成乱码。字节流写出中文的时候,字节流直接操作的是字节,写出中文必须将字符串转换成字节数组。
Reader和Writer是字符流的顶级父类
FileReader
FileReader可以从关联的文件中读取一个或一组字符
通过编码表来一次能够获取一个字符。按照字符的大小读取,不会出现半个中文。
FileWriter
字符流的拷贝
在a.txt中填写字符大家好
public class Demo { public static void main(String[] args) throws IOException { FileReader fr=new FileReader("a.txt"); FileWriter fw=new FileWriter("b.txt"); int c=-1; while((c=fr.read())!=-1){ fw.write(c); } }}
运行代码,a.txt中的内容并没有拷贝到,b.txt。而在末尾添加了fw.flush()后,就可以拷贝过去了。
因为在其内部自己定义了一个1024大小的char数组来做缓冲区。2048个字节,相当于2k。
什么时候用字符流?
字符流可以拷贝纯文本文件(不可以拷贝非纯文本文件,比如传个图片,上面的编码在码表上查不到),但不推荐使用,因为读取时会把字节转换为字符,写出时还要把字符转换会字节。
在只读或只写的时候可以用字符流。
BufferedReader和BufferedWriter
BufferedReader和BufferedWriter内置一个16k的缓冲区。其中有方法可以读一行
- readLine()
- newLine():写出回车换行符
public class Demo { public static void main(String[] args) throws IOException { BufferedReader br=new BufferedReader(new FileReader("a.txt")); BufferedWriter bw=new BufferedWriter(new FileWriter("b.txt")); String line; while((line=br.readLine())!=null){ bw.write(line); bw.newLine();//写出回车换行符 //bw.write("\r\n");也可以回车换行,但只在windows系统有效。Linux的是\n。Mac的是\r } br.close(); bw.close(); }}
使用指定的编码表读写字符
项目–>右键–>Properties–>Resource–>Text flie encoding里边默认的为GBK
FileReader是使用默认码表读取文件,如果需要使用指定码表读取,可以使用InputStreamReader(字节流,编码表)
FileWriter是使用默认码表写出文件,如果需要使用指定码表写出,可以使用InputStreamWriter(字节流,编码表)
public class Demo { public static void main(String[] args) throws IOException { InputStreamReader isr=new InputStreamReader(new FileInputStream("a.txt"),"utf-8"); OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("b.txt"),"utf-8"); int c=-1; while ((c=isr.read())!=-1) { osw.write(c); } isr.close(); osw.close(); }}
- 【IO流】IO框架
- IO流呀IO流
- 字符IO&数据流IO&对象流IO
- io流
- io流
- IO流
- IO流
- IO 流
- IO流
- io流
- IO流
- io流
- IO流
- IO流
- IO流
- IO流
- IO流
- IO流
- Linux系统间文件双向同步搭建Unison版
- 最小生成树-Prim算法和Kruskal算法
- 生产环境实战spark (5)分布式集群 5台设备之间hosts文件配置 ssh免密码登录
- 用构造方法求矩形的面积
- CentOS安装Git,并上传、下载
- IO流
- 线程安全性的文档化
- android java进程管理(三)之apk进程的启动
- pstorage
- C# 中的委托和事件
- 使用Tessnet2_32.dll报未能加载文件或程序集或它的某一个依赖项。试图加载格式不正确的程序解决方法
- 【转】CSDN-markdown编辑器语法——字体、字号与颜色
- GPU Memory exhausted, but no process listed by nvidia-smi
- socket编程之 select、poll、kqueue、epoll