Java输入/输出流

文章目录

  • Java输入/输出流
    • 一、流的概念
    • 二、I/O类体系
      • 2.1 字节流
      • 2.2 字符流
    • 三、文件流
      • 3.1 FileInputStream
      • 3.2 FileOutputStream
      • 3.3 FileReader
      • 3.4 FileWriter
    • 四、实体流和装饰流
    • 五、缓冲流
      • 5.1 缓冲字节流
      • 5.2 缓冲字符流
    • 六、数据流
    • 七、对象流与对象序列化
    • 八、标准输入/输出
    • 九、桥接流
    • 十、流的关闭
      • 10.1 finally中关闭流
      • 10.2 自动关闭流

一、流的概念

输入流只能读不能写,输出流只能写不能读。按照流中数据的处理单位不同,可将流分为字节流字符流。在字节流中,数据的组织和操作的基本单位是字节;在字符流中,数据的组织和操作的基本单位是字符。综上,流可分为字节输入流,字节输出流,字符输入流,字符输出流。

Java是面向对象的语言,使用类来表示各种流

使用流来进行数据输入的具体步骤为

  1. 创建适当的输入流类的对象,建立与输入设备(如磁盘或者文件)的连接
  2. 调用相应的read()方法读入数据
  3. 关闭流,释放相关的系统资源

使用流来进行数据输出的具体步骤为

  1. 创建适当的输出流类的对象,建立与输出设备(如屏幕或文件)的连接
  2. 调用相应的write()方法输出数据
  3. 关闭流,释放相关的系统资源

二、I/O类体系

为了实现对各种输入/输出设备的操作,Java提供了丰富的基于流的I/O类,这些类位于java.io包中。其中有四个抽象类尤为重要,分别是InputStream(字节输入流)类、OutputStream(字节输出流)类、Reader(字符输入流)类和Writer(字符输出流)类。所有字节流的类都是InputStream类或OutputStream类的子类,所有字符流的类都是Reader类或Writer类的子类。

2.1 字节流

2.2 字符流

三、文件流

File类的构造方法

方法原型 说明
public File(File parent, String child) 根据文件对象和字符串创建一个新的File实例
public File(String pathName) 根据路径名字符串创建一个新的File实例
public File(String parent, String child) 根据两个字符串创建一个新的File实例
public File(URL uri) 使用给定的统一资源定位符来创建一个新的File实例

File类的常用成员方法

方法原型 说明
public boolean exists() 判断文件是否存在,存在返回true,否则返回false
public boolean isFile() 判断是否为文件
public boolean isDirectory() 判断是否为目录
public String getName() 返回文件或者目录的名称
public String getAbsolutePath() 返回文件的绝对路径(包含文件名)
public long length() 如果是文件,返回文件的长度(字节数),如果是目录,返回值不确定
public boolean creatNewFile() throws IOException 创建新文件,若文件已存在,返回false;该方法只能创建文件,不能创建目录
public boolean delete() 删除当前文件或目录,如果为目录,则目录必须为空时才能删除
public String[] list() 返回当前目录下所有的文件和目录名称

3.1 FileInputStream

FileInputStream类继承于InputStream类,是进行文件读取操作的最基本的类,它的作用是将文件中的数据读入到内存中。

使用FileInputStream类读取文件内容的步骤为—>

//(1)创建流,将程序与文件连接起来,具体方法是实例化FileInputStream类的对象
FileInputStream fileInputStream = new FileInputStream("D:\\test\\data.txt");
//或者,
File myFile = new File("D:\\test\\data.txt");
FileInputStream fileInputStream = new FileInputStream(myFile);
//注意,创建流时,可能抛出异常,必须进行处理--------------------------------//(2)调用read()方法读取流中的数据,read()方法有如下三种形式,根据需要选用
public int read();
public int read(byte b[]);
public int read(byte[] b, int off, int len);//(3)读取完毕后要关闭流
fileInputStream.close();

【示例】文件字节输入流应用示例,从文本文件中读取数据并显示在屏幕上

public class Main {public static void main (String[] args) {try {File file = new File(".//great//data.txt");FileInputStream fileInputStream = new FileInputStream(file);char ch;for(int i = 0; i < file.length(); i++) {ch = (char)(fileInputStream.read());System.out.print(ch);}fileInputStream.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
}

字节流中数据操作的单位是字节。由于一个汉字占两个字节,因此使用字节流读写汉字时,可能出现乱码现象。

从文件中读取数据时,可以逐个字节读取,也可以一次读取多个字节存入字节数组中。以文件的长度来定义字节数组的长度,一次读取全部数据存入数组,修改后的代码为

byte[] buf = new byte[(int)(file.length())];   //定义字节数组,以文件的长度确定数组的长度
fileInputStream.read(buf);     //一次性读取文件所有数据存放到字节数组中
String str = new String(buf);  //利用字节数组创建字符串
System.out.println(str);       //将文件内容以字符串形式输出

当然,这种一次读取全部数据的方式只适合小文件,当读取较大文件时,宜采用分块读取的方式,即一次读取固定长度的数据,多次读取,到达文件尾时结束,读取数据的代码修改为

int n = 1024, count = 0;
byte[] buf = new byte[n];
while((count = fileInputStream.read(buf)) != -1) {  //读取数据粗如数组//将字节数组转换为字符串后输出System.out.print(new String(buf, 0, count));
}

3.2 FileOutputStream

创建FileOutputStream类的对象时,如果文件不存在,系统会自动创建该文件,但是当文件路径中包含不存在的目录时创建失败会抛出异常

使用FileOutputStream类将数据输出到文件的步骤为—>

/*(1)创建流,将程序与文件连接起来,具体方法是实例化FileOutputStream类的对象。将数据写入文件时,有覆盖和追加两种方式。覆盖是指清除文件的原有数据,写入新的数据;追加是指保留文件的原有数据,在原有数据的末尾写入新的数据。默认是覆盖方式(false)
*/
FileOutputStream fileOutputStream = new FileOutputStream("D:\\test\\data.txt");
//或者
File myFlie = new File("D:\\test\\data.txt");
FileOutputStream fileOutputStream = new FileOutputStream(myFile, true);
//注意,创建输出流时,可能抛出异常,必须进行处理-----------------------------------//(2)调用write()方法将数据输出到文件,write()方法有以下三种形式
public void write(int b);
public void write(byte b[]);
public void write(byte b[], int off, int len);//读取完毕后关闭流
fileOutputStream.close();

【示例】从键盘输入一串字符,并将其追加至文件中

public class Main {public static void main (String[] args) {Solution so = new Solution();System.out.println(""  );try {FileOutputStream fileOutputStream = new FileOutputStream(".\\great\\data.txt", true);System.out.println("请输入一行字符:");Scanner sc = new Scanner(System.in);String str = sc.nextLine();       //输入一行字符byte[] buffer = str.getBytes();   //将字符串转换为字节数组fileOutputStream.write(buffer);   //写入输入流fileOutputStream.close();         //关闭输入流} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
}

将逐个字符追加写入文件

String str = "Hello World!";for(int i = 0; i < str.length(); i++) {fileOutputStream.write(str.charAt(i));
}

3.3 FileReader

【示例】文件字符输入流示例

public class Main {public static void main (String[] args) throws IOException {Solution so = new Solution();System.out.println(""  );File file = new File(".//great//data.txt");FileReader fileReader = new FileReader(file);char ch;for(int i = 0; fileReader.ready(); i++) {ch = (char)(fileReader.read());System.out.print(ch);}fileReader.close();}
}

3.4 FileWriter

不同的操作系统下,回车换行符并不相同,调用System类的getProperty("line.separator")方法能够获取当前系统的回车换行符。但是在Windows系统下,回车换行符是"\r\n"。

【示例】文件字符输出流应用示例。输入多个字符串,以”#"结束,将这些字符串写入文件中,要求一个字符串占一行

public class Main {public static void main (String[] args) throws IOException {Solution so = new Solution();System.out.println(""  );FileWriter fileWriter = new FileWriter(".//great//data.txt", true);Scanner sc = new Scanner(System.in);String ch = System.getProperty("line.separator");while(!sc.hasNext("#")) {String str = sc.nextLine();fileWriter.write(str);fileWriter.write(ch);}fileWriter.close();System.out.println("已保存至.//great//data.txt");}
}

四、实体流和装饰流

按照是否直接连接实际数据源(例如文件)将流划分为实体流和装饰流。

实体流能够直接连接数据源,可单独使用实现对数据源的读写,如文件流。装饰流不能直接连接数据源,不能单独使用,必须在其他流(实体流或其他装饰流)的基础上使用。常用的有缓冲流、数据流和对象流等。例如访问文件,既可以只使用文件流来读写,也可以在文件流的基础上配合使用装饰流。

由于装饰流是在其他流的基础上创建的,这种创建流的方式称作“流的嵌套”。在流的嵌套中,各个流的性质必须相同,也就是流的读写单位(字节/字符)、流的方向(输入/输出)都要一致。装饰流不改变实体流中的数据内容,只是对实体流做了一些功能上的增强

五、缓冲流

使用缓冲流,当输入数据时,数据以块为单位读入缓冲区,此后如有读操作,则直接访问缓冲区;当输出数据时,先将数据写入缓冲区,当缓冲区的数据满时,才将缓冲区中的数据写入输出流中,提高了输入/输出的效率。

5.1 缓冲字节流

BufferedInputStream类是InputStream类的子类

列如,在文件流基础上使用缓冲流进行文件数据的读取,创建流的代码为

FileInputStream inOne = new FileInputStream("data.txt");    //创建文件流
BufferedInputStream inTwo = BufferedInputStream(intOne);    //以文件流为参数创建缓冲流

BufferedOutputStream类是OutputStream类的子类

BufferedOutputStream in = new BufferedOutputStream(new FileOutputStream("data.txt"));

5.2 缓冲字符流

BufferedReader类是Reader类的子类,增加了读取一行字符的方法readLine()

方法原型 说明
public BufferedReader(Reader in) 构造方法,创建具有默认大小缓冲区的缓冲字符输入流
public BufferedReader(Reader in, int size) 构造方法,创建具有指定缓冲区大小的缓冲字符输入流
public String readLine() throws IOException 从缓冲输入流中读取一行字符,以字符串的形式返回(不包括回车符),如果已到达流末尾,则返回null

BufferedWriter类是Writer类的子类

bw.write("\r\n")bw.newLine()等价

File file = new File("data.txt");
FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw);

六、数据流

Java提供了两个数据流类,DataInputStream和DataOutputStream,用来输入/输出各种类型的数据。使用数据流需要注意以下几点:

  • 数据流属于装饰流,不能单独使用
  • 使用DataOutputStream流输出的数据,必须使用DataInputStream流进行读取,这两个类必须配合使用,否则会发生数据错误。因为使用DataOutputStream流输出数据时,除了数据以外,还加上了特定的格式
  • 读取数据时,数据的类型和顺序必须与输出的数据的类型和顺序保持一致

下面只介绍数据输出流DataOutputStream类的方法,数据输入流相应的方法与之对应

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d0QXxa4u-1609296044884)(…\JAVA基础\great\DataOutputStream.png)]

【示例】读写学生信息

class StudentInfo {String name;int age;double score;StudentInfo(String name, int age, double score){this.name = name;this.age = age;this.score = score;}
}public class Main {public static void main (String[] args) throws IOException {StudentInfo[] stu = new StudentInfo[5];Scanner sc = new Scanner(System.in);//写入文件FileOutputStream fos = new FileOutputStream(".//great//data.txt");DataOutputStream dos = new DataOutputStream(fos);System.out.println("请输入学生的姓名、年龄、成绩:");for(int i = 0; i < 3; i++) {stu[i] = new StudentInfo(sc.next(), sc.nextInt(), sc.nextDouble());dos.writeUTF(stu[i].name);dos.writeInt(stu[i].age);dos.writeDouble(stu[i].score);}dos.close();     //关闭流//读出数据DataInputStream dis = new DataInputStream(new FileInputStream(".//great//data.txt"));System.out.println("文件中的内容:");for(int i = 0; i < 3; i++) {System.out.println(dis.readUTF() + " " + dis.readInt() + " " + dis.readDouble());}dis.close();}
}

七、对象流与对象序列化

对象序列化是指将一个对象的属性和方法转化为一种序列化的格式用于存储和传输。在需要的时候,再将对象重构出来,这个过程称为反序列化。若要将对象能够进行序列化,其所属的类必须实现Serializable接口。Serializable接口是一个空接口,不包含任何方法,实现这个接口只是一个标志,表示该类的对象可以进行序列化。Serializable接口在java.io包中

Serializable】接口

public Myclass implements Serializable {//----
}

对象序列化时,不保存对象的transient变量(临时变量)和static变量(静态变量)

同数据流一样,读取对象时,数据的类型和顺序必须与输出的数据的类型和顺序保持一致

Externalizable】接口

当实现序列化时,如果要自行确定哪些变量要保存,以及具体的顺序或者除了成员变量,还需要保存其他的数据,就要通过实现Externalizable接口来进行。

一个类实现Externalizable接口以后,当采用ObjectOutputStream流输出对象时,会自动调用writeExternal()方法,按照方法规定的逻辑保存对象数据。当采用ObjectInputStream流输入对象时,会自动调用readExternal()方法

示例】读写用户信息

class UserInfo implements Externalizable {public String userName;public String userPass;public int userAge;public UserInfo() {}public UserInfo(String username, String userpass, int userage) {this.userName = username;this.userPass = userpass;this.userAge = userage;}@Overridepublic void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {Date date = (Date)in.readObject();System.out.println(date);this.userName = (String)in.readObject();this.userAge  = in.readInt();}@Overridepublic void writeExternal(ObjectOutput out) throws IOException {Date date = new Date();out.writeObject(date);out.writeObject(userName);out.writeInt(userAge);}public String toString() {String str = "用户名: " + this.userName + ", 密码: " + this.userPass +", 年龄: " + this.userAge;return str;}
}public class Main {public static void main (String[] args) throws IOException, ClassNotFoundException {//写入文件(序列化)FileOutputStream fout = new FileOutputStream(".//great//data.txt");ObjectOutputStream oout = new ObjectOutputStream(fout);UserInfo user = new UserInfo("飞流", "123456", 18);oout.writeObject(user);oout.close();     //关闭流System.out.println("数据写入成功!");//读出数据(反序列化)FileInputStream fin = new FileInputStream(".//great//data.txt");ObjectInputStream oin = new ObjectInputStream(fin);UserInfo user1 = (UserInfo)oin.readObject();oin.close();System.out.println(user1.toString());}
}

八、标准输入/输出

System类功能强大,利用它可以获得很多Java运行时的系统信息。System类的属性和方法都是静态的,System.inSystem.out就是System类的两个静态属性,分别对应了系统的标准输入和标准输出。

System.in是InputStream类的对象,当程序需要从键盘输入数据时,只需要调用System.in.read()方法即可。不过要注意,System.in是字节对象流,只能输入字节类型的数据。System.out是PrintStream类的对象,有方法print(),println(),printf()可以输出各种类型的数据。

System.err是标准错误输出流。它是PrintStream类的对象,有两个方法print()和println(),调用这两个方法可以在屏幕上输出错误或者警示信息,如

System.err.println("IOException");

九、桥接流

在流的嵌套中,各个流的性质必须相同。为了解决InputStream和Reader两个体系流的嵌套问题,引入了InputStreamReaderOutputStreamWriter,用于实现字节流向字符流的转换,在字节流与字符流之间搭建了沟通的桥梁,这两个类被形象地称为“桥接流”

相应的构造方法如下

public InputStreamReader(InputStream in);     //将字节输入流转换为字符输入流
public OutputStreamWriter(OutputStream out);  //将字节输出流转换为字符输出流
//将字节流转换为字符流
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
//上述字符流效率较低,可以使用缓冲流来提高输入效率
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

【示例】将标准输入转换为字符流后再进行数据的输入

public class Main {public static void main (String[] args) throws IOException {//将字节流转换为字符流InputStreamReader inputStreamReader = new InputStreamReader(System.in);//上述字符流效率较低,可以使用缓冲流来提高输入效率BufferedReader bufferedReader = new BufferedReader(inputStreamReader);System.out.println("请输入学生姓名:");String name = bufferedReader.readLine();System.out.println("请输入学生成绩:");double score = Double.parseDouble(bufferedReader.readLine());bufferedReader.close();System.out.println("姓名: " + name + ", 成绩:" + score);}
}

十、流的关闭

10.1 finally中关闭流

在之前的例子中,流的声明,创建以及关闭都是在try块中进行的,如果在执行过程中抛出异常,那么流的关闭语句有可能得不到执行,无法释放占用的资源。在finally中关闭流,无论是否抛出异常流都会被关闭

InputStreamReader isr = null;
try {isr = new InputStreamReader(System.in);int x = (int)isr.read();//······
} catch (IOException e) {e.printStackTrace();
} finally {try {if(isr != null) isr.close();} catch (IOException e) {e.printStackTrace();}
}

10.2 自动关闭流

使用finally块程序显得有些冗长

try-with-resources语句的形式为

try (资源的声明和创建) {//使用资源
}
  • 在括号()内创建的资源对象在try块结束时会自动释放,不需要再显式调用close()方法
  • 在括号()内创建的资源对象时try块的局部变量,作用域只限于try块内部
  • 后面可接catch块和finally块
  • 只能用于实现了java.lang.AutoCloseable接口的那些资源。java.io.Closeable接口继承了AutoCloseable接口,所有流类都实现了这两个接口,可以使用try-with-resources语句
try(InputStreamReader isr = new InputStreamReader(System.in);BufferedReader br = new BufferedReader(isr)) {String str = br.readLine();//·······
} catch (IOException e) {e.printStackTrace();
}

try-with-resources语句不仅可以用于流的操作,也可以应用于数据库编程和网络编程中所涉及的资源,只要资源实现了AutoCloseable接口即可


参考资料:《Java语言程序设计实用教程》主编 王素琴

Java输入/输出流相关推荐

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

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

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

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

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

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

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

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

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

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

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

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

  7. Java输入输出流IO

    1.什么是IO Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列.Java的I/O流提供了读 ...

  8. Java输入输出流和文件操作

    操作系统中的文件和目录概念 文件与文件系统 文件是信息的一种组织形式,是存储在外部存储介质上的具有标志名的一组相关信息集合. 文件系统用文件概念来组织和管理存放在各种介质上的信息.文件系统提供目录机制 ...

  9. [转]Java输入输出流的使用详细介绍

    出处:http://www.jb51.net/article/36138.htm 1.什么是IO Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进 ...

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

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

最新文章

  1. python使用pyodbc连接sql server 2008
  2. strom-1.1.0模拟单词统计功能,Spout编写,Bolt编写,TopologyDriver编写,本地模式运行,集群模式运行,集群模式下看输出结果
  3. 解决css firefox火狐浏览器IE浏览器下的兼容性问题
  4. oracle部署--安装oracle软件与部署单实例数据库
  5. 小米员工疑似上手小米11新机:骁龙888首发在即
  6. 无盘服务器性能测试,无盘系统性能测试及结语
  7. 在Jupyter Notebook中调用ML模型服务图像标题生成器
  8. 操作系统—进程的定义、组成和组织方式(思维导图)
  9. 深入解析大数据虚拟化的架构(下)- 系统架构
  10. MYSQL initialize、install 、启动服务报错解决方法
  11. Android 开机Logo、铃声、震动修改方案
  12. 多卡聚合设备助力无人机监控盲区打好疫情阻击战
  13. 云计算之路-阿里云上:在乌云中坚信蓝天
  14. php 图片汉字命名_基于php上传图片重命名的6种解决方法的详细介绍
  15. Python爬虫方法三部曲之二-实战训练
  16. 文字图片在一行时候,图片居中问题
  17. 离谱,还有这种自暴自弃的翻译?
  18. 东方国信基于kubernetes构建容器云平台的实践和思考
  19. Linux安装MySQL(使用yum)
  20. 活体生物发光成像技术原理及应用

热门文章

  1. 数据库可疑的解决方案
  2. linux,内核(kernel)对AD9371配置流程。
  3. PHP验证码代码_php验证码类
  4. CAD插件学习系列教程(四) 一款轻量级的CAD里程标注插件
  5. android窗口动画和壁纸关系,Android壁纸管理(Android N)
  6. 附加:中半部分sql语句 区/县(数据表)
  7. 人工智能一种现代化学习方法——学习笔记(13章)
  8. python网页编辑器-Python Jupyter 网站编辑器
  9. 首届恩智浦智能车比赛回顾
  10. winrar分卷压缩_无广告的WinRAR解压软件