这是今天在写画板保存时用到了输入输出流时,由于之前对这些模糊,而且在今后通信的那一块当中用得特别多,想要把这一节的内容弄的清楚,所以就去找了好多的资料,来深入理解。下面理解纯属个人看法,欢迎提异。
java输入输出流的功能十分的强大,但是java.io package包装了许多的不同的对象,涉及的范围也是很广的。它主要包括了有字节、字符、文件流这些。但是现在我们接触的比较多的是InoutStream(字节输入流)和OutputStream(字节输出流),以及其下的文件字节输入输出流FileInputStream和FileOutputStream。另外还有字符输入输出流Reader和Writer类。在此附图一张方便理解:
这里所说的字符流是指数据序列的基本构成单位是16位的Unicode字符数据,如各类基于字符编码的文本文件;字节流是指数据序列的基本构成单位是8位的字节数据,如各类基于二进制数据的文件。
其实说这些很不好让人理解,因为都是写固有的定义,我们可以根据自己的理解去认识它们。在我们理解某个包或者是类时,重要的是知道方法的运用。所以在这里简单介绍一下相关的方法:
Inputstream的方法:
从流中读取数据:
int read( ); //读取一个字节,返回值为所读的字节
int read( byte b[ ] ); //读取多个字节,放置到字节数组b中,通常读取的字节数量为b的长度,返回值为实际读取的字节的数量
int read( byte b[ ], int off, int len ); //读取len个字节,放置到以下标off开始字节数组b中,返
回值为实际读取的字节的数量
int available( ); //返回值为流中尚未读取的字节的数量
long skip( long n ); //读指针跳过n个字节不读,返回值为实际跳过的字节数量
关闭流: close( ); //流操作完毕后必须关闭
OutputStream的方法:
输出数据:
void write( int b ); //往流中写一个字节b
void write( byte b[ ] ); //往流中写一个字节数组b
void write( byte b[ ], int off, int len ); //把字节数组b中从下标off开始,长度为len的字节写入流中
flush( ) //刷空输出流,并输出所有被缓存的字节,由于某些流支持缓存功能,该方法将把缓存中所有内容强制输出到流中。
关闭流: close( ); //流操作完毕后必须关闭
要熟练的掌握输入输出流中的方法,就必须熟悉这几个基本的方法。其实InputStream和OutputStream的方法中是相互对应的关系。所以记忆起来就比较方便。下面通过例子来加深印象。这个例子是用IO来实现文件的copy的:
public void copy(String sta,String end){
//传入源文件和复制到的文件路径
//例如:sta = "C:\\Users\\Administrator\\Desktop\\test.txt";
//例如:end = "C:\\Users\\Administrator\\Desktop\\test1.txt";
try {
//输入输出流
InputStream ins = new FileInputStream(sta);
OutputStream ous = new FileOutputStream(end);
int aa = ins.read();//读取一个字节的数据
while(aa != -1){
ous.write(aa);//将读到的字节写入end文件
aa = ins.read();
}
ins.close();//关闭输入流
ous.flush();//强制写出输出流中剩余数据
ous.close();//关闭输出流
} catch (Exception e) {
e.printStackTrace();
}
}
但是在这种情况下,文件的复制还是相当慢的,所以我们这是要用到BufferedInputStream(输入缓冲流)和BufferedOutputStream(输出缓冲流)。这里要注意的是他们的构造器就行了,就是分别传入InputStream和OutputStream。其他的用法与上面相似。
当然这是IO最简单的。还有稍微复杂的在后面一点。
例如在画板的保存问题上,我们要把n条直线先保存在某个文件里,然后在打开时将这些直线画出来。这里的话先参看代码:(这里只有菜单项的监听器类):
public void actionPerformed(ActionEvent e) {
cmd = e.getActionCommand();
JFileChooser jf = new JFileChooser();
if("打开".equals(cmd)){
//打开选中的文件选择框的文件
jf.showOpenDialog(null);
File file = jf.getSelectedFile();
try {
InputStream ins = new FileInputStream(file);//文件输入流
DataInputStream dis = new DataInputStream(ins);
byte len = dis.readByte();//读出直线条数
for(int i=0;i<len;i++){//读出直线的四个参量,并绘制直线
int x1 = dis.readInt();
int y1 = dis.readInt();
int x2 = dis.readInt();
int y2 = dis.readInt();
g.drawLine(x1, y1, x2, y2);//画线
}
dis.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}else if("保存".equals(cmd)){
jf.showSaveDialog(null);
File file = jf.getSelectedFile();//文件选择框
try {
OutputStream ous = new FileOutputStream(file);//文件输出流
DataOutputStream dos = new DataOutputStream(ous);
dos.writeByte(Main.list.size());//写入直线的条数
for(int i = 0;i<Main.list.size();i++){
//从队列中循环取出直线对象赋给新创建的直线对象
//分别写入直线的四个参量
Line line = Main.list.get(i);
dos.writeInt(line.x1);
dos.writeInt(line.y1);
dos.writeInt(line.x2);
dos.writeInt(line.y2);
}
dos.flush();//强制输出
dos.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
其实在这里的话呢是说,我们先写到文件里的数据就应该是先读出来,而且起哄的对应先后关系自己一定熟悉,否则必会出错,这里首先是写入直线的条数,然后将直线的四个点的参数写入,每画一条就多写入四个数据。同理,在读取的时候,也是这个先后关系。更要注意的是,对应输入输出的数据的类型也是要对应的。还有其他的图形、图片等等数据的都是要一样的对待。这里在后面的通信问题上也是,同样我们可以根据这个道理,可以很简便的对文件进行加密。所以加密的原理就在此,很简单。
这些都还只是写简单的,后面学习过程中有新的理解会及时更新。