第 6章 数据流的运用北京大学计算机系代亚非
2
第 6章 数据流的运用
6.1 输入输出方法
6.2 输入输出流的基类
6.3 File I/O
6.4 数据输入输出流
6.5 随机存取文件
6.6 文件的其它操作
6.7 java中的 unicode
6.8 管道流
6.9 对象流
6.10 流的分类
6.11 小结
3
文件程序终端文件程序网络端点数据流起点终点网络端点文件,字符串存储区
6.1 输入输出方法
什么是数据流?
数据流是指所有的数据通信通道
在 java中有关流的操作使用 java.io.*
出于安全的考虑,小应用不能实现文件 I/O流
4
6.1 输入输出方法
System类管理标准输入输出流和错误流
System.out:
把输出送到缺省的显示 (通常是显示器 )
System.in
从标准输入获取输入 (通常是键盘 )
System.err
把错误信息送到缺省的显示
每当 main方法被执行时,就自动生成上述三个对象
5
6.1 输入输出方法
public class ReadHello
{ public static void main(String args[])
{ char inchar;
System.out.println(“Enter a character:”);
try{ inChar=(char)System.in.read();
Syste.out.println(“,+ inChar);
}catch(IOException e)
{ Sytem.out.println(“Error reading from user”);
}
}
}
6
stream\Iostream.class---f4.bat
6.1 输入输出方法
import java.io.*;
class IOTest
{ public statics void main(String args[])
{try { byte bArray[]=new byte[128];
System.out.println(“Enter something:”);
System.in.read(bArray);
System.out.print(“You entered:”);
System.out.println(bArray);
}catch(IOException ioe)
{ System.out.println(ioe.toString()); }
}
}
7
6.1 输入输出方法
为什么输入的是字符,输出是乱码?
原因,System.out.println(bArray)输出的是数组的地址而不是字符
改进,将字符数组变换成字符串
原来是,System.out.println(bArray);
现在为,String s=new String(bArray,0);
System.out.println(s);
System.in是属于 BufferedInputStream类型
System.out是属于 PrintStream类型
System.err也是属于 PrintStream类型
8
6.2 输入输出流的基类
Java中每一种流的基本功能依赖于基本类
InputStream和 OutputStream
它们是抽象类,不能直接使用
属于 InputStream类的方法有,
read():从流中读入数据
skip():跳过流中若干字节数
available():返回流中可用字节数
mark():在流中标记一个位置
reset():返回标记过得位置
markSupport():是否支持标记和复位操作
close():关闭流
9
6.2 输入输出流的基类
方法 read()提供了三种从流中读数据的方法,
int read():读一个整数
int read(byte b[]):读多个字节到数组中
int read(byte,int off,int len);
属于 OutputStream类的方法有,
write(int b):将一个整数输出到流中
write(byte b[]):将数组中的数据输出到流中
write(byte b[],int off,int len):将数组 b中从 off指定的位置开始 len长度的数据输出到流中
10
6.2 输入输出流的基类
flush():将缓冲区中的数据强制送出
close():关闭流,
PrintStream类
println()不属于 OutputStream类,它是
PrintStream类的子类,能提供复杂的输出
PrintStream类的方法有,
write,flush,checkError,print,println,close.
其中 println可以输出多种形式的数据,例如,
println(String s),println(char c)等
11
输出文件 输入文件 read
write
6.3 File I/O
文件对象的建立
File fp=new File(“tempfile.txt”);
对文件操作要定义文件流
FileInputStream类用来打开一个输入文件
FileOutputStream类用来打开一个输出文件
12
6.3 File I/O
文件流的建立
FileInputStream in=new FileInputStream(fp);
FileOutputStream out=new
FileOutputStream(fp);
例,文件拷贝 (注意要捕获文件异常 )
输入流的参数是用于输入的文件名
输出流的参数是用于输出的文件名
file1.txt file2.txt输入流 输出流
13
6.3 File I/O
import java.io.*;
class filestream
{ public static void main(String args[])
{ try{
File inFile=new File(”file1.txt");
File outFile=new File(”file2.txt");
FileInputStream fis=new FileInputStream(inFile);
FileOutputStream fos=new FileOutputStream(outFile);
int c; while((c=fis.read())!=-1) fos.write(c);
fis.close(); fos.close();
}catch(FileNotFoundException e) {
System.out.println("FileStreamsTest,"+e);
}catch(IOException e) {
System.err.println("FileStreamsTest,"+e);
}}}
14
6.3 File I/O
增加缓冲区流,减少访问硬盘的次数,提高效率文件文件流 缓冲区流
file1.txt file2.txt
输入流 输出流输入缓冲区 输出缓冲区
156.3 File I/O
缓冲区流,
BufferedInputStream和
BufferedOutputStream
将它们与文件流相接
FileInputStream in=new
FileInputStream(“file1.txt”);
BufferedInputStream bin=
new BufferedInputStream(in,256)
int len; byte bArray[]=new byte[256];
len=bin.read(bArray);
len中得到是长度,bArray中得到的是数据
16
6.3 File I/O
只有缓冲区满时,才会将数据送到输出流,
Java在输出数据流中,当对方尚未将数据取走时,
程序就会被阻塞,
有时要人为地将尚未填满的缓冲区中的数据送出,使用 flush()方法,
文件
17
6.4 数据输入输出流
什么时候需要数据输入输出流?
文件流和缓冲区流的处理对象是字节或字节数组,利用数据输入输出流可以实现对文件的不同数据类型的读写,
DataInputStream,DataOutputStream
一种较为高级的数据输入输出方式,除了字节和字节数组,还可以处理 int,float,boolean等类型,
还可以用 readLine方法读取一行信息
可使用的方法,
write,writeBoolean…,read,readByte… 等
18
6.4 数据输入输出流
数据流的建立
FileOutputStream fos=
new FileOutputStream(”file2.txt"));
DataInputStream dis=
new DataInputStream(fos)
数据输出流可以是一个已经建立好的输入数据流对象,例如网络的连结,文件等,
下面的例子显示如何利用数据输入输出流往文件中写不同类型的数据
19
6.4 数据输入输出流
class datainput_output
{ public static void main(String args[]) throws IOException
{ FileOutputStream fos=new FileOutputStream(“a.txt”);
DataOutputStream dos=new DataOutputStream (fos);
try{ dos.writeBoolean(true);
dos.writeByte((byte)123);
dos.writeChar('J');
dos.writeDouble(3.141592654);
dos.writeFloat(2.7182f);
dos.writeInt(1234567890);
dos.writeLong(998877665544332211L);
dos.writeShort((short)11223);
}finally{ dos.close(); }
20
Stream\datainputandoutput--->f5.bat
6.4 数据输入输出流
DataInputStream dis=new DataInputStream(
new FileInputStream(”a.txt"));
try{ System.out.println("\t "+dis.readBoolean());
System.out.println("\t "+dis.readByte());
System.out.println("\t "+dis.readChar());
System.out.println("\t "+dis.readDouble());
System.out.println("\t "+dis.readFloat());
System.out.println("\t "+dis.readInt());
System.out.println("\t "+dis.readLong());
System.out.println("\t "+dis.readShort());
}finally{dis.close();}
}}
21
6.4 数据输入输出流
DateLine(InputStream in)(计算字符和行数 )
{ DataInputStream data=new
DataInputStream(in);
String currentLine;
int lineCount=0; int charCount=0;
while((currentLine=dataIn.readLine())!=null)
{ ++lineCount;
charCount+=currentLine.length();
}
return (charCount/(float)lineCount);
}
22
文件目录zip文件
6.5 随机存取文件
类 RandomAccessFile
zip文件需要用随机方法处理
文件目录给出个文件的入口,可以随机读取,
创建一个随机文件
new RandomAccessFile(“file1.txt”,“r”);
new RandomAccessFile(“file2.txt”,“rw”);
随机文件可以同时完成读和写操作,
23
pos
6.5 随机存取文件
支持随机文件操作的方法,
readXXX()或 writeXXX()
skipBytes();将指针乡下移动若干字节
seek():将指针调到所需位置
getFilePointer():返回指针当前位置
length():返回文件长度
利用 seek(long pos)方法查找随机文件中的信息
例,把若干个 32位的整数写到一个名为
,temp.dat”的文件中,然后利用 seek方法,以相反的顺序再读取这些数据
24
6.5 随机存取文件
public class random_file
{ public static void main(String args[])
{ int data_arr[]={12,31,56,23,27,1,43,65,4,99};
try { RandomAccessFile randf=new
RandomAccessFile(“temp.dat”);
for (int i=0;i>data_arr.length;i++)
randf.writeInt(data_arr[i]);
for(int i=data_arr.length-1;i>=0;i--)
{ randf.seek(i*4);
System.out.println(randf.readInt()); }
randf.close();
}catch (IOException e)
{ System.out.println(“File access error:,+e);} } }
25
6.6 文件的其它操作
使用文件类获取文件的路径信息
设 f是一个文件对象
File f=new File(“data”,temp.dat”);
f.getName():返回文件名 temp.dat
f.getParent():返回文件所在目录名 data
f.getPath():返回文件路径 data\temp.dat
f.getAbsolutePath():返回绝对路
c:\myprog\data\temp.dat
26
6.6 文件的其它操作
例,获取当前目录下所有文件名和文件的尺寸,
import java.io.*;
public class file_size
{ public static void main(String args[])
{ File files=new File(“.”);
String file_list[]=files.list();
for(int i=0;i<file_list.length;i++)
{ File current_file=new File(file_list[i]);
System.out.println(file_list[i]+
current_file.length());
}
}
27
在 java中用 unicode 表示字符和字符串
DatainputStream的 readLine方法,以字节形式读入,以 unicode形式输出
DataInputStream不适合输入是 unicode的形式
处理字符用 InputStreamReader 类和
BufferedReader 类 (jdk1.1)
byte Unicode
16bit8 bit
+ 00000000
6.7 java 中的 unicode
286.7 java 中的 unicode
import java.io;(从键盘上读一个字符串 )
public class CharInput
{ public static void main(String args[])
{String s; throws IOException
InputStreamReader ir;
BufferedReader in;
ir=new InputStreamReader(System.in);
in=new BufferedReader(ir);
String s=in.readLine();
int i=Integer.parseInt(s); i=i*2;
System.out.println(“the result is” +i); }
}
可以将字符串转换成整数加以运算
123
29
6.7 java 中的 unicode
问题,
如果字符流不是来自本地,有可能编码不一样,
直接读取会读出不正确字符
处理方法,
ir=new InputStreamReader(is,”8859_1”);
采用的是 iso8859_1编码方式,在不同平台之间正确转换字符,
30
6.7 java 中的 unicode
import java.io.*;
class filetounicode
{ public static void main(String args[])
{ try{ FileInputStream fis=new
FileInputStream("toyamei.txt");
InputStreamReader dis=new
InputStreamReader(fis);
BufferedReader reader=new
String s; BufferedReader(dis);
while((s=reader.readLine())!=null)
{ System.out.println("read,"+s);}
dis.close();
}catch(IOException e) { }
}
}
316.8 使用管道流
PipedInputStream和 PipedOutputStream
创建管道流,
PipedInputStream pis=new PipedInputStream();
PipedOutputStream pos=new
PipedOutputStream(pis);
或,
PipedOutputStream pos=new
PipedOutputStream();
PipedInputStream pis=new
PipedInputStream(pos);
输出流 输入流
326.8 使用管道流
管道流一定是输入输出并用
例,将数据从输出管道进,从输入管道出
import java.io.*;
class pipedstream
{ public static void main(String args[]) throws
IOException
{ byte aByteData1=123,aByteData2=111;
PipedInputStream pis=
new PipedInputStream();
PipedOutputStream pos=
new PipedOutputStream(pis);
System.out.println("PipedInputStream");
33
try{
pos.write(aByteData);
pos.write(aByteData2);
System.out.println((byte)pis.read());
System.out.println((byte)pis.read());
} finally {
pis.close();
pos.close();
}
6.8 使用管道流
34
6.9 对象流
在 java.io包中 什么是对象的持续性?
能够纪录自己的状态一边将来再生的能力,叫对象的持续性
什么是串行化?
对象通过写出描述自己状态的的数值来记录自己的过程叫串行化,
什么是对象流?
能够输入输出对象的流,
两者什么关系?
将串行化的对象通过对象输入输出流写入文件或传送到其它地方,
356.9 对象流
一个相关的例子,从一个源读入一个简单的对象
import java.net;import java.io
public class GetString
{ public String getStringFromUrl(URL inURL)
{ InputStream in;
try { in =inURL.openStream();
}catch(IOException ioe)
{System.out.printlin(“URL error;”+ioe);
return null; }
return getString(in);
}通过 url得到一个字符串
36
6.9 对象流
public String getStringFromSocket(Socket
inSocket)
{ inputStream in;
try{ in=inSocket.getInputStreamSream();
}catch(IOEception ioe)
{ System.out.println(“Socket error:”+ioe);
return null; }
return getString(in);
} 通过 socket得到一个字符串
376.9 对象流
public String getString(inputStream inStream)
{ String readString = new String();
DataInputStream in =new
DataInputSream(inStream);
char inChar;
try{ while(true)
{ inChar=in.readByte();
readString=readString+inChar; }
}catch(EOFException eof)
{ System.out.println(readString);}
}catch(IOException ioe) {
{ System.out.println(“error:”+ieo);}
return readString; }
38
6.9 对象流
下面的对象能读吗?
Class testObject
{ int x; int y;
float angle;
String name;
public testObject(int x,int y,float angle,
String name);
{ this.x=x;this.y;this.angle;this.name=name;}
}
这仍然是一个简单的对象
396.9 对象流对象流是怎样工作的?
允许可串行化的对象在流中传输
1.只有实现 serializable接口的类才能被串行化
public class Student implements Serializable
{ int id;String name; int age;
String department;
public Student(int id,String name,int age,
String department)
{ this.id=id; this.name=name;
this.age=age; this.department =departmernt;
}
}
406.9 对象流
2,构造对象的输入输出流 (将对象保存到文件中,或者通过网络传送到其他地方 )
相应的类,ObjectInput
对象的输出,ObjectOutputStream
相应的方法,writeObject()
对象的输入,ObjectInputStream
相应的方法,readObject()
注,jdk1.1以上版本支持对象流操作
416.9 对象流对象流举例,将 Student类的一个实例写到文件中
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class Objectser
{public static void main(String args[])
Student stu=new Student(981036,“Li Ming”,16,“CSD”);
{try {FileOutputStream fo=new
FileOutputStream(“date.ser”);
ObjectOutputStream so=new
ObjectOutputStream(fo);
os.writeObject(stu);so.close();
}catch(Exception e) {;}
}
42
6.9 对象流
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class ObjectRecov
{ public static void main(String args[])
{ Student stu;
try {FileInputStream fi=new
FileInputStream(“date.ser”);
ObjectInputStream si=new
ObjectInputStream(fi);
stu=(Student)si.readObject();si.close();
}catch(Exception e) {System.out.println(e);}
System.out.println(“ID:,+stu.id+“name:”+
stu.name+“age:”+age+“dept.:”+stu.department);
}
}
43
6.10 流的分类
InputStream和 OutputStream是所有输入输出流的祖先,它们是一个抽象类,System.in和
System.out是它们的子类
InputStream
FileInputStream
PipedIntputStream
FilterInputStream
ByteArrayInputStream
DataInputStream
BufferedInputStream
LineNumberInputStream
SequencedInputStream
StringBufferInputStream
PushbackInputStream
44
6.10 流的分类
InputStream中的基本方法包括,
read,available,mark,skip,reset,
markSuppposed,close
OutputStream中的基本方法包括,
write,flush,close
OutputStream
FileOutputStream
PipeOutputStream
FilterOutputStream
ByteArrayOutputStream
DataOutputStream
BufferedOutputStream
PrintStream
45
6.11 小结
在 Java中有数据传输的地方都用到 I/O流
(通常是文件,网络,内存和标准输入输出等 )
InputStream 和 OutputStream是所有 I/O流的祖先 (只有 RandomAccessFile类是一个例外 ),read和 write是它们最基本的方法,读写单位是字节,
在众多的流对象中,并不是每一种都单独使用,
其中过滤流的子类在数据送出去之前做必要的处理,
文件 文件输入流 缓冲输入流 行号输入流 数据输入流 目的
46
6.11 小结
File,File(Input/Output)Stream,
RandomAccessFile是处理本地文件的类
Data(Input/Output)Stream是一个过滤流的子类,借此可以读写各种基本数据,在文件和网络中经常使用,如,readByte,writeBoolean等,
Buffered(Input/Output)Stream的作用是在数据送到目的之前先缓存,达到一定数量时再送到目的,已减少阻塞次数,
Piped(Input/Output)Stream适合与一个处理的输出作为另一个处理的输入的情况
47
作业作业,将键盘上输入的一串字符写到文本文件中