五.IO流 与文件
1流
1.1 输入流 输出流
可以从其中读入一个字节序列的对象称为输入流
可以向其中写入一个字节学列的对象称为输出流
输入输出流的基础是抽象类InputStream和OutputStream,因为面向字节的流不便处理unicode形式存储的信息,(unicode中的每个字符都使用多个字节表示),因此有从抽象类Reader和Writer中继承来的类操作unicode存储的信息,这些类的输入输出操作是基于unicode码元的,而不是基于单字节的字符
1.2 读写字节
InputStream 有一个抽象的方法 abstract int read() 所有它的子类都要复写这个方法,才可以读操作,读到末尾,返回-1
OutputStream 有一个抽象的方法 abstract void write( int b) ,它可以向某个输出位置写出一个字节
完成读写要close()释放资源
int read( byte[] b) 读入一个字节数组 ,并返回字节数,如果读到末尾,返回-1
int read (byte[] b,int off ,int len) 读入一个字节数组,off是第一个读入字节的偏移量,len是读入字节的长度 ,该方法返回的是实际读入的字节数
void write ( byte[] b)
void write (byte [] b,int off ,int len)
flush() 将缓冲区的数据发送到目的地,,清空输出流
close() 清空输出流并关闭流
1.3流家族
60个
字节流 InputStream 和OutputStream
对应 unicode文本 Reader 和Writer ,他们的基本方法和字节流类相似
OutputStream和Writer有flush方法 ,只有writer类实现了Appendable接口
永远 append()方法
组合流过滤器
例如为了从文件中读入数字,可以这样:
FileInputStream fin = new FileInputStream( “ employee.dat”);
DataInputStream din= new DataInputStream( fin);
double s = din.readDouble();
如果使用缓存机制可以这样写:
DataInputStream din= new DateInputStream(
new BufferedInputStream(
new FileInputStream(“ employee.dat”)
));
2.文本输入与输出
在保存数据时.我们可以采用二进制形式或者文本形式,二进制形式不方便阅读,本节中我们讨论文本输入和输出
在下一节中我们讨论二进制的输入和输出
在存储文本字符串时候需要考虑字符编码,
OutputStreamWriter 可以将unicode编码的字符流转换成字节流
InputStreamReader 可以将输入流转换成可以产生unicode字符的读入器
例如 InputStreamReader in = new InputStreamReader(System.in);该输入读入器将从键盘读入的数据转换成unicode格式的数据
可以通过构造器指定编码格式,默认是iso 8859-1
InputStreamReader in= new InputStreamReader(
new FileInputStream(“employee.txt”) ,
” utf-8”
);
因为读入器和写出器使用比较普遍,java提供了另外两个类 FileReade 和FileWriter
FileWriter fw= new FileWriter( “ employee.txt”);该方法等同于
FileWriter fw = new FileWiter( new FileOutputStream ( ‘employee.txt’));
2.1如何写出文本输出
使用PrintWriter类可以以文本格式打印字符串和数字
PrintWriter out= new PrintWriter(employ.txt);
等同于
PrintWriter out =new PrintWriter(new FileWriter(“ employ.txt”));
自动清空模式,会自动输出到文件中
String s=” sgahgj”;
double salary= 5666;
PrintWriter out= new PrintWriter(new FileWriter(employee.txt), true );
out.println(s);
out.println(salary);
System.out System.in 是流,不是写出器和读入器
2.2 如何读入文本输入
Scanner 和BufferedReader都可以读入文本
(1)BufferedReader in =new BufferedReader( new FileReader(employee.txt));
String line;
while ( line= in.readLine()!=null)
{
do something with line
}
(2)
Scanner in = new Scanner();//它的方法有 nextInt() nextDouble() nextLine()
hasNextLine()
while(in.hasNextLine())
{
String line= in.nextLine();
}
3读写二进制数据
interface DateInput
{
boolean readBoolean();
byte readByte()
char readChar()
int readInt()
void readFully( byte[] b,int off,int len) 将二进制数据读入字节数组中
}
interface DataOutput
{
void writeByte()
void writeChar()
void writeInt()
void writeChars()
}
它的两个类 DataInputStream DataOutputStream
随机访问文件
RandomAccessFile类 可以随机在文件的任意位置读或写数据同时实现了DataInput和DataOutput 接口,该类和InputStream 和OutputStream 没有任何关系,是一个继承Object的独立的类,,定位用的getFilePointer( ),在文件里移动用的seek( ),以及判断文件大小的length( )、skipBytes()跳过多少字节数。此外,它的构造函数还要一个表示以只读方式("r"),还是以读写方式("rw")打开文件的参数,不支持只写
r 表示读入
rw 表示读写
RandomAccessFile in = new RandomAccessFile(“employee.dat”,”r”);
RandomAccessFile inout = new RandomAccessFile(“employee.dat”,”rw”);
- public class TestRandomAccessFile {
- public static void main(String[] args) throws IOException {
- RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw");
- for (int i = 0; i < 10; i++) {
- //写入基本类型double数据
- rf.writeDouble(i * 1.414);
- }
- rf.close();
- rf = new RandomAccessFile("rtest.dat", "rw");
- //直接将文件指针移到第5个double数据后面
- rf.seek(5 * 8);
- //覆盖第6个double数据
- rf.writeDouble(47.0001);
- rf.close();
- rf = new RandomAccessFile("rtest.dat", "r");
- for (int i = 0; i < 10; i++) {
- System.out.println("Value " + i + ": " + rf.readDouble());
- }
- rf.close();
- }
- }
4,用ZipInputStream 和ZipOutputStream 来读写ZIP文件
5.对象流和序列化
对象序列化:将对象写入流中,之后可以读回,每一个对象都对应一个序号,
保存时,如果是第一次保存这个对象,那么给他分配一个序列号,第二次报存这个对象,会告知和之前保存的对象相同,在读回时,当读到一个对象序列号时就会利用流中数据构建这个对象,当第二次读到这个序列号,不再构建对象,而是给它分配这个对象的引用即可
用到的类 ObjectOutputStream ObjectInputStream
ObjectOutputStream out =new ObjectOutputStream(“employee.dat”);
Employ e=new Employ (23,””小明);
Mannage m= new Mannage (40,”xiao qinag”);
out.writeObject(e);
out.writeObject(m);
要存储和恢复这些类必须实现Serializable接口
public class Employ implements Serializable{}
6.新I/0
6.1 内存映射文件
将文件映射到内存中,把这个文件就当作数组来读取,速度会快很多
读写数据的速度 :
内存映射文件>带缓冲的输入流> 普通输入流>随机访问文件
7.2s 9.9s 100s 160s
随机访问文件性能损失很大
内存映射文件由java.nio这个包负责
1).首先获得通道FileInputStream FileOutputStream RandomAccessFile中都有获得通道发动方法
FileChannel channel= new FileInputStream(“employee.dat”).getChannel();
2)通过FileChannel类的map()方法得到一个MapedByteBuffer,可以指定缓冲区的三种模式
MapedByteBuffer buff= FileChannel.map(mode ,int off,int length);
3)一旦获得了这个缓冲过区,就可以利用MapedBuffer 和Buffer超类执行操作
例如 while (buff.hasRemain())
{
byte b=buffer.get();
}
6.2 Buffer超类
文件缓冲区
他有很多子类,例如 ByteBuffer IntBuffer
但是注意 StringBuffer和他们完全没有关系
常用的是ByteBuffer 和CharBuffer