博主声明:

转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。

本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/smile_running

  • I/O 流

关于数据的存储,分为内部存储和外部存储。内部存储就像内存一样,是一种临时性的对数据进行储存的方式,这种方式存储的数据量不大,但是获取数据块。另一种就是持久性的存储,以文件的方式来保存数据,可以是数据库、文本文件、图片文件、视频文件等等,存储的数据量非常大。

Java提供了一种对文件进行操作的API,就是I/O流。I/O流是Java中的一个非常庞大的家族,同时这个家族也非常强大。关于流的概念,我们可以这样的理解。水流,流的是水;电流,流的是电;I/O流,流的就是与计算机相关的二进制字节码、字符码。

I/O(Input / Output)就是标准的输入和输出,加上流的话。那么就是InputStream / OutputStream。流这个家族成员有很多,下面我们来通过一个表格来看看常用的流。

(1)流的家族

分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputSream OutputSream Reader Writer
访问文件 FileInputSream FileOutputStream FileReader FileWriter
访问数组 ByteArrayInputSream ByteArrayOutputSream CharArrayReader CharArrayWriter
访问管道 PipedInputSream PipedOutputSream PipedReader PipedWriter
缓冲流 BufferedInputSream BufferedOutputSream BufferedReader BufferedWriter
访问字符串     StringReader StringWriter
转换流     InputStreamReader OutputStreamWriter
对象流 ObjectInputStream ObjectOutputSream    
特殊流 DataInputStream DataOutputStream    
打印流   PrintStream   PrintWriter
推回输入流 PushbackInputStream   PushbackReader  
过滤流 FilterInputStream FilterOutputStream FilterReader FilterWriter
随机存储文件的流(支持读写) RandomAccessFile

整个流的家族差不多也就这些了。通过以上的表格,我们大致了解了流的家族成员,下面我们来看看关于流的分类。

(2)流的分类

根据流的流向不同 输入流 输出流
根据流动单位不同 字节流 字符流
根据流的功能不同 节点流 处理流
  • 输入流  、输出流的作用

输入流,用于从 .txt文件中读取数据;输出流,向文件中写入数据

  • 字节流  、字符流的区别

字节流,byte来接收数据,作用于任何类型的文件。

字符流,char来接收数据。只能作用于纯文本(.txt)文件。如果是纯文本文件,读取速度比字节流更快。

  • 节点流  、 处理流

节点流,直接作用于文件上,如:new FileInputStream(File file);

处理流 , 作用于流上,如:new BufferedInputStream(InputStream is),作用是加速流的读取/写入速度。

  • File 类

介绍了整个流家族,我们还缺一个与流息息相关的 File 类。顾名思义,这是对文件进行创建、删除操作的一个类。而流则就是对文件的读取/写入操作的类。对于文件的操作,我们直接看代码例子比较鲜明,这也没什么理论好说的。

 @Testpublic void file() throws IOException {// 绝对路径:d:/FileTest/test ,新建文件夹File dirFile = new File("d:/FileTest/test");if (!dirFile.exists()) {dirFile.mkdirs();}// 相对路径:C:\Users\x\eclipse-workspace\HelloJava\Test.txt ,新建文件File helloFile = new File("Test.txt");if (!helloFile.exists()) {helloFile.createNewFile();}// 列出 d:/FileTest/test 文件夹下的所有文件名File nameFile = new File("d:/FileTest/test");String[] fileName = nameFile.list();for (String name : fileName) {System.out.println(name);}//判断文件的存在性System.out.println(helloFile.exists());//获取绝对路径System.out.println(helloFile.getAbsolutePath());//获取父目录System.out.println(helloFile.getParent());// 获取最后修改文件的时间System.out.println(new Date(helloFile.lastModified()));}

注意点:例如,D:/FileTest/test ,使用 mkdir 与 mkdirs 的区别 mkdir 前提是 FileTest 存在的情况下才可以创建成功 mkdirs 不需要,若 FileTest 文件夹不存在,则一并创建。

I/O流的用法

  • FileInputStream/FileOutputStream

这两个是节点流,可以直接作用于文件上。例如,从文本文件中读取数据打印到控制台上:

  • FileInputStream 实现读取文件
 @Testpublic void fisTest() {File file = new File("Hello.txt");FileInputStream fis = null;try {fis = new FileInputStream(file);byte[] b = new byte[10];int length;while ((length = fis.read(b)) != -1) {String str = new String(b, 0, length);System.out.print(str);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}

比较难理解的就是while循环,它表达的是从 Hello.txt 文件中读取byte[10]这样长度的字节,然后打印到控制台。若已经读到结尾,则没有数据可以读了,就会返回 -1

  • FileOutputStream 实现写入文件
 @Testpublic void fosTest() {// 指定文件路径,若不存在,则会自动创建File file = new File("Hello.txt");FileOutputStream fos = null;try {fos = new FileOutputStream(file);byte[] b = new String("hello Java 2").getBytes();fos.write(b, 0, b.length);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}}}
  • FileInputStream/FileOutputStream 实现文件拷贝
 @Testpublic void copyTest() {long start = System.currentTimeMillis();File srcFile = new File("mv.mp4");File destFile = new File("mv3.mp4");FileInputStream fis = null;FileOutputStream fos = null;try {fis = new FileInputStream(srcFile);fos = new FileOutputStream(destFile);byte[] b = new byte[4 * 1024];int len;while ((len = fis.read(b)) != -1) {fos.write(b, 0, len);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}long end = System.currentTimeMillis();System.out.println("time:" + (end - start));}
  • BufferedInputStream/BufferedOutputStream

这两个是作用于字节流的处理流,它可以加速文件的读取和写入,所以我就尝试了一下。通过对比,我认为是有快一点,决定因素更大的在于byte[]数组的缓冲区大小。据说4k的缓冲区是读写大文件的最快方式。BufferedInputStream/BufferedOutputStream用法也非常简单,其实流族的代码写法都差不太多。下面来看看代码的使用:

@Testpublic void copy2Test() {long start = System.currentTimeMillis();//备注:mv.mp4  测试文件大小 500MFile file = new File("mv.mp4");File file2 = new File("mv2.mp4");BufferedInputStream bis = null;BufferedOutputStream bos = null;try {FileInputStream fis = new FileInputStream(file);FileOutputStream fos = new FileOutputStream(file2);bis = new BufferedInputStream(fis);bos = new BufferedOutputStream(fos);byte[] b = new byte[4 * 1024];// 4k缓冲区int len;while ((len = bis.read(b)) != -1) {bos.write(b, 0, len);bos.flush();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {//把 bis 和 bos 关闭,那么 fis 和 fos 也就自动被关闭if (bos != null) {try {bos.close();} catch (IOException e) {e.printStackTrace();}}if (bis != null) {try {bis.close();} catch (IOException e) {e.printStackTrace();}}}long end = System.currentTimeMillis();System.out.println("time:" + (end - start));}
  • FileReader/FileWriter

这两个也是节点流,可以直接作用于文件上。但这个只能用于读取/写入纯文本文件(.txt),比如你新建的.doc文件也纯写文字,它也不能给你读取出来。它的用法类似,只是接收的缓冲区改为 char 型,代码如下:

/*** 使用 FileReader 来读取文件 注意:只能读取文本文件,如.txt*/@Testpublic void frTest() {FileReader fr = null;try {File file = new File("Hello.txt");fr = new FileReader(file);char[] c = new char[10];int len;while ((len = fr.read(c)) != -1) {String str = new String(c, 0, len);System.out.println(str);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (fr != null) {try {fr.close();} catch (IOException e) {e.printStackTrace();}}}}
  • FileReader/FileWriter实现纯文本文件的拷贝
@Testpublic void txtCopyTest() {FileReader fr = null;FileWriter fw = null;try {File file = new File("Hello.txt");File file2 = new File("Test.txt");fr = new FileReader(file);fw = new FileWriter(file2);char[] c = new char[10];int len = 0;while ((len = fr.read(c)) != -1) {fw.write(c, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {if (fw != null) {try {fw.close();} catch (IOException e) {e.printStackTrace();}}if (fr != null) {try {fr.close();} catch (IOException e) {e.printStackTrace();}}}}
  • BufferedReader/BufferedWriter

这两个是作用于字符流的处理流,目的也是加速文件的读取和写入速度。具体用法:

@Testpublic void txtCopy2Test() {BufferedReader br = null;BufferedWriter bw = null;try {File file = new File("Hello.txt");File file2 = new File("Test.txt");FileReader fr = new FileReader(file);FileWriter fw = new FileWriter(file2);br = new BufferedReader(fr);bw = new BufferedWriter(fw);String str = null;while ((str = br.readLine()) != null) {bw.write(str);bw.newLine();bw.flush();}} catch (IOException e) {e.printStackTrace();} finally {if (bw != null) {try {bw.close();} catch (IOException e) {e.printStackTrace();}}if (br != null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}}}
  • InputStreamReader/InputStreamWriter

这是一个转换流,例如从键盘上输入一条字符串,本质是二进制的字符码,我们可以将它转为能看的懂的字符。代码如下:

/*** 系统的输入和输出,利用InputStreamReader(转换流)来转二进制码*/@Testpublic void systemOut() {InputStreamReader isr = null;try {System.out.println("请输入字符串:");InputStream is = System.in;// 用到转换流isr = new InputStreamReader(is);char[] c = new char[10];int len;while ((len = isr.read(c)) != -1) {String str = new String(c, 0, len);System.out.println(str);}} catch (IOException e) {e.printStackTrace();} finally {if (isr != null) {try {isr.close();} catch (IOException e) {e.printStackTrace();}}}}
  • PrintStream/PrintWriter

这两个是打印流,用于打印数据。也可以直接作用文件上,例如,向文本文件中打印数据:

 /*** PrintStream 和 PrintWriter 用法一致,只不过流的单位不同*/@Testpublic void printIOTest() {PrintStream ps = null;try {File file = new File("Hello2.txt");ps = new PrintStream(file);ps.append("Java");ps.append("Android");ps.append("Python");ps.append("kotlin");} catch (FileNotFoundException e) {e.printStackTrace();} finally {if (ps != null) {ps.close();}}}
  • DataInputStream/DataOutputStream

这两个流比较特殊,它只能用于读取/写入基本数据类型(byte、char、short、int、long、float、double、boolean),额外还可以写入 String (readUTF)。但是写入的基本数据类型会形成字节码,我们只能通过 DataInputStream来读取。代码例子:

/*** DataOutputStream 只能用于写入基本数据类型,反之也只能用DataInputStream来读取,否则读到的就是乱码*/@Testpublic void dataIOTest() {DataInputStream dis = null;DataOutputStream dos = null;try {dis = new DataInputStream(new FileInputStream(new File("Hello2.txt")));dos = new DataOutputStream(new FileOutputStream(new File("Hello2.txt")));dos.writeUTF("Java");dos.writeChar('c');dos.writeLong(4564114564l);dos.writeBoolean(false);dos.write(22);System.out.println(dis.readUTF());System.out.println(dis.readChar());System.out.println(dis.readLong());System.out.println(dis.readBoolean());System.out.println(dis.read());} catch (Exception e) {e.printStackTrace();} finally {if (dos != null) {try {dos.close();} catch (IOException e) {e.printStackTrace();}}if (dis != null) {try {dis.close();} catch (IOException e) {e.printStackTrace();}}}}

使用 FileInputStream 来读取的话,只能读到乱码文件:

使用DataInputStream来都,则正常显示:

  • ObjectInputStream/ObjectOutputStream

这两个是对象处理流,主要是把对象持久性的存储。比如我有一个Student类,我创建了2个Student类的对象并对它进行了赋值,然后我想存储持久性这个对象,就需要这两个处理流。

  • 序列化:允许把内存中的Java对象转换为二进制流来持久性的储存,通过网络可以传输序列化对象(二进制流)。
  • 反序列化:可以通过网络接收到的序列化对象(二进制流)来恢复原来的Java对象。

需注意:处理流在存储对象的时候,比如一个类,这个类必须实现序列化接口(Serializable 或 Externalizable)。如果被 static 或 transient 修饰的变量,不可被序列化,接收到的就会是空值。例子如下:

  • ObjectOutputStream 序列化对象
         /*** 序列号过程*/@Testpublic void objIOTest() {Student stu1 = new Student("001", "张三");Student stu2 = new Student("002", "李四");ObjectOutputStream oos = null;try {oos = new ObjectOutputStream(new FileOutputStream(new File("student.txt")));oos.writeObject(stu1);oos.flush();oos.writeObject(stu2);oos.flush();} catch (Exception e) {e.printStackTrace();} finally {if (oos != null) {try {oos.close();} catch (IOException e) {e.printStackTrace();}}}}
  • ObjectInputStream 反序列化
 /*** 反序列化*/@Testpublic void objIOTest2() {ObjectInputStream ois = null;try {ois = new ObjectInputStream(new FileInputStream(new File("student.txt")));Student get_stu1 = (Student) ois.readObject();System.out.println(get_stu1);Student get_stu2 = (Student) ois.readObject();System.out.println(get_stu2);} catch (Exception e) {e.printStackTrace();} finally {if (ois != null) {try {ois.close();} catch (IOException e) {e.printStackTrace();}}}}
  • RandomAccessFile

这个流属于比较特殊,它自身可以充当输入流,也可以充当输出流。原因是它的构造器可以传入一种 mode,这种 mode 共分为4种情况:

  • r      只读
  • rw    读和写
  • rwd  读和写,并且同步更新内容
  • rws  读和写,并且同步更新内容和元数据

例子:通过RandomAccessFile对文本文件的插入操作,RandomAccessFile(以及所有流)在写入的时候,都会将文件中的数据覆盖。所以,通过seek();方法将光标往后移动,保存后面的字符数据后再插入,最后将字符数据加到后面即可。

 /*** RandomAccessFile 实现在文本中插入数据*/@Testpublic void randomAccessTest() {RandomAccessFile raf_rw = null;try {raf_rw = new RandomAccessFile(new File("Hello3.txt"), "rw");// 光标移动到要插入的位置raf_rw.seek(5);// 保存后面的所有字符串StringBuffer buf = new StringBuffer();String str;while ((str = raf_rw.readLine()) != null) {buf.append(str + "\n");}System.out.println(buf.toString());raf_rw.seek(5);raf_rw.writeUTF("Java" + buf.toString());} catch (Exception e) {e.printStackTrace();} finally {try {raf_rw.close();} catch (IOException e) {e.printStackTrace();}}}

IO流的大致使用都过了一遍,这些仅仅是的基本用法。

什么是 Java 输入输出流?流的用法大全相关推荐

  1. java实验10流_实验9 Java输入输出流

    <实验9 Java输入输出流>由会员分享,可在线阅读,更多相关<实验9 Java输入输出流(14页珍藏版)>请在金锄头文库上搜索. 1.山 西 大 学 计 算 机 与 信 息 ...

  2. Java输入/输出流体系中常用的流分类

    java输入/输出流体系中常用的流分类 分类 字节输入流 字节输出流 字符输入流 字符输出流 抽象基类 InputStream OutputStream Reader Writer 访问文件 File ...

  3. java输入流从指定字节读取,JAVA输入输出流-字节流篇

    当前位置:我的异常网» 综合 » JAVA输入输出流-字节流篇 JAVA输入输出流-字节流篇 www.myexceptions.net  网友分享于:2013-08-14  浏览:8次 JAVA输入输 ...

  4. java输出流缓冲区内容清除,Java输入输出流与缓冲区的使用

    Java输入输出流与缓冲区的使用,有需要的朋友可以参考下. 一,Input/Output流: 将外设中的数据读取到内存中就是输入. 将内存中的数据写入到外设中就是出. I/O流就是用来处理设备间的 . ...

  5. Java基础知识每日总结(19)---Java输入输出流、文件、递归

    输入输出流.文件.递归 在变量.数组和对象中存储数据是暂时的,程序结束后它们则会丢失.为了能够永久地保存程序创建的数据,需要将其保存在磁盘文件中.这样以后就可以在其他程序中使用它们.Java的I/O技 ...

  6. JAVA输入输出流学习心得

    JAVA输入输出流 本文主要从以下几个方面总结JAVA输入输出流 1.什么是流?什么是输入输出流? 2.字节流与字符流 3.Scanner 什么是流? 举个例子,水龙头里流出的水流就是流.从水龙头里流 ...

  7. Java中Steam流的用法及使用备忘

    文章目录 Java中Steam流的用法及使用备忘 一. 流的常用创建方法 1-1 使用Collection下的 stream() 和 parallelStream() 方法 1-2 使用Arrays ...

  8. JAVA输入输出流总结

    JAVA中的流按照数据流的流向分为输入输出流:按照数据处理的类型不同又分为字节流和字符流.下面就分别来进行说明. 字符流 一:输入流: java 中使用的字符输入流的基本类为Reader抽象类,通常实 ...

  9. 【java开发系列】—— java输入输出流

    前言 任何语言输入输出流都是很重要的部分,比如从一个文件读入内容,进行分析,或者输出到另一个文件等等,都需要文件流的操作.这里简单介绍下reader,wirter,inputstream,output ...

最新文章

  1. LeetCode 653. Two Sum IV - Input is a BST--Python解法
  2. Matcher类的简单使用
  3. sqlhelper中事务的简单用法(初学者)
  4. 设置 Xcode 自动生成代码片段
  5. 在Visual Studio中使用任何C++编译器
  6. 聊聊同步、异步、阻塞与非阻塞
  7. 超方便、最简单版本:java 邮件发送 (半分钟写完代码)
  8. hdu 2523 SORT AGAIN
  9. java中的等待_Java中更好的等待语法
  10. Javascript创建对象几种方法解析
  11. How to activate an Anaconda environment
  12. Java大厂面试题:从 JVM 角度说进程和线程之间的关系
  13. 初学者如何在CSDN写博客
  14. 加密狗Android软件,加密狗app
  15. 转帖:三种快乐物质——多巴胺、血清素、内啡肽
  16. bzoj 5369 最大前缀和
  17. [经验栈]C#与是德科技信号发生器(Keysight RF Signal Generators)N9310A通信操作
  18. Excel 2010 多个窗口独立同屏显示方法——修改注册表方法
  19. Android学习笔记_28_手势识别
  20. android studio 设备调试及Logcat查看

热门文章

  1. 基于图像的三维建模——特征点检测与匹配
  2. [BZOJ 3811]玛里苟斯(线性基)尽量理解的题解
  3. 小韩实操 -- Mysql数据库的备份与恢复及安全配置
  4. android plist表情,在iOS中的UITextView中不显示笑脸(表情符号)?
  5. 12.03-内存管理_Tagged Pointer
  6. docker启动容器之后马上又自动关闭解决办法
  7. 浏览器清理缓存快捷键
  8. oppop+r1c怎么设置语言中文,OPPO R1C怎么样 OPPO R1C手机评测 (全文)
  9. 苹果市场占有率_快手充值快快币苹果版
  10. Multi-Stage Progressive Image Restoration