一、流的概念
流是指计算机各部件之间的数据流动。按照数据的传输方法,流可以分为输入流与输出流。从流的内容上划分,流分为字节流和字符流。
- 输入输出流
在Java语言中,把不同类型的输入输出源(键盘,屏幕等)抽象为流,其中输入或输出的数据被称为数据流。数据流分为输入流和输出流,从外设或外存传递到应用程序的流称为输入流,将数据从应用程序传递到外设或外存的流称为输出流。输入流只可以从其中读取数据,输出流只可以向其中写入数据。 - 缓冲流
对数据流的每次操作若都是以字节为单位进行操作,那么数据的传输效率显然很低,所以为了提高数据的传输效率,通常使用缓冲流(buffered stream
),即为一个流配有一个缓冲区(buffer
),这个缓冲区就是专门用于传送数据的一块内存。
当向一个缓冲流写入数据时,系统将数据发送到缓冲区,而不是直接发送到外部设备。缓冲区自动记录数据,当缓冲区满时,系统会将数据全部发送到相应的外部设备。
当从一个缓冲流读取数据时,系统实际是从缓冲区中读取数据,当缓冲区空时,系统就会从相关外部设备自动读取数据,并读取尽可能多的数据填满缓冲区,由此可见,缓冲区提高了内存与外部设备之间的数据传输效率。
二、输入输出流类库
为了方便流的处理,Java语言的流类都封装在java.io包之中,所以要是用流类,必须导入java.io包。
按照处理的数据单位分为字节流和字符流。
- 字节流:操作的数据单元是8位字节,
InputStream
、OutputStream
作为抽象基类。 - 字符流:操作的数据单元是字符,
Writer
、Reader
作为抽象基类。 - 字节流可以处理所有的数据文件,但是若处理纯文本数据,建议使用字符流。
三、使用InputStream
和OutputStream
流类
InputStream
和OutputStream
流类是Java语言中用来处理以位(bit)为单位的流,它除了可以用来处理二进制文件(binary file
)的数据以外,也可以用来处理文本文件。
**注意:虽然说字节流可以操作文本文件,但是并不提倡这样做,因为字节流操作文本文件,若是文件中有汉字,可能会出现乱码,这是因为字节流不能够直接操作Unicode
字符所导致,因此Java语言不提倡使用字节流读取文本文件,而是建议字符流操作文本文件。
InputStream
流类
常用方法:
方法 | 功能 |
| 从输入流中的当前位置读入一个字节的二进制数据,然后以此数据位地位字节,配上8个全0的高位字节合成一个16位的整型量(0-255)返回给调用此方法的语句,若输入流中的当前位置没有数据,则返回-1。 |
| 从输入流中的当前位置连续读入多个字节保存在数组b中,同时返回所读到的字节数。 |
| 从输入流中的当前位置连续读入len个字节,从数组b的第off+1个元素位置处开始存放,同时返回所读到的字节数。 |
| 返回输入流中可以读取的字节数 |
| 使位置指针从当前位置向后跳过n个字节 |
| 在当前位置处做一个标记,并且在输入流中读取readlimit个字节数后该标记失效 |
| 将位置指针返回到标记的位置 |
| 关闭输入流与外设的链接并且释放所占用的系统资源 |
当Java程序需要从外设如键盘、磁盘文件等读入数据时,应该创建一个适当类型的输入流对象来完成与该设备的连接,由于InputStream
是抽象类,所以程序中创建的输入流对象一般是InputStream
某个子类的对象,通过调用该对象继承的read()
方法就可以实现相应设备的输入操作。
流中的方法都声明抛出异常,所以程序中调用流方法时必须处理异常,否则编译不能通过,由于所有的I/O流都实现了AutoCloseable
接口,而只是实现该接口的资源才可以使用try-with-resources
语句自动关闭打开的资源。因此,在使用I/O流进行输入输出操作的时候,可以使用try-with-resources
语句处理异常。
OutputStream
流类OutputStream
流类中包含一套所有字节输出都需要的方法,可以完成最基本的向输出流写入数据的功能。
方法 | 功能 |
| 将参数b的低位字节写入到输出流 |
| 将字节数组b的全部字节按顺序写入到输出流 |
| 将字节数组b中的第off+1个元素开始的len个数据,顺序地写入到输出流 |
| 强制清空缓冲区并执行向外设写操作 |
| 关闭输出流与外设的连接并且释放所占用的系统资源 |
例如:写入到文件中
import java.io.*;
class demo {
public static void main(String[] args) throws IOException {
char ch;
FileInputStream fin = new FileInputStream(FileDescriptor.in);
FileOutputStream fout = new FileOutputStream("text.txt");
System.out.println("请输入一串字符!(以#号结束)");
while ((ch = (char) fin.read()) != '#')
fout.write(ch);
}
}
读取文件的内容
import java.io.*;
class demo {
public static void main(String[] args) throws IOException {
char ch;
int data;
// FileInputStream fin = new FileInputStream(FileDescriptor.in);
// FileOutputStream fout = new FileOutputStream("text.txt");
// System.out.println("请输入一串字符!(以#号结束)");
// while ((ch = (char) fin.read()) != '#')
// fout.write(ch);
FileInputStream fin = new FileInputStream("text.txt");
FileOutputStream fout = new FileOutputStream(FileDescriptor.out);
while (fin.available() > 0) {
data = fin.read();
fout.write(data);
}
}
}
FileInputStream
和FileOutputStream
主要用来处理二进制图像文件,例如:
import java.io.*;
class demo {
public static void main(String[] args) throws IOException {
FileInputStream fin = new FileInputStream("1.png");
FileOutputStream fout = new FileOutputStream("2.png");
System.out.println("文件大小"+fin.available());//利用available()方法获取文件的大小,并输出,以字节(B)为单位。
byte[] b = new byte[fin.available()];//新建一个byte类型的数组
fin.read(b);//将文件读入数组
fout.write(b);//将数组中的数据写入新文件"2.png"中。
System.out.println("文件复制更名成功!");
}
}
- 顺序输入流
顺序输入流类SequenceInputStream
是InputStream
的直接子类,其功能是将多个输入流顺序连接在一起,形成单一的输入数据流,没有对应的输出数据流存在。再进行输入时,顺序输入流依次打开每个输入流并读取数据,也在读取完毕后将该流关闭,然后自动切换到下一个输入流。也就是说,由多个输入流构成的顺序输入流,当从一个流中中读取数据遇到EOF时,SequenceInputStream
将会自动转向下一个输入流,直到构成SequenceInputStream
类的最后一个输入流读取到EOF时为止。SequenceInputStream
类的构造方法、
构造方法 | 功能 |
| 创建一个串行输入流,连接枚举对象e中的所有输入流 |
| 创建一个串行输入流,连接输入流s1和s2 |
SequenceInputStream
类的常用方法
常用方法 | 功能 |
| 返回流中可读取的字节数 |
| 关闭输入流 |
| 从输入流中读取字节,遇到EOF就转向下一输入流 |
| 将len个数据读到一个字节数组从off开始的位置 |
- 管道输入输出流
Java之中管道字节输入流PipedInputSteam
和管道字节输出流PipedOutputStream
类提供了利用管道方式进行数据输入输出管理的类。管道流用来将一个程序或县城的输出连接到另外一个程序或线程作为输入,是的相互连接的线程能够通过PipedInputStream
和PipedOutputStream
流进行数据交换,从而可以实现程序内部线程间的通信或不同程序之间的通信。
在jdk1.8文档中明确说明了,不建议从单个线程中使用这两个对象,因为它可能会使线程死锁。
具体方法参考jdk文档 - 过滤输入输出流
过滤字节输入流类FilterInputStream
和过滤字节输出流类FilterOuputStream
,分别实现了在数据的读写操作的同时进行数据处理,他们是InputStram
和OutputStream
类的直接子类。过滤字节输入输出流类的主要特点是,顾虑字节输入输出流时间里在基本输入输出流之上,并在输入输出数据的同时能对所传输的数据做指定类型或格式的转换,即可实现对二进制字节数据的理解和编码转换。
具体使用方法见jdk文档。
整理如下:DataInputStream
类的常用方法
常用方法 | 说明 |
| 从流中读1字节,但是字节值非0返回 |
| 从流中读1自字节,返回该字节值 |
| 从流中读取a,b2字节,形成Unicode字符(char)((a<<8)|(b&0xff)) |
| 从六中读入2字节的short值并返回 |
| 从流中读入4字节的int值并返回 |
| 从流中读入4字节的float值并返回 |
| 从流中读入8字节的long值并返回 |
| 从流中读入8字节的double值并返回 |
DataOutputStream
类的常用方法
常用方法 | 说明 |
| 将boolean写入底层输出流作为1字节值,值 |
| 向流中写入1字节,最低的1字节,其他的字节丢弃 |
| 向流中写入参数v的高2字节,其他的字节丢弃 |
| 向流中写入参数v的高2字节,其他的字节丢弃 |
| 向流中写入参数v的4字节 |
| 向流中写入参数v的4字节 |
| 向流中写入参数v的8字节 |
| 向流中写入参数v的8字节 |
package sample;
import java.io.*;
class demo {
public static void main(String[] args) throws IOException {
FileOutputStream fout = new FileOutputStream("text");
DataOutputStream dout = new DataOutputStream(fout);
dout.writeInt(10);
dout.writeLong(12345);
dout.writeFloat(3.1415626f);
dout.writeDouble(987654321.123);
dout.writeBoolean(true);
dout.writeChars("GoodBye!\0");//此处不加上\0后面会抛出IO异常EOFException;
FileInputStream fin = new FileInputStream("text");
DataInputStream din = new DataInputStream(fin);
System.out.println(din.readInt());
System.out.println(din.readLong());
System.out.println(din.readFloat());
System.out.println(din.readDouble());
System.out.println(din.readBoolean());
char ch;
while ((ch = din.readChar()) != '\0')
System.out.print(ch);
}
}
writeChars()里面需要加上一个\0,不然的话会抛出异常,亲测,EOFException3表示输入过程中意外地到达文件尾或流尾的信号,导致异常。
- 标准输入输出流
当程序对标准输入输出设备进行操作的时候,则不需要创建输入或输出流类的对象。
对于一般的系统来说,标准输入设备通常指键盘,标准输出设备通常指屏幕显示器。为了方便程序对键盘输入和屏幕输出进行操作。Java系统事先在System类中定义静态流对象System.in
、System.out
和System.err
。System.in
对应着输入流,通常指键盘输入设备。System.out
对应着输出流,指显示器等信息输出设备,System.err
对应着标准错误输出设备,使得程序的运行错误,可以由固定的输出位置,通常来说该对象对应着显示器。
1.标准输入
Java语言的标准输入是System.in
是BufferedInputStream
类的对象,当程序需要从键盘上读入数据时,只需要调用System.in
的read()
方法即可,该方法从键盘缓冲区读入一个字节的二进制数据,并将它们存储到缓冲区b,实际读取的字节数作为整数返回。其方法:public int read (byte[] b) throws IOException
。第一个字节存入b[0],以此类推。
2.标准输出
Java语言的标准输出,是打印输出流PrintStream
类的对象。详见jdk手册。
import java.io.*;
class demo {
public static void main(String[] args) throws IOException {
byte[] b = new byte[128];
System.out.println("请输入字符:");
int count = System.in.read(b);
System.out.println("输入的是:");
for(int i = 0; i < count; ++i){
System.out.println(b[i] + " ");//输出的是ASCII值
}
for(int i = 0; i < count; ++i)
System.out.println((char)b[i] + " ");//以字符的方式输出数组b元素
}
四、使用Reader
和Writer
流类
Reader
和Writer
类则是用来处理“字符流”的,也就是文本文件,与字节输入输出流的功能一样,字符输入输出流类知识建立了一条通往文本文件的通道。Reader
类的常用方法
常用方法 | 说明 |
| 从输入流中读一个字符 |
| 从输入流中读最多 |
| 从输入流中读最多 |
| 从输入流中最多向后跳n个字符 |
| 判断流是否最好读的准备 |
| 标记输入流的当前位置 |
| 测试输入流是否支持mark |
| 重定位输入流 |
| 关闭输入流 |
Writer
类的常用方法
常用方法 | 说明 |
| 将单一字符c输出到流中 |
| 将字符串输出到流中 |
| 将字符数组cbuf输出到流 |
| 将字符数组按指定格式输出 |
| 将缓冲区的数组写到文件 |
| 关闭输出流 |
- 使用FileReader类读取文件
文件字符输入流类FileReader
是继承自InputStreamReader
类,而InputStreamReader
类又是继承自Reader
类,因此,Reader
类与InputStreamReader
类所提供的方法均可供FileReader
类所创建对象使用。
使用FileReader
类读取文件时,必须先调用FileReader()
构造方法创建FileReader
类的对象,再利用它来调用read()
方法。
其构造方法:public FileReader(String name)
,根据文件名称创建一个可以读取的输入流对象。
import java.io.*;
class demo {
public static void main(String[] args) throws IOException {
char[] ch = new char[500];//创建可以容纳500字符的数组
FileReader file = new FileReader("text.txt");
int num = file.read(ch);//将数据读取到数组之中,并且返回读取的字符数量
String str = new String(ch, 0, num);//将字符数组转换成为字符串
System.out.println("读取的字符个数有:" + num + "个。内容如下:");
System.out.println(str);
}
}
这样子会将文件中的内容读出来,输出。但是可能会有人遇到乱码问题,记住,windows默认创建的txt文件时ANSI编码格式,所以,你需要保存为UTF-8格式。
- 使用
FileWriter
类写入文件
文件字符输出流类FileWriter
继承自OutputStreamWriter
类,但是OutputStreamWriter
类又是从Writer
类中继承得到的,所以说,Writer
类与OutputStreamWriter
类suotigong7的方法均可提供给FileWriter
类所创建的对象使用。FileWriter
类的构造方法
构造方法 | 功能说明 |
| 根据所给的文件名创建一个可以供写入字符数据的输出流对象,原先的文件会被覆盖 |
| 同上,如果说a设置为 |
import java.io.*;
class demo {
public static void main(String[] args) throws IOException {
FileWriter file = new FileWriter("text.txt");
String str = "Java牛皮!";
file.write(str);
file.close();
}
}
- 利用
BufferedReader
类读取文件
缓冲字符输入流类BufferedReader
继承自Reader
类,BufferedReader
类是用来读取缓冲区李的数据,使用该类读取缓冲区中的数据之前,必须创建FileReader
类对象,再将以该对象来创建BufferedReader
类的对象,然后才可以利用该对象来读取缓冲区中的数据。
构造方法
构造方法 | 功能说明 |
| 创建缓冲区字符输入流 |
| 创建缓冲区字符输入流,并设置缓冲区大小 |
常用方法
常用方法 | 功能说明 |
| 读取单一字符 |
| 从流中读取字符并且写入到字符数组之中 |
| 从流中读取字符存放到字符数组之中,off代表数组下标,len代表的是数组长度 |
| 跳过n个字符不读取 |
| 读取一行字符串 |
| 关闭流 |
import java.io.*;
class demo {
public static void main(String[] args) throws IOException {
FileReader file = new FileReader("text.txt");
BufferedReader bfile = new BufferedReader(file);
String tmpString;
while((tmpString = bfile.readLine())!=null){
System.out.println(tmpString);
}
}
}
- 使用
BufferedWriter
类写入文件
与BufferedReader
类类似,BufferedWriter
继承自Writer
类,BufferedWriter
类,是用来将数据写入缓冲区中,首先来说,我必须创建FileWriter
类对象,再以该对象为参数创建BufferedWriter
类的对象,然后就可以利用此对象来讲数据写入缓冲区中,所以不同的是,缓冲区中的数据最后必须都要用flush()
方法将缓冲区清空,也就是将缓冲区的数据全部写到文件之内。
缓冲字符输出流类BuffereWriter
的构造方法:
构造方法 | 功能说明 |
| 创建缓冲区字符输出流 |
| 创建缓冲区字符输出流 |
BufferedWriter
类的常用方法
常用方法 | 功能说明 |
| 将单一字符写入缓冲区 |
| 将字符数组ch按照指定格式写入到输出缓冲区中(off表示数组下标,len表示写入的字符数) |
| 写入字符串(off表示下标,len表示写入的字符数) |
| 写入回车换行字符 |
| 关闭流 |
import java.io.*;
class demo {
public static void main(String[] args) throws IOException {
BufferedWriter out = new BufferedWriter(new FileWriter("text.txt"));
String str = new String("Hello!Java!我是新一代程序员!");
out.write(str);
out.newLine();
out.write("我必定会登顶巅峰!");
out.close();
}
}
五、文件的处理与随机访问
- 对于文件以及文件夹的管理
- 创建一个File类的对象,每个File类的对象对应着系统的一个磁盘文件或者文件夹,所以说创建File类对象需要给出它所对应的文件名或者文件夹名。
File类的构造方法
构造方法 | 功能说明 |
| 利用path参数创建对象 |
| 以path为路径,创建name的文件或文件夹 |
| 用一个已经存在代表某磁盘的文件夹的File对象dir作为文件夹,以name作为文件或文件夹名来创建File对象 |
因为在不同的操作系统中使用的文件夹的分隔符不一样,如Windows操作系统使用的是反斜线,但是在UNIX操作系统上使用的是正斜线,但是为了保证Java程序能够在不同的平台上运行,可以使用File类的一个静态变量File.separator。该属性中保存了当前系统规定的文件夹分隔符,使用它会组合成在不同操作系统上都能够通用的路径。
- 文件或文件夹属性
常用方法
用方法 | 功能说明 |
| 判断文件或文件夹是否存在 |
| 判断对象是否代表有效文件 |
| 判断对象是否代表有效文件夹 |
| 返回文件名或文件夹名 |
| 返回文件或者文件夹的路径 |
| 返回文件的字节数 |
| 判断文件是否可读 |
| 判断文件是否可写 |
| 将文件夹中所有文件名保存在字符串数组中返回 |
| 比较两个文件或文件夹是否相同 |
- 文件或文件夹操作
管理操作方法
常用方法 | 功能说明 |
| 将文件重命名成newFile对应的文件名 |
| 将当前文件删除,若删除成功返回 |
| 创建当前文件夹的子文件夹,若成功返回 |
- 对文件的随机访问
RandomAccessFile
类的构造方法
构造方法 | 功能说明 |
| 以name来指定随机文件流对象所对应的文件名,以mode表示对文件的访问模式 |
| 以file来指定随机文件流对象所对应的文件名,以mode表示对文件的访问模式 |
访问模式:r:表示只读方式打开文件,rw:表示以读写方式打开文件。
RandomAccessFile
类的常用方法
常用方法 | 功能说明 |
| 关闭随机访问文件并释放系统资源 |
| 获取文件描述符 |
| 返回文件指针的当前位置 |
| 返回文件长度 |
| 跳过输入流中n个字符,并返回跳过实际的字节数 |
| 从文件输入流中读取一个字节的数据 |
| 从文件输入流的当前指针位置开始读取长度为len字节的数据存放到字节数组b中,存放的便宜位置为off,若遇到文件结束符,则返回值-1 |
| 从文件输入流的当前指针位置开始读取b.length字节的数据存放到字节数组b中,若遇文件结束符,则抛出 |
| 从文件输入流的当前指针位置开始读取长度为len字节的数据,放到b数组中,存放的位置开始为off,遇到文件结束符,则抛出 |
| 读取文件的逻辑值 |
| 从文件中读取带符号的字节值 |
| 从文件中读取一个 |
| 从文本文件中读取一行 |
| 设置文件指针位置 |
RandomAccessFile
类用于写入操作的常用方法
用方法 | 功能说明 |
| 在文件指针的当前位置写入一个 |
| 在文件指针的当前位置写入一个 |
| 在文件指针的当前位置写入一个字节值 |
| 以字节形式写入一个字符串到文件 |
| 在文件指针的当前位置写入v的两字节,高字节优先 |
| 以字符形式写一个字符串到文件 |
| 在文件当前指针位置写入8字节数据v |
| 在文件当前指针位置写入4字节数据v |
| 在整形数作为4字节写入文件 |
| 将长整型数作为8字节写入文件 |
| 在文件指针当前位置写入2字节,高位字节 |
| 作为UTF格式向文件之中写入一个字符串 |