day20-Java IO流一(基本/拷贝文件)

20.01_IO流概述及其分类

  • IO流用来处理设备之间的数据传输

  • Java对数据的操作是通过流的方式

  • Java用于操作流的类都在IO包中

  • 流按流向分为两种:输入流输出流

  • 流按操作类型分为两种:

    • 字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
    • 字符流 : 字符流只能操作纯字符数据,比较方便。
  • 字节流的抽象父类:

    • InputStream 字节输入流所有类的超类
    • OutputStream 字节输出流所有类的超类
  • 字符流的抽象父类:

    • ReaderWriter
  • 3.IO程序书写

    • 使用前,导入IO包中的类
    • 使用时,进行IO异常处理
    • 使用后,释放资源

20.02_IO流(FileInputStream)

FileInputStream input = new FileInputStream("xxoo.txt");  //可能抛出FileNotFoundException
int x ;
while( (x = input.read()) != -1){ //从文件中读取一个字节(一个字符的二进制数值)
    System.out.println(x);
}
input.close();  //关闭释放资源

20.03_read()方法返回值为什么是int,而不是byte?

因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型

read()方法返回值为什么是int.png

20.04_IO流(FileOutputStream)

// FileOutputStream 创建的时候(下面这个构造方法),如果文件不存在,会自动创建,如果文件存在,就会清空文件。
FileOutputStream ouput = new FileOutputStream("xxoo.txt");  

ouput.write(97); //虽然写出的是一个int数,但是在写出的时候会将前面的24个0去掉,所以写出的一个byte
ouput.write(98); //一次write()操作会覆盖原来文件的内容

ouput.close();

20.05_IO流(FileOutputStream追加)

// 使用此构造方法,代表每次写文件 都是追加 文件内容末尾
FileOutputStream fop = new FileOutputStream("xxoo.txt", true);
fop.write(100); 
fop.close();

20.06_IO流(拷贝图片)

FileInputStream fis = new FileInputStream("xxoo.png");    //读文件
FileOutputStream fos = new FileOutputStream("copy.png");  //写文件

int b ;
while( (b = fis.read()) != -1 ) {
    fos.write(b);;
}

fis.close();
fos.close();

20.07_IO流(拷贝大文件问题)

  • 当读写一个大文件时,比如一个普通MP3文件,4Mb左右,就有4百多万个字节,而字节流一次只读写一个字节,那么拷贝一个MP3就需要读写将近9百多万次,效率将会十分低下。

20.08_IO流(字节数组拷贝之available()方法)

  • int read(byte[] b) :一次读取一个字节数组
  • write(byte[] b) :一次写出一个字节数组
  • available() 获取读的文件所有的字节个数
  • 弊端:有可能会内存溢出
FileInputStream input = new FileInputStream("xxoo.png");
FileOutputStream output = new FileOutputStream("copy.png");  //写文件

byte[] data = new byte[input.available()]; //根据文件大小做一个字节数组
input.read(arr);  //将文件上的所有字节读取到数组中
output.write(data); //将数组中的所有字节一次写到了文件上

input.close();
output.close();

20.10_IO流(定义小数组的标准格式)

FileInputStream fis = new FileInputStream("xxoo.png"); 
FileOutputStream fos = new FileOutputStream("copy.png");

byte[] data = new byte[1024 * 10];  //代表 10Kb

int len ;
while( (len = fis.read(data)) != -1){
    fos.write(data, 0, len);
}
fos.close();
fis.close();

// write(byte[] b, int off, int len) 从byte数组 的off读,读取len个长度的有效内容

20.11_BufferedInputStream和BufferOutputStream拷贝

  • A: 缓冲思想

    • 字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,
    • 这是加入了数组这样的缓冲区效果,java本身在设计的时候,
    • 也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流
  • B. BufferedInputStream

    • BufferedInputStream内置了一个缓冲区(数组)
    • BufferedInputStream中读取一个字节时
    • BufferedInputStream会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个
    • 程序再次读取时, 就不用找文件了, 直接从缓冲区中获取
    • 直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个
  • C. BufferedOutputStream

    • BufferedOutputStream也内置了一个缓冲区(数组)
    • 程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中
    • 直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里
  • D. 小数组的读写和带Buffered的读取哪个更快?

    • 定义小数组如果是8192个字节大小和Buffered比较的话
    • 定义小数组会略胜一筹,因为读和写操作的是同一个数组
    • Buffered操作的是两个数组
FileInputStream fis = new FileInputStream("xxoo.png");  //创建输入流对象
FileOutputStream fos = new FileOutputStream("copy.png"); //创建输出流对象
// 这上下四句,可以使用匿名对象写成2句
BufferedInputStream bis = new BufferedInputStream(fis); //创建缓冲区对象,对输入流进行包装
BufferedOutputStream bos = new BufferedOutputStream(fos); //创建缓冲区对象,对输出流进行包装

int data ;
while( (data = bis.read()) != -1 ) {
    bos.write(data);
}
bis.close();  // 这里只需要对 缓冲对象 关闭即可,不用再去关闭 输入出流
bos.close();

20.12_IO流(flush和close方法的区别)

  • flush()方法
    • 用来刷新缓冲区的,刷新后可以再次写出
  • close()方法
    • 用来关闭流释放资源的的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再写出

20.13_IO流(字节流读写中文)

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

20.14_IO流(流的标准处理异常代码1.6版本及其以前)

  • try finally嵌套
    以下代码了解即可,可能老项目有类似代码,现在最新eclipse(4.6.2)写如下代码依旧提示异常没有处理错误的。
FileInputStream fis = null;
FileOutputStream fos = null;
try {
    fis = new FileInputStream("aaa.txt");
    fos = new FileOutputStream("bbb.txt");
    int b;
    while((b = fis.read()) != -1) {
        fos.write(b);
    }
} finally {
    try {
        if(fis != null)
            fis.close();
    }finally {
        if(fos != null)
            fos.close();
    }
}

20.15_IO流(流的标准处理异常代码1.7版本)

// 因为 InputStream 实现了 AutoCloseable接口,所以会自动关闭
// 而 tyr(){} 会自动关闭 ()里面的对象,反之,()里面的对象必须实现了 AutoCloseable接口
try(
  FileInputStream in = new FileInputStream("xxoo.txt");
  FileOutputStream out = new FileOutputStream("xxoo.txt");
){
  int data ;
  while( (data = in.read()) != -1) {
    out.write(data);
  }
}

在try()中创建的流对象必须实现了AutoCloseable这个接口,
如果实现了,在try后面的{}(读写代码)执行后就会自动调用,流对象的close方法将流关掉 

20.16_IO流(图片加密)

// 图片加密,关键: 整数被异或两次就是整数本身
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("xo.png"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("t.png"));

int len ;
while( (len = bis.read()) != -1) {
  bos.write(len ^ 10);   //为什么这里 使用  ^ ? 因为一个整数被 ^ 两次,就是原来的整数
}

bis.close();
bos.close();

20.17_IO流(拷贝文件)

  • 在控制台录入文件的路径,将文件拷贝到当前项目下
Scanner sc = new Scanner(System.in);
System.out.println("请输入文件的绝对路径: ");
String path = sc.nextLine();
sc.close();

File file = new File(path);
if (!file.exists() || !file.isFile()) {
  System.out.println("路径不存在,或者路径指向的不是一个文件!");
  return;
}
System.out.println("拷贝中...");

FileInputStream in = new FileInputStream(file);   //也可以使用 BufferedInputStream
FileOutputStream out = new FileOutputStream(file.getName());

byte[] data = new byte[1024 * 10];  // 自定义缓冲大学,10Kb 
int len ;
while( (len = in.read(data)) != -1) {
  out.write(data, 0, len);
} 
in.close();
out.close();
System.out.println("拷贝成功...");

20.18_IO流(录入数据拷贝到文件)

  • 将键盘录入的数据拷贝到当前项目下的text.txt文件中,键盘录入数据当遇到quit时就退出
Scanner sc = new Scanner(System.in);
FileOutputStream out = new FileOutputStream("text.txt"); 
System.out.println("请输入文件内容: ");

while(true) {
    String text = sc.nextLine();
    if("quit".equals(text)) break ;
    
    out.write(text.getBytes());
    out.write("\r\n".getBytes());
}
System.out.println("程序结束...");
sc.close();
out.close();

END。
我是小侯爷。
在魔都艰苦奋斗,白天是上班族,晚上是知识服务工作者。
如果读完觉得有收获的话,记得关注和点赞哦。
非要打赏的话,我也是不会拒绝的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容