黑马程序员----二十-IO流一

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

今天学习IO流.

一.IO流
1.概念
a.IO流用来处理设备之间的数据传输
b.java对数据的操作是通过流的方式
c.java用于操作流的类都在IO包中
d.流按流向分为两种:输入流和输出流
e.流按操作类型分为两种:
 1.字节流:可以操作任何数据
 2.字符流:只能操作纯字符数据,方便

2.IO流常用父类
a.字节流的抽象父类:
 InputStream
 OutputStream
b.字符流的抽象父类
 Reader
 Writer

3.IO程序书写
a.使用前,导入IO包中的类
b.使用时,进行IO异常处理
 为什么要进行异常处理,因为操作很有可能不存在.
c.使用后,释放资源
 在内存和硬盘之间开启一个管道,使用完之后要关闭.

二.FileInputStream
1.因为InputStream是抽象类,所以只能操作子类对象FileInputStream.

2.方法
a.read()
FileInputStream fis=new FileInputStream("xxx.txt");
这是读当前路径下的xxx.txt文件,但是如果当前路径下没有,会出现异常,所以要抛出FileNotFountException.
int x=fis.read();
有可能文件是不可读的,所以要抛出IOException.
sysout(x);
fis.close();
整个过程就是从硬盘上开启一个管道,从硬盘上读取一个字节,然后关闭管道,释放资源.
ascii码表在任何码表里面,因为所有码表都要字母数字等.数字也是有编码的,0是48,1是49,9是57,都是一个字节.
每一次read()都读取一个字节.如果读完了再读,就是-1.
有了-1这个标记,就知道了何时结束,也就是循环结束的条件.

3.读取的标准格式
int i=0;
while((i=fis.read()) != -1){
 sysout(i);
}
fis.close();

三.read方法为什么返回int
1.int是4个字节,而byte是1个字节,为什么用int来接收而不直接用byte来接收呢?
a.因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111
b.那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上
c.24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型
d.byte类型8个二进制位,-1的原码是10000001,-1的反码是11111110,-1的补码是11111111.
e.int是4个字节,但是读是读1个字节,所以前面永远有3个字节也就是24位的0.

四.FileOutputStream
1.write()方法也是一次一个字节.写的时候会去掉前面3个字节.
2.写的时候没有文件就没关系了.

五.FileOutputStream的追加
再创建了一次,是清空了内容再写呢,还是把文件删了再创建一个.
看了下创建时间和修改时间,就发现其实是清空了内容再写入.
如果new FileOutputStream("a.txt",true);
那么就是追加.

六.拷贝图片
FileInputStream fis=new FileInputStream("aaa.jpg");
FileOutputStream fos=new FileOutputStream("copy.jpg");
int i;
while((i=fis.read() !=-1){
 fos.write(i);
}
fis.close();
fos.close();
基本上IO流就围绕这这些核心代码.
拷大文件的时候特别慢,因为是读一个字节,写一个字节.

八.字节数组拷贝之available方法
1.available()
可以获取到读取的那个文件的所有字节数.
2.read(byte[] b)
byte[] b=new byte[fis.available()];
fis.read(b);
直接把所有字节放到字节数组里,再直接读取整个字节数组.
write(b);
然后直接写入整个字节数组.

2.这种方式可以拷贝,但是在开发中不推荐,因为JVM的内存也只有170MB左右.第一种方式效率低.

九.定义小数组
1.byte[] arr=new byte[2];
读取"abc",第一次是97,98,,,第二次是99,98,为什么呢?
因为第二次读取的时候,第一个位置覆盖了,第二个位置没有覆盖.

2.int len;
len=fis.read(arr);
第一次读取是2,第二次读取是1,第三次就是-1.
但是abc拷贝过来果然是abcb,怎么办?
write方法解决
write方法里正好有write(byte[] b,int off,int len),off就是数组中的索引,len就是长度.
fos.write(arr),每次读进来多少,就写多少,第一次读进来是2,就写2,第二次读进来是1,就写1.

十.定义小数组的
1.一般字节数组的长度定义成1024的整数倍,因为计算机进制就是1024.所以可以是
byte[] arr=new byte[1024 * 8];

2.文件里abc,如果fis.read()里面忘记写arr了,那就只读了一个字节,但是写是写了97个空字节,第二次98,第三次99,所以写了294个空字节.

3.标准格式
FileInputStream fis=new FileInputStream("a1.txt");
FileOutputStream fos=new FileOutputStream("a1copy.txt");
byte[] arr=new byte[1024 * 8];
int len;
while( (len=fis.read(arr)) != -1){
 fos.write(arr,0,len);
}
fis.close();
fos.close();

4.1024*8 1024就是1024个字节,就是1KB,*8就是 8KB.
1bit表示1位,1B就是8bit,8位.

十一.BufferedInputStream和BufferedOutputStream
1.FileInputStream fis=new FileInputStream("a1.txt");
FileOutputStream fos=new FileOutputStream("a1copy.txt");
BufferedInputStream bis=new BufferedInputStream(fis);
BufferedOutputStream bos=new BufferedOutputStream(fos);
创建缓冲区对象,对输入输出流进行包装让其变得更加强大.
int b;
while(   (b=bis.read())  != -1){
 bos.write(b);
}
bis.close();
bos.close();
直接关bis和bos.

2.Buffered的输入和输出都会新建一个byte数组,大小为8192,因为Buffered的两个都是在内存里的,内存里的运算效率比硬盘要高的多,所以只要降低硬盘的读写次数就能提高效率.

3.小数组和Buffered哪个更快
小数组如果是8192个字节大小,那么比Buffered略胜一筹,因为读和写是操作同一个数组,而Buffered是操作两个数组.

十二.flush和close方法的区别
1.flush方法
用来刷新缓冲区,刷新后可以再次写出
2.close方法
用来关闭流释放资源.

3.为什么没关的时候copy文件小了一点,因为close方法具备刷新的功能,在关闭流之前会先刷新一次缓冲区,将缓冲区的字节全都刷新到文件上,再关闭.因为写的时候最后8192没有满,close的时候就把这些剩余的刷出来.
如果不关闭,flush一下也可以.

十三.字节流读写中文
1.字节流读取中文的问题
字节流在读中文的时候有可能会读到半个中文,造成乱码
2.字节流写出中文的问题
字节流直接操作字节,所以写出中文必须将字符串转换成字节数组.
写出回车换行write("\r\n".getBytes());

十四.流的标准处理异常代码1.6版本
1.一共六行异常
 读.文件可能不存在
 写.路径可能不存在
 read可能不可读
 write可能不可写
 fis可能关不掉
 fos可能关不掉
抛出throws IOException是不行的,因为有可能文件不存在或者路径不存在,那么输入或输出流的开启就出现异常,那么后面的close就没有执行,那么流就没有关闭.所以必须在finally里写close.把其他的都放在try里.但是
FileInputStream fis=null;
FileOutputStream fos=null;
要放在外面.
因为定义放里面的话,和finally中的语句都不在一个结构里.

2.必须进行初始化,因为如果新建失败了,那么执行close的时候就相当于调用一个没有被赋值的对象.

3.finally{
 try{
  if(fis != null)
  fis.close();
 }finally{
  if(fos != null)
  fos.close();
 }
}
try finally的嵌套目的是能关一个尽量关一个

十五.流的标准处理异常代码1.7版本
try(
 FIS fis=new FIS("a1.txt");
 FOS fos=new FOS("copy.txt");
){
 int b;
 while( (b=fis.read()) != -1){
  fos.write(b);}
}
1.7有自动关闭功能.
如果自己写一个MyClose,有close()方法,但是不能写在try的()里,因为没有不能自动关闭.
可以implements AutoCloseable,就会自动调用close()方法.

十六.图片加密
如果每次写一个字节,就异或(^)一个数,这样打开的时候就显示文件损坏,下次只要再异或一次就相当于解密了,第一次复制是加密,第二次复制是解密.异或的那个数就是密码

十七.拷贝文件
需求:在控制台录入一个文件的路径,将文件拷贝到当前项目下.
分析:
1.创建键盘录入对象
2.定义方法对键盘录入的路径进行判断,如果是文件就返回
3.在主方法中接收该文件
4.读和写该文件

定义一个方法获取键盘录入的文件路径,并封装成File对象返回
1.返回值类型File
2.参数列表无

getFile():
Scanner sc=new Scanner(System.in);
sysout("请输入文件路径");
while(true){
 String line=sc.nextLine();
 File file=new File(line);
 if(!file.exists()){
 sysout("文件路径不存在,重录:");
 }else if(file.isDirectory()){
 sysout("这是文件夹路径,重录:");
 }else{
 return file;
 }
}

main:
File file=getFile();
BIS bis=new BIS(new FIS(file));
BOS bos=new BOS(new BOS(file.getName());
int b;
while( (b=bis.read()) != -1){
 bos.write(b);
}
bis.close();
bos.close();

十八.录入数据拷贝到文件.
需求:将键盘录入的数据拷贝到当前项目下的text.txt文件中,键盘录入数据当遇到quit时就退出.
分析:
1.创建键盘录入对象.
2.创建输出流对象,关联text.txt文件
3.定义无限循环.
4.遇到quit退出循环
5.如果不quit,就将内容写出
6.关闭流

Scanner sc=new Scanner(System.in);
FileOutputStream fos=new FileOutputStream("text.txt");
while(true){
String line=sc.nextLine();
if("quit".equals(line)){
 break;
}
fos.write(line.getBytes());
fos.write("\r\n".getBytes());
}
fos.close();

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值