IO流

水流 特点
连续性 逝者如斯夫,不舍昼夜;
方向性 一江春水向东流。水往低处流。百川东到海,何时复西归?少壮不努力,老大徒伤悲!
源头尽头 唯有源头活水来;覆水难收

Java里的IO也有这样的特点。

IO:数据从硬盘流向内存(Input),或者从内存流向硬盘(Output)。

IO流分类:

按照流的流向来分:输入流、输出流。

|-输入流:读入内存。

|-输出流:写出到硬盘等设备。

按操作数据单元分:字节流、字符流

|-字节流:8位

|-字符流:16位

按流的角色分:节点流、处理流。

|-节点流:特定的IO设备(如硬盘),也叫低级流

|-处理流:经过封装的流,也叫高级流、包装流,可以消除不同节点流的差异(典型的装饰器模式)

Java的IO流有40多个类,高抽象层的基类有四个:

字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

字节流

字节流:100100011010100010

  1. 可以操作所有文件,包括文本文件、视频、音频、压缩文件等等都可以用字节流读写。

两个重要的抽象类:

(1)抽象类 java.io.OutputStream,是输出字节流的所有类的超类

|--API方法摘要:

|--|--void write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。

|--|--abstract void write(int b) 将指定的字节写入此输出流。

|--|--void close() 关闭此输出流并释放与此流有关的所有系统资源。

(2)抽象类 java.io.InputStream,是输入字节流的所有类的超类

|--API方法摘要:

|--|--abstract int read()从输入流中读取数据的下一个字节。

|--|--int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。

|--|--void close() 关闭此输入流并释放与该流关联的所有系统资源。

FileOutputStream写文件

  1. // 文件输出流。完整地说,是文件字节输出流。
  2. public class FileOutputStream extends OutputStream

步骤:

1.创建流对象

2.调用write方法,把数据写入文件

3.释放资源

  1. import java.io.*;
  2. public class 文件字节输出流 {
  3. public static void main(String[] args) {
  4. File file = new File("文件字节输出流.txt"); // 创建文件对象
  5. try {
  6. // (1)构造:通过文件对象创建文件输出流对象
  7. FileOutputStream fos = new FileOutputStream(file);
  8. // (2)写入文件
  9. // (2.1)write(int b) 将"单个字节"写入到文件中
  10. for (int i = 49; i < 97; i++) {
  11. fos.write(i);
  12. fos.write(' ');
  13. }
  14. // (2.2)write(byte[] b) 将"字节数组"中的数据全部写入文件
  15. byte[] buffer = "I Love Java,你呢?".getBytes();
  16. fos.write(buffer);
  17. // (3)关闭流
  18. fos.close();
  19. } catch (IOException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. }

追加:

使用构造方法:FileOutputStream(File file, boolean append)

  1. // 构造:通过文件对象创建文件输出流对象
  2. // 附加第二个参数true,指定进行文件追加,默认为不追加
  3. fos = new FileOutputStream(file, true);

回车换行:

CR(carriage return),回车,\r

LF(line feed),换行,\n

windows:\r\n

linux或unix:\n

mac:\r

FileInputStream读文件

  1. public class FileInputStream extends InputStream
  1. import java.io.*;
  2. public class 文件字节输入流 {
  3. static final int C_CONDITION = 2;
  4. public static void main(String[] args) {
  5. try {
  6. File file = new File("testRead.dat"); // 创建文件对象
  7. // 【1】创建输入流对象,相当于打开文件
  8. FileInputStream fis = new FileInputStream(file);
  9. if (C_CONDITION == 1) {
  10. // 【2】.read():读取单个字节
  11. for (int i = 0; i < file.length(); i++) {
  12. // 循环读取"字节",转为字符输出,英文没问题
  13. int read = fis.read();
  14. char ch = (char) read;
  15. System.out.print(ch);
  16. }
  17. System.out.println();
  18. } else {
  19. // 【2】.read(byte[] b):读取文件中的数据到字节数组
  20. // 根据文件的字节长度创建字节数组
  21. long len = file.length();
  22. byte[] buf = new byte[(int) len];
  23. fis.read(buf);
  24. // 利用字节数组创建字符串
  25. String str = new String(buf);
  26. System.out.println(str);
  27. }
  28. // 【3】关闭流
  29. fis.close();
  30. } catch (FileNotFoundException fnfe) {
  31. System.out.println("文件打开失败。");
  32. } catch (IOException ioe) {
  33. ioe.printStackTrace();
  34. }
  35. }
  36. }

复制文件

  1. package ahjava.io;
  2. import java.io.*;
  3. public class 复制文件 {
  4. public static void main(String[] args) {
  5. 字节流复制文件();
  6. }
  7. static void 字节流复制文件() {
  8. File srcFile = new File("testRead.dat"); // 源文件对象
  9. File destFile = new File("testCopy.java"); // 目标文件对象
  10. if (destFile.exists()) {
  11. // 判断目标文件是否存在,存在则删除
  12. destFile.delete();
  13. }
  14. // 目标文件不存在才复制
  15. try {
  16. destFile.createNewFile();
  17. // 创建文件输入/输出流对象
  18. FileInputStream fis = new FileInputStream(srcFile);
  19. FileOutputStream fos = new FileOutputStream(destFile);
  20. // 创建字节数组,作为临时缓冲
  21. byte[] buf = new byte[128];
  22. System.out.println("开始复制文件...");
  23. int len = -1;
  24. // 循环从文件输入流中读取数据
  25. while ((len = fis.read(buf)) != -1) {
  26. System.out.println(len);
  27. // 写入到文件输出流中
  28. fos.write(buf, 0, len);
  29. }
  30. System.out.println("文件复制成功!");
  31. fis.close(); // 关闭流
  32. fos.close();
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }

上面的代码有哪些风险?

改进版:

  1. static void 字节流复制文件2() {
  2. // 1.close()提取到finally中
  3. // 2.提取FilexxxStream对象
  4. // 3.初始化(否则不准close)
  5. // 4.close()时加判空语句
  6. FileInputStream fis = null;
  7. FileOutputStream fos = null;
  8. File srcFile = new File("testRead.dat"); // 源文件对象
  9. File destFile = new File("testCopy.java"); // 目标文件对象
  10. if (destFile.exists()) {
  11. // 判断目标文件是否存在,存在则删除
  12. destFile.delete();
  13. }
  14. // 目标文件不存在才复制
  15. try {
  16. destFile.createNewFile();
  17. fis = new FileInputStream(srcFile);
  18. fos = new FileOutputStream(destFile);
  19. // 创建字节数组,作为临时缓冲
  20. byte[] buf = new byte[128];
  21. System.out.println("开始复制文件...");
  22. int len = -1;
  23. // 循环从文件输入流中读取数据
  24. while ((len = fis.read(buf)) != -1) {
  25. System.out.println(len);
  26. // 写入到文件输出流中
  27. fos.write(buf, 0, len);
  28. }
  29. System.out.println("文件复制成功!");
  30. // 关闭流
  31. } catch (IOException e) {
  32. e.printStackTrace();
  33. } finally {
  34. if (fis != null) {
  35. try {
  36. fis.close();
  37. } catch (IOException e) {
  38. // TODO Auto-generated catch block
  39. e.printStackTrace();
  40. }
  41. fis = null;
  42. }
  43. if (fos != null) {
  44. try {
  45. fos.close();
  46. } catch (IOException e) {
  47. // TODO Auto-generated catch block
  48. e.printStackTrace();
  49. }
  50. fos = null;
  51. }
  52. }
  53. }

又臭又长!

Java 7异常处理写法:

try后面增加括号,其中定义流对象,该流对象仅在try中有效,执行完毕自动释放,不需要写finally。

  1. try(流对象){
  2. } catch (IOException e) {
  3. }

具体代码如下:

  1. static void 字节流复制文件3() {
  2. File srcFile = new File("testRead.dat"); // 源文件对象
  3. File destFile = new File("testCopy.java"); // 目标文件对象
  4. if (destFile.exists()) {
  5. // 判断目标文件是否存在,存在则删除
  6. destFile.delete();
  7. }
  8. // try(流对象)
  9. try (FileInputStream fis = new FileInputStream(srcFile);
  10. FileOutputStream fos = new FileOutputStream(destFile)) {
  11. destFile.createNewFile();
  12. // 创建字节数组,作为临时缓冲
  13. byte[] buf = new byte[128];
  14. System.out.println("开始复制文件...");
  15. int len = -1;
  16. // 循环从文件输入流中读取数据
  17. while ((len = fis.read(buf)) != -1) {
  18. System.out.println(len);
  19. // 写入到文件输出流中
  20. fos.write(buf, 0, len);
  21. }
  22. System.out.println("文件复制成功!");
  23. // 关闭流
  24. } catch (IOException e) {
  25. e.printStackTrace();
  26. }
  27. }

*Java9异常处理写法

觉得try里的代码太繁琐,try()中可以引入外部的变量:

  1. FileInputStream fis = new FileInputStream(srcFile);
  2. FileOutputStream fos = new FileOutputStream(destFile);
  3. try (fis;fos){...}
  4. // ↑ 理想状态,代码并不能这么写

然而,fis、fos本身需要抛异常,如果直接try...catch,这两个变量会变成另外的try中的局部变量;

如果把声明提取到try之外,try (fis;fos)又需要变量是final的

  1. FileInputStream fis = null;
  2. FileOutputStream fos = null;
  3. try {
  4. fis = new FileInputStream(srcFile);
  5. fos = new FileOutputStream(destFile);
  6. } catch (FileNotFoundException e1) {
  7. e1.printStackTrace();
  8. }
  9. try (fis;fos) {

CopyFile.java:20: 错误: 用作 try-with-resources 资源的变量 fis 既不是最终变量, 也不是实际上的最终变量

try (fis;fos) {

^

CopyFile.java:20: 错误: 用作 try-with-resources 资源的变量 fos 既不是最终变量, 也不是实际上的最终变量

try (fis;fos) {

所以,fis和fos需要往外抛出异常,外部调用的地方又需要捕获异常。比不用此功能还要麻烦。可运行代码如下:

  1. import java.io.*;
  2. public class CopyFile{
  3. public static void main(String[] args) {
  4. try {
  5. copyJDK9();
  6. } catch (FileNotFoundException e) {
  7. e.printStackTrace();
  8. }
  9. }
  10. static void copyJDK9() throws FileNotFoundException {
  11. File srcFile = new File("testRead.dat");
  12. File destFile = new File("testCopy.java");
  13. if (destFile.exists()) {
  14. destFile.delete();
  15. }
  16. FileInputStream fis = new FileInputStream(srcFile);
  17. FileOutputStream fos = new FileOutputStream(destFile);
  18. try (fis;fos) {
  19. destFile.createNewFile();
  20. byte[] buf = new byte[128];
  21. System.out.println("start copy...");
  22. int len = -1;
  23. while ((len = fis.read(buf)) != -1) {
  24. System.out.println(len);
  25. fos.write(buf, 0, len);
  26. }
  27. System.out.println("success");
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }

Java基础教程——字节流的更多相关文章

  1. Java基础教程(25)--I/O

    一.I/O流   I/O流表示输入源或输出目标.流可以表示许多不同类型的源和目标,例如磁盘文件.设备.其他程序等.   流支持许多不同类型的数据,包括字节.原始数据类型.字符和对象等.有些流只传递数据 ...

  2. Java基础教程(18)--继承

    一.继承的概念   继承是面向对象中一个非常重要的概念,使用继承可以从逻辑和层次上更好地组织代码,大大提高代码的复用性.在Java中,继承可以使得子类具有父类的属性和方法或者重新定义.追加属性和方法. ...

  3. Java基础教程(12)--深入理解类

    一.方法的返回值   当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...

  4. Java基础教程:注解

    Java基础教程:注解 本篇文章参考的相关资料链接: 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3 注解基础与高级应用:http: ...

  5. Java基础教程:网络编程

    Java基础教程:网络编程 基础 Socket与ServerSocket Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个s ...

  6. Java基础教程(5)--变量

    一.变量 1.变量的定义   正如上一篇教程<Java基础教程(4)--面向对象概念>中介绍的那样,对象将它的状态存在域中.但是你可能仍然有一些疑问,例如:命名一个域的规则和惯例是什么?除 ...

  7. Java基础教程:Lambda表达式

    Java基础教程:Lambda表达式 本文部分内容引用自OneAPM:http://blog.oneapm.com/apm-tech/226.html 引入Lambda Java 是一流的面向对象语言 ...

  8. Java基础教程:泛型基础

    Java基础教程:泛型基础 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚 ...

  9. Java基础教程:多线程基础(1)——基础操作

    Java:多线程基础(1) 实现多线程的两种方式 1.继承Thread类 public class myThread extends Thread { /** * 继承Thread类,重写RUN方法. ...

随机推荐

  1. python引用方法赋值问题探究

    python脚本编写中,经常会遇到引用一个模块的方法的场景.引用的方法里到底赋不赋值曾经困扰了我好久. 最近利用python写了一个接口自动化测试脚本,在查阅观看多篇博文和视频后解决了封装方法引用的问 ...

  2. MongoDB 监控 --- MongoDB基础用法(八)

    MongoDB 监控 在你已经安装部署并允许MongoDB服务后,你必须要了解MongoDB的运行情况,并查看MongoDB的性能.这样在大流量得情况下可以很好的应对并保证MongoDB正常运作. M ...

  3. SpringBoot+Mybatis_Plus Generator

    AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity.Mapper.Mapper XML.Service.Control ...

  4. ArcPy批量选择指定属性的要素

    在GIS数据处理中,选择数据是十分频繁的操作,常用的是"按属性选择"和"按位置选择",这两个功能虽然比较强大,但有时也不能满足实际需求.比如可能时常会遇到这样一 ...

  5. Android 教你如何发现 APP 卡顿

    最近部门打算优化下 APP 在低端机上的卡顿情况,既然想优化,就必须获取卡顿情况,那么如何获取卡顿情况就是本文目的. 一般主线程过多的 UI 绘制.大量的 IO 操作或是大量的计算操作占用 CPU,导 ...

  6. unicode与编码的关系

    参考链接先贴上来:https://blog.csdn.net/humadivinity/article/details/79403625https://www.cnblogs.com/kevin2ch ...

  7. 【Kata Daily 191010】Grasshopper - Summation(加总)

    题目: Summation Write a program that finds the summation of every number from 1 to num. The number wil ...

  8. JS+CSS+HTML实现“代码雨”类似黑客帝国文字下落效果

    HTML代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <l ...

  9. absolute与relative 的超越

    relative 超越了自身而已,所有位置的变化是相对于正常流下自身的表现而言 absolute  超越了父容器,位置信息是基于父容器的位置而言

  10. 一致性(ECMAScript语法标准翻译)

    Conformance A conforming implementation of ECMAScript must provide and support all the types, values ...