什么是 Java 输入输出流?流的用法大全
博主声明:
转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。
本文首发于此 博主:威威喵 | 博客主页: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 输入输出流?流的用法大全相关推荐
- java实验10流_实验9 Java输入输出流
<实验9 Java输入输出流>由会员分享,可在线阅读,更多相关<实验9 Java输入输出流(14页珍藏版)>请在金锄头文库上搜索. 1.山 西 大 学 计 算 机 与 信 息 ...
- Java输入/输出流体系中常用的流分类
java输入/输出流体系中常用的流分类 分类 字节输入流 字节输出流 字符输入流 字符输出流 抽象基类 InputStream OutputStream Reader Writer 访问文件 File ...
- java输入流从指定字节读取,JAVA输入输出流-字节流篇
当前位置:我的异常网» 综合 » JAVA输入输出流-字节流篇 JAVA输入输出流-字节流篇 www.myexceptions.net 网友分享于:2013-08-14 浏览:8次 JAVA输入输 ...
- java输出流缓冲区内容清除,Java输入输出流与缓冲区的使用
Java输入输出流与缓冲区的使用,有需要的朋友可以参考下. 一,Input/Output流: 将外设中的数据读取到内存中就是输入. 将内存中的数据写入到外设中就是出. I/O流就是用来处理设备间的 . ...
- Java基础知识每日总结(19)---Java输入输出流、文件、递归
输入输出流.文件.递归 在变量.数组和对象中存储数据是暂时的,程序结束后它们则会丢失.为了能够永久地保存程序创建的数据,需要将其保存在磁盘文件中.这样以后就可以在其他程序中使用它们.Java的I/O技 ...
- JAVA输入输出流学习心得
JAVA输入输出流 本文主要从以下几个方面总结JAVA输入输出流 1.什么是流?什么是输入输出流? 2.字节流与字符流 3.Scanner 什么是流? 举个例子,水龙头里流出的水流就是流.从水龙头里流 ...
- Java中Steam流的用法及使用备忘
文章目录 Java中Steam流的用法及使用备忘 一. 流的常用创建方法 1-1 使用Collection下的 stream() 和 parallelStream() 方法 1-2 使用Arrays ...
- JAVA输入输出流总结
JAVA中的流按照数据流的流向分为输入输出流:按照数据处理的类型不同又分为字节流和字符流.下面就分别来进行说明. 字符流 一:输入流: java 中使用的字符输入流的基本类为Reader抽象类,通常实 ...
- 【java开发系列】—— java输入输出流
前言 任何语言输入输出流都是很重要的部分,比如从一个文件读入内容,进行分析,或者输出到另一个文件等等,都需要文件流的操作.这里简单介绍下reader,wirter,inputstream,output ...
最新文章
- LeetCode 653. Two Sum IV - Input is a BST--Python解法
- Matcher类的简单使用
- sqlhelper中事务的简单用法(初学者)
- 设置 Xcode 自动生成代码片段
- 在Visual Studio中使用任何C++编译器
- 聊聊同步、异步、阻塞与非阻塞
- 超方便、最简单版本:java 邮件发送 (半分钟写完代码)
- hdu 2523 SORT AGAIN
- java中的等待_Java中更好的等待语法
- Javascript创建对象几种方法解析
- How to activate an Anaconda environment
- Java大厂面试题:从 JVM 角度说进程和线程之间的关系
- 初学者如何在CSDN写博客
- 加密狗Android软件,加密狗app
- 转帖:三种快乐物质——多巴胺、血清素、内啡肽
- bzoj 5369 最大前缀和
- [经验栈]C#与是德科技信号发生器(Keysight RF Signal Generators)N9310A通信操作
- Excel 2010 多个窗口独立同屏显示方法——修改注册表方法
- Android学习笔记_28_手势识别
- android studio 设备调试及Logcat查看
热门文章
- 基于图像的三维建模——特征点检测与匹配
- [BZOJ 3811]玛里苟斯(线性基)尽量理解的题解
- 小韩实操 -- Mysql数据库的备份与恢复及安全配置
- android plist表情,在iOS中的UITextView中不显示笑脸(表情符号)?
- 12.03-内存管理_Tagged Pointer
- docker启动容器之后马上又自动关闭解决办法
- 浏览器清理缓存快捷键
- oppop+r1c怎么设置语言中文,OPPO R1C怎么样 OPPO R1C手机评测 (全文)
- 苹果市场占有率_快手充值快快币苹果版
- Multi-Stage Progressive Image Restoration