目录
字节数组输入流(ByteArrayInputStream)实例
字节数组输出流(ByteArrayOutputStream)
字节数组输出流(ByteArrayOutputStream)实例
前言
Java不是在语言层面上对输入/输出提供支持,而是将这个任务交由类库来完成,这样类库可以充分、灵活地运用各种输入/输出技术。输入/输出是程序与用户之间沟通的桥梁,程序从外界获得数据称为输入,程序将运算结果等信息传递给外界称为输出,Java的输入、输出是以流的方式来进行处理的,那么什么是流,流是怎样来处理输入、输出的呢,今天我们来学习Java中的输入/输出流。
流的概念
在Java中,把一组有序的数据序列称为流,流系列中的数据有未经加工的原始二进制数据,也有经过特定包装过滤处理的格式数据。
流式输入、输出特点是数据的获得和发送均沿数据序列顺序进行。
输出流是向存储介质或数据通道中写入数据,而输入流是从存储介质或数据通道中读取数据,如下图所示:
流的特性:
- 先进先出:最先用输出流写入存储介质的数据最先被输入流读取到;
- 顺序存取:写入和读取流数据均按顺序逐个字节进行,不能随机访问中间的数据;
- 只读或只写:每个流只能是输入流或输出流的一种,不能同时具备两个功能。
Java API提供了两套流来处理输入/输出来满足不同性质的输入/输出需要:
- 面向字节的流:数据的处理是以字节为基本单位;
- 面向字符的流:用于字符数据的处理。
注意:为了满足字符的国际化表示要求,Java的字符编码是采用16位表示一个字符的Unicode码,而普通的文本文件中采用的是8位的ASCII码。
Java系统定义了以下3个可以直接使用的流对象:
- 标准输入(System.in):InputStream类型,通常代表键盘输入;
- 标准输出(System.out):PrintStream类型,通常写往显示器;
- 标准错误输出(System.err):PrintStream类型,通常写往显示器。
在Java中使用字节流和字符流的步骤基本相同,以输出流为例:
- 创建一个与数据源相关的流对象;
- 利用流对象的方法往流写入数据;
- 执行close()方法关闭流。
I/O设备与文件
计算机外部设备分为两类:存储设备与输入/输出设备。
- 存储设备:包括硬盘、软盘、光盘等,数据以文件的形式进行组织;
- 输入/输出设备:输入设备(键盘、鼠标、扫描仪等)和输出设备(显示器、打印机、绘图仪等),从数据操作的角度,文件内容可以是字节的序列;
根据数据的组织方式,文件可以分为文本文件和二进制文件。
- 文本文件:存放的是ASCII码(或其他编码)表示的字符;
- 二进制文件:具有特定结果的字节数据。
面向字节的输入流
InputStream类
在java.io包中,InputStream类表示字节输入流,它是抽象类,不能实例化,其作用是用来表示那些从不同数据源产生输入的类。
面向字节的输入流类都是类InputStream的子类,如下图:
类InputStream定义了以下方法:
- public int read():读一个字节,返回读到字节的int表示方式,读到流的未尾时返回-1;
- public int read(byte b[]):读多个字节数组,返回结果为读到的实际字节个数,当输入流中无数据可读时返回-1;
- public int read(byte[] b,int off,int count):从输入流读count个字节到字节数组,数据从数组的off处开始存放,当输入流中无数据可读时返回-1;
- public long skip(long n):指针跳过n个字节,定位输入位置指针的方法;
- public void mark():在当前位置指针处做一标记;
- public void reset():将位置指针返回标记处;
- publicvoid close():关闭流。
数据的读取通常是按照顺序逐个字节进行访问,在某些特殊情况下,要重复处理某个字节可通过mark()加标记,以后用reset()返回该标记处再处理。
类InputStream的子类的使用
类InputStream的主要子类及功能如下表:
类名 | 构造方法的主要参数 | 功能描述 |
---|---|---|
ByteArrayInputStream | 字节数组 | 以程序中的一个字节组作为输入源,通常用于对字节数组中的数据进行转换 |
FileInputStream | 类File的对象或字符串表示的文件名 | 以文件作为数据源,用于实现对磁盘文件中数据的读取 |
PipedInputStream | PipedOutputStream的对象 | 与另一输出管道相连,读取写入输出管道中的数据,用于程序中线程间通信 |
FilterInputStream | InputStream的对象 | 用于装饰另一输入流以提供对输入数据的附加处理功能 |
SequeueInputStream | 一系列InputStream的对象 | 将两个其他流首尾相接,合并为一个完整的输入流 |
ObjectInputStream | InputStream的对象 | 用于从输入流读取串行化对象,可实现轻量级对象持久性 |
类FilterInputStream的常见子类及功能
类名 | 功能描述 |
---|---|
BufferedInputStream | 为所装饰的输入流提供缓存区的功能,以提高输入数据的效率 |
DataInputStream | 为所装饰的输入流提供数据转换功能,可从数据源读取各种基本类型的数据 |
LineNumberInputStream | 为文本文件输入流附加行号 |
PushbackInputStream | 提供回压数据的功能,可以多次读取同样数据 |
文件输入流(FileInputStream)
FileInputStream类用于从二进制文件读取数据,它的对象可以用关键字 new 来创建,构造方法为:
- FileInputStream(File file):打开一个到实际文件的连接来创建文件输入流,该文件通过文件系统的File对象指定;
- FileInputStream(String name):打开一个到实际文件的连接来创建文件输入流,该文件通过文件系统的路径名name指定。
文件输入流(FileInputStream)实例
例如:在屏幕上显示文件内容:
import java.io.*;
public class first {
public static void main(String[] args) throws Exception{
try {
FileInputStream file=new FileInputStream("e:/新建文本文档.txt"); //创建一个FileInputStream类实例对象file
int byteRead=file.read(); //创建一个byteRead变量存储读一个字节
while(byteRead!=-1) { //如果返回值不是-1则继续执行file的读操作
System.out.print((char)byteRead); //将int类型转换为char类型并输出
byteRead=file.read();
}
}catch(ArrayIndexOutOfBoundsException e) { //访问数组元素下标越界的异常
System.out.println("要一个文件名作为命令行参数!");
}catch(FileNotFoundException e) { //访问文件不存在的异常
System.out.println("文件不存在");
}catch(IOException e) {} //输入输出异常
}
}
注意:读到文件结尾时read方法返回-1,编程时可以利用该特点来组织循环,从文件的第一个字节一直读到最后一个字节。
字节数组输入流(ByteArrayInputStream)
ByteArrayInputStream类从内存的字节数组中读取数据(数据源是一个字节数组),它本身采用适配器设计模式,把字节数组转换为输入流类型,使程序能对字节数组进行读操作。
字节数组输入流(ByteArrayInputStream)实例
使用ByteArrayInputStream类读取数组中的字节
import java.io.*;
public class first {
public static void main(String[] args) throws Exception{
String str="123456789qwerty"; //创建一个字符串变量
byte[]strBuf=str.getBytes(); //把字符串转换为字节数组
ByteArrayInputStream bais=new ByteArrayInputStream(strBuf); //创建一个字节数组流对象
int data=bais.read(); //从字节数组输入流读取字节
while(data!=-1) {
char upper=Character.toUpperCase((char)data); //小写转换为大写
System.out.print(upper+" ");
data=bais.read(); //读取字节
}
bais.close(); //关闭字节数组输入流
}
}
运行结果为:
1 2 3 4 5 6 7 8 9 Q W E R T Y
数据输入流(DataInputStream)
DataInputStream类的所有读方法都以“read”开头,具体如下:
- readByte():从输入流中读取1个字节,把它转换为byte类型的数据;
- readFloat():从输入流中读取4个字节,把它转换为float类型的数据;
- readLong():从输入流中读取8个字节,把它转换为Long类型的数据;
- readUTF():从输入流中读取若干字节,把它转换为UTF-8编码的字符串。
我们发现在数据输出流(DataOutputStream)实例中写入的文件,会发现是一些乱码,原因是在于该文件中的数据不是文本格式的数据,要读取其中的数据需要以输入流的方式访问文件,用DataInputStream的readInt方法读取对应数据。
数据输入流(DataInputStream)实例
import java.io.*;
public class first {
public static void main(String[] args) throws Exception{
try {
FileInputStream file=new FileInputStream("d:/x.txt");
DataInputStream in=new DataInputStream(file);
while(true) {
int n1=in.readInt();
int n2=in.readInt();
System.out.println(n1+","+n2);
}
}catch(EOFException e) {}
catch(IOException e) {}
}
}
运行结果为:
11,13
17,19
29,31
41,43
59,61
71,73
面向字节的输出流
面向字节的输出流都是类OutputStream的后代类,如下图:
类OutputStream是一个抽象类,含一套所有输出流均需要的方法:
- public void write(int b):将参数b的低字节写入输出流;
- public void write(byte b[]):将字节数组全部写入输出流;
- public void write(byte b[],int off,int count):将字节数组从off处开始的count个字节数据写入输出流;
- public void flush():强制将缓冲区数据写入输出流对应的外设;
- public void close():关闭输出流。
文件输出流(FileOutputStream)
FileOutputStream类用于向二进制文件写入数据,构造方法为:
- FileOutputStream(String name ,boolean append):创建一个向指定名字的文件中写入数据的流,若第二个参数为true,则以添加方式写入字节,文件中原有的内容不会被清除;
- FileOutputStream(File file,boolean):创建一个向指定File对象表示的文件中写入数据流,若第二个参数为true,则将字节写入文件末尾而不是文件开始处。
文件输出流(FileOutputStream)实例
使用文件输出流将100~200之间能被3整除的数写到文本文件中,要求每10个数一行
import java.io.*;
public class first {
public static void main(String[] args) throws Exception{
int n,num,i=0;
try {
FileOutputStream fos=new FileOutputStream("D:/t.txt",true);
for(n=100;n<=200;n++) {
if(n%3==0) {
i++;
String str=String.valueOf(n);
String str1=str+" ";
byte[]buff=str1.getBytes();
fos.write(buff);
if(i%10==0) {
str="\r\n";
byte[]buf=str.getBytes();
fos.write(buf);
}
}
}
fos.close();
}catch(FileNotFoundException e1) {
System.out.println(e1);
}catch(IOException e2) {
System.out.println(e2);
}
}
}
运行结果为:
字节数组输出流(ByteArrayOutputStream)
ByteArrayOutputStream类向内存的字节数组写入数据,它也采用了适配器设计模式,把字节数组类型转换为输出流类型,使程序能对字节数组进行写操作。其构造方法为:
- ByteArrayOutputStream():创建一个新的字节数组输出流;
- ByteArrayOutputStream(int size):创建指定大小缓冲区的字节数组输出流。
字节数组输出流(ByteArrayOutputStream)实例
import java.io.*;
public class first {
public static void main(String[] args) throws Exception{
ByteArrayOutputStream baos=new ByteArrayOutputStream();
String s="Welcome to java";
byte[]buf=s.getBytes();
baos.write(buf);
System.out.println(baos.toString());
byte[]b=baos.toByteArray();
for(int i=0;i<b.length;i++) {
System.out.print((char)b[i]);
}
}
}
运行结果为:
Welcome to java
Welcome to java
数据输出流类(DataOutputStream)
类DataOutputStream实现各种基本类型数据的输出处理,它实现了DataOutput接口,在该接口中定义了基本类型数据的输出方法。
DataOutputStream类的所有方法都以“write”开头,具体如下:
- writeByte():向输出流中写入byte类型的数据;
- writeLong():向输出流中写入Long类型的数据;
- writeFloat():向输出流中写入float类型的数据;
- writeUTF():向输出流中写入UTF-8编码的数据。
其中,writeBytes、writeChars、writeUTF这3个方法均是以字符串作为参数,但它们的数据写入结果不同,writeBytes是按字节写入数据,它会丢弃掉字符的高8位,所以,不适合处理汉字。writeChars是按字符写入数据。writeUTF是按UTF-8字符编码写入数据。
数据流类(DataOutputStream)实例
找出10~100之间的所有姐妹素数,写入文件中。所谓姐妹素数,是指相邻两个奇数均为素数。
import java.io.*;
public class first {
public static boolean isPrime(int n) {
for(int k=2;k<=Math.sqrt(n);k++) {
if(n%k==0)
return false;
}
return true;
}
public static void main(String[] args) throws Exception{
try {
FileOutputStream file=new FileOutputStream("D:/x.txt");
DataOutputStream out=new DataOutputStream(file);
for(int n=11;n<100;n+=2) {
if(isPrime(n)&&isPrime(n+2)) { //两个相邻奇数是否为素数
out.writeInt(n); //将素数写入文件
out.writeInt(n+2);
}
}
out.close();
}catch(IOException e) {}
}
}
运行结果为:
最后
好了,关于Java I/O流——面向字节的输入/输出流的知识学到这里,谢谢观看!!!
我们下篇文章再见!!!
成功不是将来才有的,而是从决定去做的那一刻起,持续累积而成。