• 【疯狂Java讲义】Java学习记录(IO流)


    IO流

    IO:Input / Output

    完成输入 / 输出

    应用程序运行时——数据在内存中                        ←→                把数据写入硬盘(磁带)

                                    内存中的数据不可持久保存

    输入:从外部存储器(硬盘、磁带、U盘)把数据读入内存中。

    输出:从内存中把数据写入外部存储器(硬盘、磁带、U盘)中,这样就可以保证,即使程序退出了,数据依然不会丢失。

    File —— 代表磁盘上的文件或目录

    listRoot:列出磁盘上所有的根目录

    exists:判断是否存在

    mkdir:创建目录

    listFiles():列出当前目录下所有的文件和子目录

    listFiles(FileFilter filter):列出当前目录下符合指定条件的文件和子目录

    listFiles(FilenameFilter filter)

    列出某个磁盘所有的文件——递归

    1. import java.io.File;
    2. public class ListE {
    3. public static void main(String[] args) {
    4. // 创建一个File,它代表了E盘
    5. File e = new File("e:/Program Files");
    6. List(e);
    7. }
    8. public static void List(File dir) {
    9. System.out.println(dir + "目录下包含的文件和子目录有:");
    10. // 该方法返回当前目录所包含的所有文件和子目录
    11. File[] files = dir.listFiles();
    12. for (File file : files) {
    13. System.out.println(" " + file);
    14. // 如果file是目录,继续列出该目录下所有文件
    15. if (file.isDirectory()) {
    16. List(file);
    17. }
    18. }
    19. }
    20. }

     列出某个磁盘所有的.txt文件——递归

    1. import java.io.*;
    2. public class FileFilterTest {
    3. public static void main(String[] args) {
    4. File e = new File("e:/");
    5. // 返回当前目录所包含的所有*.txt文件,此时就需要对文件进行过滤
    6. File[] files = e.listFiles(new FileFilter() {
    7. // pathname就代表正在处理的文件,如果该方法返回true,意味着该文件就被保留,否则该方法将会被过滤掉
    8. @Override
    9. // 没有比IOExcepiton更小的,所以只能用try catch
    10. public boolean accept(File pathname) {
    11. // 说明文件名以.txt结尾
    12. try {
    13. if (pathname.getCanonicalPath().endsWith("txt")) {
    14. return true;
    15. }
    16. } catch (IOException e) {
    17. e.printStackTrace();
    18. }
    19. return false;
    20. }
    21. });
    22. for (File file : files) {
    23. System.out.println(file);
    24. }
    25. }
    26. }

    File的特征:只能访问磁盘上的文件和目录,它无法访问文件内容。

    如果要访问文件的内容,必须使用IO流

    流的分类

    1、按流的方向来分(从程序所在内存的角度来看)

    (1)输入流

    把外部输入读入当前程序所在内存

    (2)输出流

    把当前程序所在内存的数据输出到外部

    2、按流处理的数据来分

    (1)字节流

    处理数据单位是字节(8bit),适应性广、功能强大

    (2)字符流

    处理的数据单元是字符。通常来说它主要用于处理文本文件

    在处理文本文件时,比字节流方便

    3、按流的角色来分

    (1)节点流

    直接和一个IO的物理节点(磁盘上的文件、网络)关联

    (2)包装流(处理流 / 过滤流)

    以节点为基础,包装之后得到的流

    都继承了FilterXxx等基类

    流的概念模型

    输入流中的数据单元放入应用程序;应用程序中的数据单元放入输出流。

    缓冲流

    外部存储器的速度比内存的速度慢,外部存储器的读写与内存的读写并不同步

    ——通过缓冲就可以解决这种不同步

    反正你把流用完了,

    - 别忘记调用flush方法(把缓冲中的内容刷入实际的节点)

                 调用close()也可——系统会在关闭之前,自动刷缓冲

    IO流一共涉及40多个类

    字节流字符流
    节点流InputStreamOutputStreamReaderWriter抽象
    FileInputStreamFileOutputStreamFileReaderFileWriter访问文件
    ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter数组
    PipedInputStreamPipedOutputStreamPipedReaderPipedWriter访问管道
    StringReaderStringWriter访问字符串
    缓冲流BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter缓冲
    FilterInputStreamFilterOutputStreamFilterReaderFilterWriter抽象
    PrintStreamPrintWriter打印
    InputStreamReaderOutputStreamWriter转换
    DataInputStreamDataOutputStream特殊

    所有以InputStream结尾的都是字节输入流

    所有以OutputStream结尾的都是字节输出流

    所有以Reader结尾的都是字符输入流

    所有以Writer结尾的都是字符输出流

    1、FileInputStream 

    1. import java.io.*;
    2. public class FileInputStreamTest {
    3. public static void main(String[] args) throws IOException {
    4. // 创建输入流,相当于得到一根有水的水管
    5. FileInputStream fis = new FileInputStream("D:\\Program Files\\eclipse-java-2023-06-R-win32-x86_64\\workplace\\day\\src\\day13\\FileInputStreamTest.java");
    6. // System.out.print((char)fis.read());// 该方法每次只读一个字节
    7. /*
    8. * 为了把fis中水滴全部“取出”内存,有两个做法:
    9. * 1、用大桶
    10. * 2、用循环
    11. */
    12. byte[] buff = new byte[64]; // 我的水桶可以装64个“水滴”
    13. int hasRead = -1;
    14. //hasRead = fis.read(buff);// 用“桶”从fis(水管)中取水
    15. while((hasRead = fis.read(buff)) > 0) {
    16. // 上一次读取了几个字节,此处就输出几个字节
    17. System.out.println(new String(buff, 0 ,hasRead));
    18. }
    19. }
    20. }

    运行结果: 

     2、FileOutputStream

    1. import java.io.FileOutputStream;
    2. import java.io.IOException;
    3. public class FileOutputStreamTest {
    4. public static void main(String[] args) {
    5. FileOutputStream fos = null;
    6. try {
    7. // 得到输出流,相当于得到一个没有水滴的水管
    8. fos = new FileOutputStream("abc.txt");
    9. fos.write(97); // 每次输出"一个字节“
    10. fos.write(98);
    11. fos.write(99);
    12. fos.write(100);
    13. fos.write(101);
    14. fos.write("自由、民主的普世价值观~".getBytes());
    15. } catch (IOException ex) {
    16. ex.printStackTrace();
    17. } finally {
    18. try {
    19. fos.close();
    20. } catch (Exception ex) {
    21. ex.printStackTrace();
    22. }
    23. }

    运行结果: 

    复制文本文件

    1. import java.io.*;
    2. public class CopyTest {
    3. public static void main(String[] args) {
    4. // JDK 7提供了自动关闭资源的try语句
    5. try (
    6. // 创建输入流,得到一个有水滴的水管
    7. FileInputStream fis = new FileInputStream("D:\\Program Files\\eclipse-java-2023-06-R-win32-x86_64\\workplace\\day\\src\\day13\\CopyTest.java");
    8. // 创建输出流,得到一个空水管
    9. FileOutputStream fos = new FileOutputStream("D:\\Program Files\\eclipse-java-2023-06-R-win32-x86_64\\workplace\\day\\src\\day13\\test.txt");
    10. )
    11. {
    12. int hasRead = -1;
    13. byte[] buff = new byte[128];
    14. // 从fis里读取水滴,放入buff中
    15. while((hasRead = fis.read(buff)) > 0) {
    16. // 将buff中水滴写入fos,hasRead用于控制:读了多少,就写多少
    17. fos.write(buff, 0, hasRead);
    18. }
    19. } catch (IOException ex) {
    20. ex.printStackTrace();
    21. }
    22. }
    23. }

    运行结果: 

    节点流直接与IO节点关联

    ——IO节点有很多:键盘、网络、文件、磁带……

    过滤流:建立在节点流的基础之上

            过滤流的好处:

            ——消除底层节点之间的差异

            ——使用过滤流的方法执行IO更加便捷

                    FileOutputStream →PrintStream

                                  FileWriter→PrintWriter

                             如果已经知道要读的内容是字符内容,就可按如下方式转换:

                             InputStream→InputStreamReader→BufferedReader

    1、 FileOutputStream →PrintStream

    1. import java.io.*;
    2. public class PrintStreamTest {
    3. public static void main(String[] args) {
    4. try (
    5. // 创建节点流,节点流使用不方便
    6. FileOutputStream fos = new FileOutputStream("D:\\Program Files\\eclipse-java-2023-06-R-win32-x86_64\\workplace\\day\\src\\day13\\my.txt");
    7. // 把节点流包装成过滤流:消除节点流的差异,而且PrintStream的方法更加方便
    8. PrintStream ps = new PrintStream(fos);
    9. )
    10. {
    11. ps.println("我想");
    12. ps.println("我想早");
    13. ps.println("我想早点");
    14. } catch (Exception ex) {
    15. ex.printStackTrace();
    16. }
    17. }
    18. }

    运行结果: 

    3、DataInputStream与DataOutputStream

    它们是两个特殊的流——它们是过滤流(建立在已有IO的基础之上)

    ——它们只要增加一些特定的方法来读取特定的数据。

    1. import java.io.*;
    2. public class DataOutputStreamTest {
    3. public static void main(String[] args) {
    4. try (
    5. // 创建节点流——与磁盘上的文件关联
    6. FileOutputStream fos = new FileOutputStream("price.txt");
    7. // 创建过滤流,过滤流建立在节点流的基础上
    8. DataOutputStream dos = new DataOutputStream(fos);
    9. )
    10. {
    11. dos.writeDouble(3.4);
    12. dos.writeDouble(5.23);
    13. dos.writeDouble(4.34);
    14. dos.writeDouble(5.12);
    15. } catch (Exception ex) {
    16. ex.printStackTrace();
    17. }
    18. }
    19. }

    运行结果:

    1. import java.io.*;
    2. public class DataInputStreamTest {
    3. public static void main(String[] args) {
    4. try (
    5. // 先创建节点流,与指定物理节点(文件)建立读写
    6. FileInputStream fis = new FileInputStream("price.txt");
    7. // 以节点流来创建过滤流
    8. DataInputStream dis = new DataInputStream(fis);
    9. )
    10. {
    11. System.out.println(dis.readDouble());
    12. System.out.println(dis.readDouble());
    13. System.out.println(dis.readDouble());
    14. } catch (Exception ex) {
    15. ex.printStackTrace();
    16. }
    17. }
    18. }

    运行结果:

    重定向标准输入输出

    System.in——标准输入。通常代表键盘。

    System.out——标准输出。通常代表屏幕。

    System.setOut() ——可以将标准输出重定向另一个输出流。

    1. import java.io.*;
    2. public class SetOutTest {
    3. public static void main(String[] args) throws Exception{
    4. // 可以将标准输出重定向到指定的输出流
    5. System.setOut(new PrintStream("out.txt"));
    6. System.out.println("ABC");
    7. System.out.println("ABC");
    8. System.out.println("ABC");
    9. System.out.println("ABC");
    10. }
    11. }

    运行结果:输出的内容重定向到out.txt文本文件中 

    System.setIn() ——可以将标准输出重定向另一个输入流。

    1. import java.io.*;
    2. public class RedirectKeyIn {
    3. public static void main(String[] args) throws Exception {
    4. // 将标准输入重定向到RedirectKeyIn.java
    5. System.setIn(new FileInputStream("RedirectKeyIn.java"));
    6. //System.in,它是一个节点流,一般关联着物理键盘
    7. //直接用System.In(InputStream——节点、字节、输入流)可以读取键盘输入
    8. //缺点是:太繁琐、而且效率相当低下
    9. //System.out.println(System.in.read());
    10. InputStreamReader reader = new InputStreamReader(System.in);
    11. BufferedReader br = new BufferedReader(reader);
    12. String line = null;
    13. // 控制BufferedReader每次读取一行
    14. while ((line = br.readLine()) != null) {
    15. System.out.println(line);
    16. }
    17. }
    18. }

    运行结果:

    Java虚拟机读取其他进程的数据 

    Java如何启动其他进程:Runtime实例.exec()

    该方法的返回值是一个Process对象

    Process——代表一个进程。

                        进程就是运行中的应用程序。

    1. import java.io.*;
    2. public class ReadFromProcess {
    3. public static void main(String[] args) throws Exception{
    4. Runtime runtime = Runtime.getRuntime();
    5. // 启动javac应用程序,返回该应用程序对应的进程
    6. // Process proc = runtime.exec("javac.exe -encoding UTF8 -d . ReadFromProcess.java");
    7. Process proc = runtime.exec("javac.exe -encoding UTF8 -d . ReadFromProcess");
    8. // 要得到javac应用程序输出的内容,此处应该用输入流?还是输出流?
    9. // 对于javac来说,是输出;但对于我们应用程序来说,用输入流
    10. InputStreamReader reader = new InputStreamReader(proc.getErrorStream());
    11. BufferedReader br = new BufferedReader(reader);
    12. String line = null;
    13. StringBuilder sb = new StringBuilder();
    14. // 控制BufferedReader每次读取一行
    15. while ((line = br.readLine()) != null) {
    16. //System.out.println(line);
    17. sb.append(line);
    18. }
    19. // 如果有错误输出
    20. if (sb.toString().length() > 0) {
    21. System.out.println("编译出错,错误信息如下----");
    22. // 输出错误提示
    23. System.out.println(sb);
    24. } else {
    25. System.out.println("成功完成----");
    26. }
    27. }
    28. }

    上面为“编译出错”的代码,下面为“成功完成”的代码 

    RandomAccessFile——随意(任意)访问文件

    Random——想访问文件的哪个点,就访问文件的哪个点(任意)

    RandomAccessFile实现了Closeable接口,所以可以使用自动关闭资源的try语句

    特征

    1、既可读、又可写、还可追加。相当于InputStream与OutputStream合体。

          RandomAccessFile它不会覆盖原有的文件内容。

    2、只能访问文件!这就是它的局限性。

    1. import java.io.*;
    2. public class RandomAccessFileTest {
    3. public static void main(String[] args) {
    4. try (
    5. // 使用RadomAccessFile创建一个只读的输入流
    6. RandomAccessFile raf = new RandomAccessFile("RandomAccessFileTest.java", "r");
    7. )
    8. {
    9. byte[] buff = new byte[1024];
    10. int hasRead = -1;
    11. while ((hasRead = raf.read(buff)) > 0) {
    12. System.out.println(new String(buff, 0, hasRead));
    13. }
    14. } catch (Exception ex) {
    15. ex.printStackTrace();
    16. }
    17. }
    18. }

    创建RandomAccessFile,需要指定读(r)、写(rw)模式

    体现它的“random【任意】”性的方法

    seek(long pos)——用于把记录指针移动到任意位置,想访问哪个点就访问哪个点。

    一开始,它的记录指针位于文件的开始位置。

    使用RandomAccessFile来追加文件内容

    1、把记录指针移动到最后

    2、执行输出即可

    1. import java.io.RandomAccessFile;
    2. public class AppendTest {
    3. public static void main(String[] args) {
    4. try (
    5. // 使用RadomAccessFile创建一个只读的输入流
    6. RandomAccessFile raf = new RandomAccessFile("AppendTest.java", "rw");
    7. )
    8. {
    9. // 把记录指针移动到文件的最后
    10. raf.seek(raf.length());
    11. raf.write("//做人好累".getBytes());
    12. } catch (Exception ex) {
    13. ex.printStackTrace();
    14. }
    15. }
    16. }

    使用RandomAccessFile来插入文件内容

    1、把记录指针移动到指定位置

    2、从当前位置到文件结尾的内容,先读取,并保存

    3、输出要插入的内容

    序列化

    Java对象(内存)->二进制流

    目的

    1、在有些时候,需要把对象存储到外部存储器中持久化保存。

    2、在有些时候,需要把对象通过网络传输。

    可序列化的对象

    Java要求序列化的类实现下面任意两个接口

    1、Serializable:接口只是一个标记性的接口,实现该接口无需实现任何方法

    2、Externalizable:实现该接口要实现方法。

    序列化的IO流

      ObjectInputStream——负责从二进制流“恢复”对象。readObject

    ObjectOutputStream——负责把对象保存到二进制流中。writeObject

    1. import java.io.*;
    2. class Apple implements Serializable{
    3. private String name;
    4. private String color;
    5. private double weight;
    6. public Apple() {
    7. super();
    8. }
    9. public Apple(String name, String color, double weight) {
    10. super();
    11. this.name = name;
    12. this.color = color;
    13. this.weight = weight;
    14. }
    15. public String getName() {
    16. return name;
    17. }
    18. public void setName(String name) {
    19. this.name = name;
    20. }
    21. public String getColor() {
    22. return color;
    23. }
    24. public void setColor(String color) {
    25. this.color = color;
    26. }
    27. public double getWeight() {
    28. return weight;
    29. }
    30. public void setWeight(double weight) {
    31. this.weight = weight;
    32. }
    33. public String toString() {
    34. return "Apple[name="
    35. + name +",color=" + color
    36. + ",weight=" + weight + "]";
    37. }
    38. }
    39. public class WriteObject {
    40. public static void main(String[] args) {
    41. Apple ap = new Apple("红富士", "红色", 3.4);
    42. System.out.println(ap);
    43. // 当程序结束时,虚拟机退出,内存中的Apple对象就被销毁了
    44. try (
    45. ObjectOutputStream oos = new ObjectOutputStream(
    46. new FileOutputStream("app.bin"));
    47. )
    48. {
    49. oos.writeObject(ap); //把ap对象写入app.bin文件中
    50. }
    51. catch (Exception ex) {
    52. // TODO: handle exception
    53. }
    54. }
    55. }

    1. import java.io.*;
    2. public class ReadObject {
    3. public static void main(String[] args) {
    4. try (
    5. ObjectInputStream ois = new ObjectInputStream(
    6. new FileInputStream("app.bin"));
    7. )
    8. {
    9. Apple ap = (Apple)ois.readObject();
    10. System.out.println(ap);
    11. }
    12. catch (Exception ex) {
    13. ex.printStackTrace();
    14. }
    15. }
    16. }

    序列化机制

    总结

    Java传统IO的基本体系

    字节输入流字节输出流字符输入流字符输出流
    访问文件InputStreamOutputStreamReaderWriter
    访问数组FileXxx
    访问管道ByteArrayXxxCharArrayXxx
    访问字符串StringXxx
    过滤流FilterInputStreamFilterOutputStreamFilterReaderFilterWriter
    打印流PrintStreamPrintWriter
    转换流InputStreamReaderOutputStreamWriter
    特殊流DataInputStreamDataOutputStream
    ObjectInputStreamObjectOutputStream

    RandomAccessFile

    1、它只能访问文件。相当于DataInputStream和DataOutputStream组合

    2、任意,由seek(int pos)。

  • 相关阅读:
    【开题报告】基于SpringBoot的乡村文旅平台的设计与实现
    由粒子加速器产生的反中子形成的白洞
    捷报 | 美格智能Cat.1模组SLM332中标中国电信定制版Cat.1模组产品招募
    Vue——组件化开发
    GOLANG 原生SQL 为什么 查询不到字段值
    DevOps持续集成-Jenkins(4)
    【算法训练-回溯算法 三】【回溯算法最佳实践】括号生成、复原IP地址
    程序员的晋升困境
    JAVASE语法零基础——Object类
    湖南互联网医院|湖南互联网医院牌照办理流程及材料
  • 原文地址:https://blog.csdn.net/have_to_be/article/details/132534699