IO流·字节流

IO流概述及其分类

* A:概念
  * IO流用来处理设备之间的数据传输
  * Java对数据的操作是通过流操作的
  * Java用于操作流的类都在IO包中
  * 流按流向分为两种输入流、输出流
  * 流按操作类型分为两种
    * 字节流:字节流可以操作任何数据,因为再计算机中任何数据都是以字节的形式存储的
    * 字符流:字符流只能操作纯字符数据,比较方便

* B:IO流常用父类
  * 字节流的抽象父类
    * InputStream
    * OutputStream
  * 字符流的抽象父类
    * Reader
    * Writer

* C:IO程序书写
  * 使用前,导入IO包中的类
  * 使用时:进行IO异常处理
  * 使用后:释放资源

FileInputStream

* read() 一次读取一个字节

package com.heima.stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; public class Demo1_FileInputStream { public static void main(String[] args) throws IOException {
// demo1();
// demo2(); } public static void demo2() throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream("xxx.txt");
int b;
while ((b = fis.read()) != -1) { // 判断文件是否读到末尾
System.out.print(Character.toChars(b));
}
fis.close(); // 关流
} public static void demo1() throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream("xxx.txt"); // 创建流对象,传入文件名或File对象
int x = fis.read(); // 从输入流中读取一个字节
System.out.println(x); int y = fis.read(); // 每read一次,指针就会向后移动一个单位
System.out.println(y); int z = fis.read();
System.out.println(z); int a = fis.read(); // 文件的结束标记是-1字节,-1不是有效字节
System.out.println(a); fis.close(); // 关闭流,释放资源
}
}

FileInputStream

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

* read() 方法读取的是一个字节,为什么返回的是int,而不是byte?

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

FileOutputStream

* write() 一次写出一个字节
* FileoutputStream的构造方法实现数据追加

package com.heima.stream;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; public class Demo2_FileOutputStream {
// FileOutputStream在创建对象的时候如果 没有这个文件会帮我们创建出来 如果有这个文件,会先将这个文件清空
public static void main(String[] args) throws IOException {
// demo1();
// demo2();
} public static void demo2() throws FileNotFoundException, IOException {
FileOutputStream fos = new FileOutputStream("yyy.txt", true); // 如果想续写,就在第二个参数传入true
fos.write(97);
fos.write(97);
fos.write(97); fos.close();
} public static void demo1() throws FileNotFoundException, IOException {
FileOutputStream fos = new FileOutputStream("yyy.txt"); // 创建字节输出流对象,如果没有该文件,就自动创建一个
fos.write(97); // 虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前3个8位
fos.write(98);
fos.write(99); fos.close(); // 关流
}
}

FileOutputStream

拷贝文件

* FileInputStream读取
* FileOutputStream写出

package com.heima.stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; public class Demo3_Copy { public static void main(String[] args) throws IOException {
// demo1();
// demo2();
// demo3();
} public static void demo3() throws FileNotFoundException, IOException {
// 第二种拷贝方法,但是开发中不推荐,因为容易导致内存溢出
FileInputStream fis = new FileInputStream("亲爱的小孩.mp3");
FileOutputStream fos = new FileOutputStream("copy2.mp3");
int len = fis.available(); byte[] arr = new byte[len]; // 创建与文件一样大小的字节数组
fis.read(arr); // 将文件上的字节读取到内存中
fos.write(arr); // 将字节数组写入到文件上 fis.close();
fos.close();
} public static void demo2() throws FileNotFoundException, IOException {
// 第一种拷贝方式,不推荐,效率太低
FileInputStream fis = new FileInputStream("亲爱的小孩.mp3"); // 创建输入流对象
FileOutputStream fos = new FileOutputStream("copy.mp3"); // 创建输出流对象
int b;
while ((b = fis.read()) != -1) { // 逐个字节拷贝,效率较低
fos.write(b);
}
fis.close();
fos.close();
} public static void demo1() throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream("19051435 赵文彬 (2).jpg"); // 创建输入流对象
FileOutputStream fos = new FileOutputStream("copy.jpg"); // 创建输出流对象 int b;
int count = 0;
while ((b = fis.read()) != -1) { // 在不断的读取每一个字节
fos.write(b); // 将每一个字节写出
count++; // 记录字节数
}
fis.close(); // 关流,释放资源
fos.close();
System.out.println(count / 1024); // 照片为196KB大小
}
}

Copy

定义小数组的标准格式

* 案例演示
  * 字节流一次读写一个字节数组复制图片和视频

package com.heima.stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; public class Demo4_ArrayCopy {
// 第三种拷贝方式: 定义小数组
public static void main(String[] args) throws IOException {
// demo1();
// demo2();
// demo3();
} public static void demo3() throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream("亲爱的小孩.mp3");
FileOutputStream fos = new FileOutputStream("亲爱的小孩1.mp3"); byte[] arr = new byte[1024 * 8]; // 一般把数组的大小设置为1024的整数倍
int len;
while ((len = fis.read(arr)) != -1) { // 如果忘记加arr,返回的就不是读取的字节个数,而是字节的码表值
fos.write(arr, 0, len);
} fis.close();
fos.close();
} public static void demo2() throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream("xxx.txt"); // 创建字节输入流
FileOutputStream fos = new FileOutputStream("yyy.txt"); // 创建字节输出流 byte[] arr = new byte[2];
int len; // 记录有效的字节个数
while ((len = fis.read(arr)) != -1) {
// fos.write(arr);
fos.write(arr, 0, len); // 保证写入的是abc,而不是abcb
}
fis.close(); // 关流
fos.close();
} public static void demo1() throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream("xxx.txt");
byte[] arr = new byte[2];
int a = fis.read(arr); // 将文件上的字节读取到字节数组中 System.out.println(a); // 读到的有效的字节个数
for (byte b : arr) { // 第一次获取到文件上的a和b
System.out.println(b);
}
System.out.println("--------------");
int c = fis.read(arr); // 返回读取的字节数
System.out.println(c);
for (byte b : arr) { // 读取到了c和b
System.out.println(b);
}
fis.close(); // 关流
}
}

Copy

BufferedInputStream 和 BufferedOutputStream 拷贝

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

* B:BufferedInputStream
  * BufferedInputStream内置了一个缓冲区(数组)
  * 从BufferedInputStream中读取一个字节时,它会一次性从文件读取8192个,存储在缓冲区中,返回给程序一个
  * 程序再次读取时,就不用再找文件了,直接从缓冲区中获取即可
  * 知道缓冲区中所有的都被使用过后,才会重新从文件中国读取8192个

* C:BufferedOutputSteam
  * BufferedOutputStream也内置了一个缓冲区(数组)
  * 程序向流中写出字节时,不会直接写到文件中,而是先写到缓冲区内
  * 当缓冲区写满后,BufferedOutputStream才会把缓冲区中的数据一次性写到文件里

* D:案例演示

package com.heima.stream;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; public class Demo5_BufferedCopy { public static void main(String[] args) throws IOException {
// demo1();
// demo2(); } public static void demo2() throws FileNotFoundException, IOException {
/*flush和close的方法的区别:
* close方法:具备刷新功能,在关闭流之前,就会刷新一次缓冲区,
* 将缓冲区的字节全都刷新到文件上,再关闭
* flush方法:flush刷新完后还能写,但是close刷新后就不能再写了
*/ BufferedInputStream bis = new BufferedInputStream(new FileInputStream("亲爱的小孩.mp3"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("亲爱的小孩5")); int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
bos.flush(); bos.close();
bis.close();
} public static void demo1() throws FileNotFoundException, IOException {
// 美女素颜状态
FileInputStream fis = new FileInputStream("亲爱的小孩.mp3"); // 创建输入流对象,关联文件
FileOutputStream fos = new FileOutputStream("亲爱的小孩2.mp3"); // 创建输出流对象
// 美女化妆状态
BufferedInputStream bis = new BufferedInputStream(fis); // 创建缓冲区对象,对输入流进行包装
BufferedOutputStream bos = new BufferedOutputStream(fos); // 对输出流进行包装 int b;
while ((b = bis.read()) != -1) {
bos.write(b);
} bis.close(); // 只需要关闭包装后的就行了
bos.close();
}
}

BufferedInputStream

* E:小数组的读写和带Buffered的读取哪个更快
  * 定义小数组如果是8192个字节大小的个Buffered进行比较的话
  * 定义小数组的会略胜一筹,因为读和写操作的都是同一个数组
  * 而Buffered操作的是两个数组

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

字节流读写中文

* 字节流读取中文的问题
  * 字节流在读中文的时候可能会读到半个中文,造成乱码

* 字节流写出中文的问题
  * 字节流直接操作字节,所以写出中文必须将字符串转换成字节数组
  * 写出回车换行 write("\r\n".getBytes())

package com.heima.stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; public class Demo6_Chinese { public static void main(String[] args) throws IOException {
// demo1();
// demo2();
} public static void demo2() throws FileNotFoundException, IOException {
// 字节流写入中文需要将字符串转成字节数组
FileOutputStream fos = new FileOutputStream("zzz.txt");
fos.write("我读书少,你别骗我".getBytes()); // 要转换成字节数组写入
fos.write("\r\n".getBytes()); // 换行符也需要转换成字节数组
fos.write("我读书少,你别骗我".getBytes());
fos.close();
} public static void demo1() throws FileNotFoundException, IOException {
// 字节流读取中文可能会导致乱码,和码表有关
FileInputStream fis = new FileInputStream("yyy.txt");
byte[] arr = new byte[6];
int len;
while ((len = fis.read(arr)) != -1) {
System.out.println(new String(arr, 0, len)); // 调用字符串的构造方法
}
}
}

FileInputStream

流的标准处理异常代码

* 1.5 版本 try...finally 嵌套

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

package com.heima.stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; public class Demo7_TryFinally { public static void main(String[] args) throws IOException {
// demo1();
// demo2();
} public static void demo2() throws IOException, FileNotFoundException {
try (FileInputStream fis = new FileInputStream("xxx.txt");
FileOutputStream fos = new FileOutputStream("yyy.txt");
MyClose mc = new MyClose();) // 里面只能写具有自动关闭的功能的东西
{
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
} // 大括号执行完之后,会自动关闭小括号内的内容
}
} public static void demo1() throws FileNotFoundException, IOException {
// 随意的抛出异常是不负责任的,一旦出现异常,流很有可能不会被关闭
FileInputStream fis = null;
FileOutputStream fos = null; try {
fis = new FileInputStream("xxx.txt");
fos = new FileOutputStream("yyy.txt"); int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
} finally {
try {
if (fis != null) {
fis.close();
}
} finally { // try - finally 的嵌套的目的是尽可能多的关闭文件句柄
if (fos != null) {
fos.close();
}
}
}
}
} class MyClose implements AutoCloseable {
public void close() {
System.out.println("我关了");
}
}

try...finally

图片加密

* 给图片加密

package com.heima.test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; public class Test1 {
// 将写出的字节异或上一个数,这个数就是密钥,解密的时候再次异或密钥即可
public static void main(String[] args) throws IOException {
// demo1(); // 加密
// demo2(); // 解密 }
public static void demo2() throws FileNotFoundException, IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("copy.jpg")); // 创建字节输入缓冲流,关联字节输入流对象
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy1.jpg")); // 创建字节输出缓冲流,关联字节输出流对象 int b;
while ((b = bis.read())!= -1) {
bos.write(b ^ 123); // 再次异或,打回原形
} bis.close(); // 关流
bos.close();
} public static void demo1() throws FileNotFoundException, IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("19051435 赵文彬 (2).jpg")); // 创建字节输入缓冲流,关联字节输入流对象
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg")); // 创建字节输出缓冲流,关联字节输出流对象 int b;
while ((b = bis.read())!= -1) {
bos.write(b ^ 123); // 对每个字节进行异或处理
}
bis.close(); // 关流
bos.close();
}
}

Test1

拷贝文件

* 在控制台录入文件的路径,将文件拷贝到当前项目下

package com.heima.test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner; public class Test2 {
/*
* 分析:
* 1、创建键盘录入对象
* 2、定义方法对键盘录入的路径进行一系列的判断,如果是文件,就返回
* 3、在主方法中接收该文件
* 4、进行读写操作
* 5、关流
*/
public static void main(String[] args) throws IOException {
File file = getFile(); // 获取文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); // 创建字符输入缓冲流对象,关联字符输入对象
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file.getName())); // 创建字符输出缓冲流流对象,关联字符输出流对象,文件对象和读取的文件同名 int b;
while ((b = bis.read()) != -1) { // 读取原文件中的数据
bos.write(b); // 写到新文件中
}
System.out.println("文件拷贝成功"); bis.close(); // 关流
bos.close();
}
/*
* 定义一个方法,获取键盘录入的文件路径,并封装成file对象返回
* 1、返回值类型是file
* 2、无参数列表
*/
public static File getFile() {
Scanner sc = new Scanner(System.in); // 创建键盘录入对象
System.out.println("请输入一个文件的路径");
while (true) {
String line = sc.nextLine(); // 接收键盘录入的路径
File file = new File(line); // 封装成File对象,并对其进行判断
if (!file.exists()) {
System.out.println("您录入的文件的路径不存在,请重新录入");
} else if (file.isDirectory()) {
System.out.println("您录入的是文件夹路径,请重新录入");
} else {
sc.close();
return file; // 返回文件
}
} } }

Test2

录入数据拷贝到文件

* 将键盘录入的数据拷贝到当前项目下的text.txt 文档中,录入遇到 quit时退出

package com.heima.test;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner; public class Test3 {
/*
* 分析:
* 1、创建键盘录入对象
* 2、创建输出流对象,关联text.txt
* 3、定义无限循环,遇到quit就退出循环,
* 4、如果不是quit,就将内容录入
* 5、关闭流
*/
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in); // 创建键盘录入对象
FileOutputStream fos = new FileOutputStream("test.txt"); // 创建字节输入流关联text.txt文件 System.out.println("请输入数据"); // 提示输入
while (true) { // 定义无限循环
String line = sc.next(); // 录入数据 if ("quit".equals(line)) { // 判断录入的内容是否位quit
break; // 退出循环
} else {
fos.write(line.getBytes()); // 将字符串转换成字节数组并写到文件中
fos.write("\r\n".getBytes()); // 写入换行符
}
}
fos.close(); // 关流
}
}

Test3

Java I/O流 02的更多相关文章

  1. Java IO: 字符流的Piped和CharArray

    作者: Jakob Jenkov 译者: 李璟(jlee381344197@gmail.com) 本章节将简要介绍管道与字符数组相关的reader和writer,主要涉及PipedReader.Pip ...

  2. Java的IO流以及输入流与输出流的异同

    一:流的基本概念:           Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列.J ...

  3. day35-IO流02

    JavaOI流02 4.常用的类 4.1文件字节流输入流-FileInputStream InputStream抽象类是所有类字节输入流的超类 InputStream常用的子类: FileInputS ...

  4. 【转】输入/输出流 - 深入理解Java中的流 (Stream)

    基于流的数据读写,太抽象了,什么叫基于流,什么是流?Hadoop是Java语言写的,所以想理解好Hadoop的Streaming Data Access,还得从Java流机制入手.流机制也是JAVA及 ...

  5. Java虚拟机JVM学习02 类的加载概述

    Java虚拟机JVM学习02 类的加载概述 类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对 ...

  6. 理解Java中字符流与字节流的区别

    1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个“流动的方向”,通常可以从中读入一个字节序 ...

  7. Java Io 字符流

    Java Io 字符流包含: 1. InputStreamReader  它是由byte流解析为char流,并且按照给定的编码解析. 2. OutputStreamWrite  它是char流到byt ...

  8. mybatis oracle java.sql.SQLException: 流已被关闭问题

    /** * 按照页码取值(从current_page页开始,每页page_size条) * @param key * @param params * @param current_page * @pa ...

  9. Java IO包装流如何关闭?

      问题: (1)JAVA的IO流使用了装饰模式,关闭最外面的流的时候会自动调用被包装的流的close()方吗? (2)如果按顺序关闭流,是从内层流到外层流关闭还是从外层到内存关闭? 问题(1)解释: ...

随机推荐

  1. 2018-2019 ACM-ICPC, Asia Dhaka Regional Contest C.Divisors of the Divisors of An Integer (数论)

    题意:求\(n!\)的每个因子的因子数. 题解:我们可以对\(n!\)进行质因数分解,这里可以直接用推论快速求出:https://5ab-juruo.blog.luogu.org/solution-p ...

  2. poj 2566 Bound Found 尺取法

    一.首先介绍一下什么叫尺取 过程大致分为四步: 1.初始化左右端点,即先找到一个满足条件的序列. 2.在满足条件的基础上不断扩大右端点. 3.如果第二步无法满足条件则到第四步,否则更新结果. 4.扩大 ...

  3. Python基础--核心数据类型

    python的核心数据类型: Number 数字(整数,浮点数,复数,布尔型数) String 字符串 List 列表 Tuple 元组 Dictionary 字典 Set 集合 1. 整数(整型数) ...

  4. LEETCODE - 【1271】十六进制魔术数字

    class Solution { public: string toHexspeak(string num) { stringstream ss; long long inter; //转16进制 s ...

  5. C、C++语言中参数的压栈顺序

    要回答这个问题,就不得不谈一谈printf()函数,printf函数的原型是:printf(const char* format,-) 没错,它是一个不定参函数,那么我们在实际使用中是怎么样知道它的参 ...

  6. CDD All In One

    CDD All In One 组件驱动开发 (CDD) refs https://www.componentdriven.org/ https://www.learnstorybook.com/int ...

  7. Web API 设计

    Web API 设计 The Design of Web APIs free online ebook https://www.manning.com/books/the-design-of-web- ...

  8. 如何给 GitHub 添加 SSH key, 如何生成 SSH key 详细图文教程!

    如何给 GitHub 添加  SSH key, 如何生成  SSH key 详细图文教程! 一. 生成  SSH key https://ide.c9.io/xgqfrms/ 创建一个空项目:(或使用 ...

  9. HTML5 download 执行条件

    HTML5 download 执行条件 同一个域名下的资源 http only 绝对路径/相对路径 都可以 demo https://cdn.xgqfrms.xyz/ https://cdn.xgqf ...

  10. free food icons

    free food icons food icons Chinese foods https://www.flaticon.com/categories/food-and-restaurant htt ...