1、基本的输入流和输出流

流是 Java 中最重要的基本概念之一。文件读写、网络收发、进程通信,几乎所有需要输入输出的地方,都要用到流。

流是做什么用的呢?就是做输入输出用的。为什么输入输出要用“流”这种方式呢?因为程序输入输出的基本单位是字节,输入就是获取一串字节,输出就是发送一串字节。但是很多情况下,程序不可能接收所有的字节之后再进行处理,而是接收一点处理一点。比方你下载魔兽世界,不可能全部下载到内存里再保存到硬盘上,而是下载一点就保存一点。这时,流这种方式就非常适合。

在 Java 中,每个流都是一个对象。流分为两种:输入流(InputStream)和输出流(OutputStream)。对于输入流,你只要从流当中不停地把字节取出来就是了;而对于输出流,你只要把准备好的字节串传给它就行。

流对象是怎么获得的呢?不同的外部系统,获取流的方式也不同。例如,文件读写就要创建 FileInputStream/FileOutputStream 对象,而网络通信是通过 Socket 对象来获取输入输出流的。一般来说,如果一个类有 getInputStream() 或 getOutputStream() 这样的方法,就表明它是通过流对象来进行输入输出的。

InputStream 是输入流,下面是一个通过 InputStream 读取文件的例子:

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.FileNotFoundException;

import java.util.Arrays;

/**

* 通过流读取文件

*/

public class ReadFileDemo {

// 程序入口

public static void main(String[] args) {

String path = "c:/boot.ini";

File file = new File(path);

// 创建输入流

InputStream is;

try {

is = new FileInputStream(file);

} catch (FileNotFoundException e) {

System.err.println("文件 " + path + " 不存在。");

return;

}

// 开始读取

byte[] content = new byte[0]; // 保存读取出来的文件内容

byte[] buffer = new byte[10240]; // 定义缓存

try {

int eachTime = is.read(buffer); // 第一次读取。如果返回值为 -1 就表示没有内容可读了。

while (eachTime != -1) {

// 读取出来的内容放在 buffer 中,现在将其合并到 content。

content = concatByteArrays(content, buffer, eachTime);

eachTime = is.read(buffer); // 继续读取

}

} catch (IOException e) {

System.err.println("读取文件内容失败。");

e.printStackTrace();

} finally {

try {

is.close();

} catch (IOException e) {

// 这里的异常可以忽略不处理

}

}

// 输出文件内容

String contentStr = new String(content);

System.out.println(contentStr);

}

/**

* 合并两个字节串

*

* @param bytes1 字节串1

* @param bytes2 字节串2

* @param sizeOfBytes2 需要从 bytes2 中取出的长度

*

* @return bytes1 和 bytes2 中的前 sizeOfBytes2 个字节合并后的结果

*/

private static byte[] concatByteArrays(byte[] bytes1, byte[] bytes2, int sizeOfBytes2) {

byte[] result = Arrays.copyOf(bytes1, (bytes1.length + sizeOfBytes2));

System.arraycopy(bytes2, 0, result, bytes1.length, sizeOfBytes2);

return result;

}

}

虽然写得很啰嗦,但这确实是 InputStream 的基本用法。注意,这只是一个例子,说明如何从输入流中读取字节串。实际上,Java 提供更简单的方式来读取文本文件。以后将会介绍。

相比从流中读取,使用 OutputStream 输出则是非常简单的事情。下面是一个例子:

import java.io.OutputStream;

import java.io.FileOutputStream;

import java.io.File;

import java.io.IOException;

import java.util.Date;

/**

* 将当前日期保存到文件

*/

public class SaveFileDemo {

public static void main(String[] args) throws IOException {

String path = "c:/now.txt";

File file = new File(path);

if (!file.exists() && !file.createNewFile()) {

System.err.println("无法创建文件。");

return;

}

OutputStream os = new FileOutputStream(file); // 创建输出流(前提是文件存在)

os.write(new Date().toString().getBytes()); // 将当前时间写入文件

os.close(); // 必须关闭流,内容才会写入文件。

System.out.println("文件写入完成。");

}

}

Java 还提供其它的流操作方式,但它们都是对 InputStream 和 OutputStream 进行扩展或包装。所以这两个类是基础,必须要理解它们的使用。

2、Reader 和 Writer

介绍了 InputStream 和 OutputStream,接下来介绍 Reader 和 Writer。这两个类其实就是将 InputStream 和 OutputStream 包装了一下。不过它们处理的不是字节(byte),而是字符(char)。如果一个流当中的内容都是文本,那么用 Reader/Writer 处理起来会简单些。下面是一个用 Reader 读取文本文件的例子:

import java.io.FileReader;

import java.io.IOException;

import java.io.Reader;

/**

* 读取文本文件

*/

public class ReadTextFileDemo {

// 程序入口

public static void main(String[] args) {

String path = "c:/boot.ini";

String content = "";

try {

Reader reader = new FileReader(path);

char[] buffer = new char[10240];

int count;

while ((count = reader.read(buffer)) != -1) {

content += new String(buffer, 0, count);

}

} catch (IOException e) {

System.err.println("读取文件失败。");

e.printStackTrace();

}

System.out.println(content);

}

}

至于如何用 Writer 将文本内容写入文件,这里就不给出例子了,看官自己试着写一下吧。

上面这个例子,仍然不是读取文本文件最常用的方式。Java 提供 BufferedReader,我们通常用它来读取文本文件。下面是一个例子:

import java.io.BufferedReader;

import java.io.FileReader;

import java.io.IOException;

/**

* 用 BufferedReader 读取文本文件

*/

public class ReadTextDemo2 {

public static void main(String[] args) {

String path = "c:/boot.ini";

String content = "";

try {

BufferedReader reader = new BufferedReader(new FileReader(path));

String line;

while ((line = reader.readLine()) != null) {

content += line + "/n";

}

} catch (IOException e) {

System.err.println("读取文件失败。");

e.printStackTrace();

}

System.out.println(content);

}

}

3、对象序列化

对象序列化也是流应用的一个重要方面。序列化就是把一个对象转换成一串字节,既可以保存起来,也可以传给另外的 Java 程序使用。ObjectOutputStream 和 ObjectInputStream 就是专门用来进行序列化和反序列化的。下面就是一个简单的例子:

import java.io.ObjectOutputStream;

import java.io.FileOutputStream;

import java.io.File;

import java.io.IOException;

import java.io.Serializable;

import java.io.ObjectInputStream;

import java.io.FileInputStream;

import java.io.EOFException;

/**

* ObjectOutputStream/ObjectInputStream 示例。

* 这两个类分别用于序列化和反序列化。

*/

public class SerializationDemo {

public static void main(String[] args) throws Exception {

String path = "c:/persons.data";

File f = new File(path);

if (!f.exists()) {

f.createNewFile();

}

writePersons(path);

readPersons(path);

}

// 从指定的文件中读取 Person 对象

private static void readPersons(String path) throws IOException, ClassNotFoundException {

ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));

Person p;

while (true) {

try {

p = (Person) ois.readObject();

System.out.println(p);

} catch (EOFException e) {

break;

}

}

}

// 将 Person 对象保存到指定的文件中

private static void writePersons(String path) throws IOException {

Person[] persons = new Person[]{

new Person("张三", 23),

new Person("李四", 24)

};

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));

for (Person person : persons) {

oos.writeObject(person);

}

oos.close();

}

///

private static class Person implements Serializable {

private String name;

private int age;

public Person() {

}

public Person(String name, int age) {

this.name = name;

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

@Override

public String toString() {

return "Person{" +

"name='" + name + '/'' +

", age=" + age +

'}';

}

}

}

这个例子里面看不到字节和字符的读写,因为这两个类都包装好了。上面只是一个简单的例子,序列化要写好的话还是有不少讲究的。想深入了解序列化,可以看看这里。本文只关注跟流有关的部分。其实序列化用的很少,因为序列化降低了灵活性,所以可以不用的话一般都不会用。

java 流的概念_举例讲解Java中的Stream流概念相关推荐

  1. java 内部类 加载_举例讲解Java的内部类与类的加载器

    内部类 class A { //Inner1 要在 A 初始化后 才能使用,即要被A的对象所调用 class Inner1 { int k = 0; // static int j = 0; //A加 ...

  2. java自旋锁使用_实例讲解Java 自旋锁

    一直以来不是怎么清楚自旋锁,最近有点时间,好好的学习了一下: 所谓的自旋锁在我的理解就是多个线程在尝试获取锁的时候,其中一个线程获取锁之后,其他的线程都处在一直尝试获取锁的状态,不会阻塞!!!那么什么 ...

  3. java 动态调用函数_深入讲解Java语言中的函数动态调用方式

    相 信 有 不 少 人 使 用C 语 言 的 函 数 指 针 实 现 过 函 数 的 动 态 调 用. 适 当 地 运 用 函 数 动 态 调 用 功 能 不 仅 能 减 少 代 码 数 量, 而 且 ...

  4. java 自定义语言 解析_视频讲解 Java 语言基础编程题(自定义异常类,IO 流)

    第一题>点击这里查看学生信息管理系统的视频讲解知乎视频​www.zhihu.com 基于学生信息管理系统增加以下两个功能:自定义学号异常类和年龄异常类,并在该成员变量不合理时产生异常对象并抛出. ...

  5. java pdf添加图章_实例讲解Java处理PDF图章的方法

    图章(印章)是一种在合同.票据.公文等文件中表明法律效应.部门机关权威的重要指示物,常见于各种格式的文件.文档中.对于纸质文档可以手动盖章,但对于电子文档,则需要通过特定的方法来实现.本篇文档分享通过 ...

  6. python中的运算符举例_举例讲解Python中的身份运算符的使用方法

    Python身份运算符 身份运算符用于比较两个对象的存储单元 以下实例演示了Python所有身份运算符的操作: #!/usr/bin/python a = 20 b = 20 if ( a is b ...

  7. python中的运算符举例_举例讲解Python中的算数运算符的用法

    下表列出了所有Python语言支持的算术运算符.假设变量a持有10和变量b持有20,则: 例子: 试试下面的例子就明白了所有的Python编程语言提供了算术运算符: #!/usr/bin/python ...

  8. 请举例说明python中**运算符的含义_举例讲解Python中的身份运算符的使用方法

    Python身份运算符 身份运算符用于比较两个对象的存储单元 以下实例演示了Python所有身份运算符的操作: #!/usr/bin/python a = 20 b = 20 if ( a is b ...

  9. python运算符讲解_举例讲解Python中的算数运算符的用法

    下表列出了所有Python语言支持的算术运算符.假设变量a持有10和变量b持有20,则: 例子: 试试下面的例子就明白了所有的Python编程语言提供了算术运算符: #!/usr/bin/python ...

最新文章

  1. Kali渗透测试——UPNP网关发现工具Miranda
  2. java 字符串用法_java中字符串的用法
  3. Laravel_post访问【419】问题解决方法
  4. C语言 - strcpy和strncpy的编程实现及总结
  5. 与敏捷团队一起交付价值
  6. SoX-linux里操作音频的瑞士×××
  7. Struts2中4个核心组件_笔记
  8. 芝加哥大学终身教授:自然科学与社会科学的真正区别
  9. 服务器虚拟化cas,CAS虚拟化建设方案
  10. 物联网标识管理系统源码
  11. swfobject java_[Java教程]swfobject.js视频播放插件
  12. AliExpress国际速卖通唰信誉用什么虚拟卡用信可以成功扣款?
  13. 【单片机笔记】PWM信号与PPM信号简单理解
  14. 最近学到一个新词“汽车含硅量”
  15. 二十世纪初的心理学时间轴制作
  16. 关于ubuntu的详细介绍
  17. 破解“无法复制粘贴”
  18. 计算机图形学常用算法实现11 扫描线z-buffer算法
  19. Symtavision—分布式嵌入式系统时间建模分析和验证工具
  20. 【半导体先进工艺制程技术系列】SOI技术(上)

热门文章

  1. idea中项目失去svn控制
  2. G6实现标签拖动连线画流程图
  3. web站点的欢迎页面
  4. 客快物流大数据项目(六十二):主题及指标开发
  5. 2021年大数据Spark(八):环境搭建集群模式 Standalone HA
  6. TS中的感叹号和问号的用法
  7. ASP.NET MVC 2示例Tailspin Travel
  8. jenkins ssl证书报错问题解决
  9. 根据进程名杀死进程 -kill进程名
  10. 洛谷P1550 [USACO08OCT]打井Watering Hole