近日做了老师布置的Java作业,其中有不少关于I/O流的内容,做起来发现一头雾水,于是上网找了一些资料,做些简单总结.
首先说一下数据流的概念,数据流就是连续不断的数据集合,当数据写入程序或者从程序输出时,数据会按先后顺序形成数据流,所以在用流读取或者写入时,我们也是按顺序的。数据流有起点终点,起点终点可以是文件,内存,或者网络连接。
数据流分类:
(1)字节流:即数据流中最小单位是字节(byte)。
(2)字符流:数据中最小单位是字符,Java中的Unicode编码一个字符占两个字节。
I/O体系又分为流式和非流式,如下图:
以上是常用的主要类,功能简述如下:
- File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。
- InputStream(字节流,二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。
- OutputStream(字节流,二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。
- Reader(字符流,文本格式操作):抽象类,基于字符的输入操作。
- Writer(字符流,文本格式操作):抽象类,基于字符的输出操作。
- RandomAccessFile(随机文件操作):它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。
I/O流
由上图不难得知,流中主要处理以下几个类型:文件(File衍生类),字节数组(Byte相关衍生类),字符数组(Char衍生类),字符串(String相关),而网络数据流各个子类都会参与其中。
InputStream
InputStream 为字节输入流,它本身为一个抽象类,必须依靠其子类实现各种功能,此抽象类是表示字节输入流的所有类的超类。 继承自InputStream 的流都是向程序中输入数据的,且数据单位为字节(8bit);
InputStream中有三种重载的read方法用于读取数据:
- public abstract int read( ):读取一个byte的数据,返回值是高位补0的int类型值。若返回值=-1说明没有读取到任何字节读取工作结束。
- public int read(byte b[ ]):读取b.length个字节的数据放到b数组中。返回值是读取的字节数。该方法实际上是调用下一个方法实现的
- public int read(byte b[ ], int off, int len):从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中。
- public int available( ):返回输入流中可以读取的字节数。注意:若输入阻塞,当前线程将被挂起,如果InputStream对象调用这个方法的话,它只会返回0,这个方法必须由继承InputStream类的子类对象调用才有用,
- public long skip(long n):忽略输入流中的n个字节,返回值是实际忽略的字节数, 跳过一些字节来读取
- public int close( ) :使用完后,必须对我们打开的流进行关闭。
几个子类的作用简介:
- FileInputStream:把一个文件作为InputStream,实现对文件的读取操作
- ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用
- StringBufferInputStream:把一个String对象作为InputStream
- PipedInputStream:实现了pipe的概念,主要在线程中使用
- SequenceInputStream:把多个InputStream合并为一个InputStream
- FilterInputStream :用来“封装其它的输入流,并为它们提供额外的功能”。
OutputStream
与InputStream相对应,有三个重载的write方法,用于数据的输出
- public void write(byte b[ ]):将参数b中的字节写到输出流。
- public void write(byte b[ ], int off, int len) :将参数b的从偏移量off开始的len个字节写到输出流。
- public abstract void write(int b) :先将int转换为byte类型,把低字节写入到输出流中。
- public void flush( ) : 将数据缓冲区中数据全部输出,并清空缓冲区。
- public void close( ) : 关闭输出流并释放与流相关的系统资源。
几个子类作用简介:
- FileOutputStream:把信息存入文件中
- ByteArrayOutputStream:把信息存入内存中的一个缓冲区中
- StringBufferOutputStream:把一个String对象作为InputStream
- PipedOutputStream:实现了pipe的概念,主要在线程中使用
- SequenceOutputStream:把多个OutStream合并为一个OutStream
- FilterOutputStream :用来“封装其它的输出流,并为它们提供额外的功能”。
以上FilterOutputStream本身也是一个超类,其中的缓冲流BufferedOutputStream和BufferedInputStream在读写数据时减少直接访问数据源的次数,提高效率。
创建BufferedInputStream类对象格式:
InputStream is=new BufferedInputStream(InputStream in); //默认缓冲区,大小为8192字节
InputStream is=new BufferedInputStream(InputStream in,int size); //自定义缓冲区,大小为size
BufferedOutputStream创建格式与上方大同小异。
Reader类和Writer类用法和上面两种差不多,若要处理的对象全都是文本数据则可以选用字符流,字节流通用。
有两个需要注意的:
- InputStreamReader : 从输入流读取字节,在将它们转换成字符。
- BufferReader :接受Reader对象作为参数,并对其添加字符缓冲器,使用readline()方法可以读取一行。
如何选择I/O流
- 确定是输入还是输出
输入:输入流 InputStream Reader
输出:输出流 OutputStream Writer - 明确操作的数据对象是否是纯文本
是:字符流 Reader,Writer
否:字节流 InputStream,OutputStream - 明确具体的设备。
- 文件:
读:FileInputStream,, FileReader,
写:FileOutputStream,FileWriter - 数组:
byte[ ]:ByteArrayInputStream, ByteArrayOutputStream
char[ ]:CharArrayReader, CharArrayWriter - String:
StringBufferInputStream(已过时,因为其只能用于String的每个字符都是8位的字符串), StringReader, StringWriter - Socket流
键盘:用System.in(是一个InputStream对象)读取,用System.out(是一个OutoutStream对象)打印
- 文件:
- 是否需要转换流
是,就使用转换流,从Stream转化为Reader、Writer:InputStreamReader,OutputStreamWriter - 是否需要缓冲提高效率
是就加上Buffered:BufferedInputStream, BufferedOuputStream, BufferedReader, BufferedWriter
RandomAccessFile使用示例
import java.io.*;
import java.util.Scanner;
class FileCopy {
public static void main(String[] args) throws IOException {
Scanner scan=new Scanner(System.in);
System.out.println("请输入源文件名和目标文件名:");
String oldFileName=scan.nextLine();
String newFileName=scan.nextLine();
File oldFile=new File("C:\\Users\\lee\\Desktop",oldFileName);
File newFile=new File("C:\\Users\\lee\\Desktop",newFileName);
try {
RandomAccessFile rfile=new RandomAccessFile(oldFile,"r");
RandomAccessFile nfile=new RandomAccessFile(newFile,"rw");
int d=-1;
while((d=rfile.read())!=-1) {
nfile.write(d);
}
rfile.close();
nfile.close();
}catch(FileNotFoundException e){
System.out.println("找不到文件");
}
}
}
BufferedInputStream使用示例
import java.io.*;
import java.util.Scanner;
public class testBufferInputStream {
public static void main(String[] args) {
// TODO 自动生成的方法存根
File file=new File("C:\\Users\\lee\\Desktop","BufferInput.txt");
String a;
Scanner scan=new Scanner(System.in);
BufferedOutputStream fos ;
try {
fos=new BufferedOutputStream(new FileOutputStream(file));
System.out.println("请输入字符:");
while(!"quit".equals((a=scan.nextLine()))) {
System.out.println("请输入字符:");
fos.write(a.getBytes());
fos.flush();
}
fos.close();
} catch (FileNotFoundException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}catch(IOException e) {
e.getMessage();
}
}
}