文件读写操作
1.基于字节流的文件读写
InputStream类和OutputStream类是所有基于字节流的文件读写核心类的基类,他们支持8位的字节流操作。
1.1InputStream类
JSP对文件的读取操作利用的是ImputStream类的子类FileInputStream类。
FileInputStream的构造函数:
为了提高读写笑了,FileInputStream类经常和BufferedInputStream类配合使用。
BufferedInputStream类实现了一个缓冲的输入流。通过设置这样的输入流,一个应用不必为每个读取的字节调用基本系统就能将字节读入字节流中。数据以分块形式读入缓冲区中,顺序读取能直接存取缓冲区中的数据。
BufferedInputStream的构造函数为:
BufferedInputStream类的基类是:FileInputStream类,FIleInputStream类的基类是InputStream类。
用修饰器模式构造一个BufferedInputStream:
BufferedInputStream buffer=new BufferedInputStream(new FileInputStream("mydata.dat"););
实例:
(1)生成一个输入输出文件类的对象;
(2)调用此类的成员函数read()实现文件数据内容的读取;
(3)关闭此文件。
1 <%@ page language="java" contentType="text/html; charset=GB18030" 2 pageEncoding="GB18030"%> 3 <%@page import="java.io.*" %> 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 5 <html> 6 <head> 7 <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> 8 <title>Insert title here</title> 9 </head> 10 <body> 11 <font size="2"> 12 <% 13 //构造一个文件实例 14 File file=new File("/home/jim/Development/apache-tomcat-7.0.30/webapps/ROOT/WEB-INF/web.xml"); 15 %> 16 读取文件<%=file.getPath() %>:<br><br> 17 <% 18 try{ 19 //修饰器模式构造缓冲的输入流 20 BufferedInputStream buffer=new BufferedInputStream( 21 new FileInputStream(file)); 22 byte output[]=new byte[(int)file.length()]; 23 int count=0; 24 //读取文件 25 while((count=buffer.read(output))!=-1){ 26 String str=new String(output,0,count); 27 //过滤特殊字符“<"">" 28 str=str.replaceAll("<", "<"); 29 str=str.replaceAll(">", ">"); 30 str=str.replaceAll("\r\n", "<br>"); 31 out.println(str); 32 } 33 //关闭输入流 34 buffer.close(); 35 //意外处理 36 }catch(IOException e){} 37 %> 38 </font> 39 </body> 40 </html>
注意:
在jsp程序中使用FileInputStream流风格的读取操作有个缺点:不容易处理文件中的格式化问题。它不能逐行格式化地读取文件。
1.2OutputStream
FileOutputStream提供了文件写入操作的能力。FileOutputStream类具有其抽象基类OutputStream类的全部方法.
FileOutputStream的构造函数:
BufferedOutputStream类的构造方法:
下面的例子掩饰了文件的读写操作:
1 <%@ page language="java" contentType="text/html; charset=GB18030" 2 pageEncoding="GB18030"%> 3 <%@page import="java.io.*" %> 4 <html> 5 <head> 6 <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> 7 <title>Insert title here</title> 8 </head> 9 <body> 10 <font size="2"> 11 <% 12 //构造一个文件实例 13 File file=new File("/home/jim/Development/apache-tomcat-7.0.30/webapps/ROOT/chat.log"); 14 //设定为中文编码,解决乱码问题 15 request.setCharacterEncoding("GB18030"); 16 String name=request.getParameter("name"); 17 if(name==null) name="default user"; 18 request.getSession().setAttribute("name", name); 19 String msg=request.getParameter("msg"); 20 %> 21 </font> 22 <form action="Ex6_6.jsp" name="chat" method="post"> 23 姓名<input type="text" name="name" value="<%=request.getSession().getAttribute("name")%>"> 24 发言<input type="text" name="msg" > 25 <input type="submit" name="提交" value="Submit"> 26 </form> 27 <font size="2"><br> 28 <br> 29 30 <% 31 try{ 32 //修饰器模式构造缓冲的输出流 33 BufferedOutputStream bufferout=new BufferedOutputStream( 34 new FileOutputStream(file)); 35 String ChatMsg=request.getSession().getAttribute("name")+ 36 ":"+msg+"<BR>"; 37 byte[] writebytes=ChatMsg.getBytes(); 38 //写入文件 39 bufferout.write(writebytes); 40 //刷新文件 41 bufferout.flush(); 42 //关闭文件 43 bufferout.close(); 44 45 //修饰器模式构造缓冲的输入流 46 BufferedInputStream bufferin =new BufferedInputStream( 47 new FileInputStream(file)); 48 byte output[]=new byte[(int)file.length()]; 49 int count=0; 50 //读取文件 51 while((count =bufferin.read(output))!=-1){ 52 String str=new String(output,0,count); 53 out.println(str); 54 } 55 //关闭输入流 56 bufferin.close(); 57 }catch(IOException e){}//意外处理 58 %> 59 </font> 60 </body> 61 </html>
注意:当完成写入操作后,必须调用flush方法将缓存中的数据写入文件。
2.基于字符流的文件读写
2.1抽象Reader类
抽象Reader类的方法:
2.2抽象Writer类
方法:
抽象的Reader类和Writer类是其他复杂的Reader/Writer类的基类。
2.3FileReader类和FileWriter类
FileReader类的构造函数:
FileWriter类的构造函数:
与FileReader类和FileWriter类配合使用的一组缓冲流BufferedReader类和BufferedWriter类,在提高读写效率的同时,BufferedReader类还提供了读取一行的方法String readLine();BufferedWriter类提供了方法newLine()向文件中写入一个行分隔符。
实例:
该例子是一个简单的聊天程序,通过向同一文件中追加内容从而记录聊天内容。
1 <%@ page language="java" contentType="text/html; charset=GB18030" 2 pageEncoding="GB18030"%> 3 <%@page import="java.io.*" %> 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 5 <html> 6 <head> 7 <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> 8 <title>Insert title here</title> 9 </head> 10 <body> 11 <font size="2"> 12 <% 13 //构造一个文件实例 14 File file=new File("/home/jim/Development/apache-tomcat-7.0.30/webapps/ROOT/chat.log"); 15 //设定中文编码,解决乱码问题 16 request.setCharacterEncoding("GB18030"); 17 //获取表单变量,并利用sesssion存储 18 String name=request.getParameter("name"); 19 if(name==null) name="default user"; 20 String msg=request.getParameter("msg"); 21 if(msg==null) msg="Empty"; 22 boolean refresh=true; 23 if(msg.equals(request.getSession().getAttribute("msg")) 24 &&name.equals(request.getSession().getAttribute("name"))) 25 refresh=false; 26 request.getSession().setAttribute("msg", msg); 27 request.getSession().setAttribute("name", name); 28 %> 29 </font> 30 <form action="Ex6_7.jsp" name="chat" method="post"> 31 姓名<input type="text" name="name" value="<%=request.getSession().getAttribute("name")%>"> 32 发言<input type="text" name="msg" value="<%=request.getSession().getAttribute("msg")%>"> 33 <input type="submit" name="提交" value="Submit"> 34 </form> 35 <font size="2"><br> 36 <br> 37 <% 38 try{ 39 if(refresh){ 40 //修饰器模式构造缓冲的输出流,使用可以追加的方式写入 41 BufferedWriter bufferout=new BufferedWriter(new FileWriter(file,true)); 42 String ChatMsg=request.getSession().getAttribute("name")+":"+msg+"<br>"; 43 //写入文件 44 bufferout.write(ChatMsg); 45 //刷新文件 46 bufferout.flush(); 47 //关闭文件 48 bufferout.close(); 49 } 50 //修饰器模式构造缓冲的输入流 51 BufferedReader bufferin=new BufferedReader(new FileReader(file)); 52 String output=null; 53 //读取文件 54 while((output=bufferin.readLine())!=null){ 55 out.println(output); 56 } 57 //关闭输入流 58 bufferin.close(); 59 }catch(IOException e){}//意外处理 60 %> 61 </font> 62 </body> 63 </html>
3.基于数据流的文件读写
基于数据流的文件读写操作是通过DataInputStream类和DataOutputStream类完成的。
这是一组流式风格的读写类,称为数据输入流和数据输出流。
这两个类通过对底层字节流的封装,提供了与机器无关读写Java原始数据的能力。也就是说读写操作总,不必再关心这个数值的字节数。
3.1DataInputStream类
构造函数:
3.2DataOutputStream类
构造函数:
实例:
1 <%@ page language="java" contentType="text/html; charset=GB18030" 2 pageEncoding="GB18030"%> 3 <%@page import="java.io.*" %> 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 5 <html> 6 <head> 7 <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> 8 <title>Insert title here</title> 9 </head> 10 <body><div align="center"> 11 <% 12 String action=request.getParameter("action"); 13 request.setCharacterEncoding("GB18030"); 14 if("submit".equals(action)){ 15 File file=new File("/home/jim/Development/apache-tomcat-7.0.30/webapps/ROOT/notebook.log"); 16 String name=request.getParameter("name"); 17 String words=request.getParameter("words"); 18 try{ 19 DataOutputStream dataout=new DataOutputStream( 20 new BufferedOutputStream(new FileOutputStream(file))); 21 dataout.writeUTF(name); 22 dataout.writeUTF(words); 23 dataout.close(); 24 }catch(IOException e){} 25 } 26 %> 27 <table width="53%" border="0" cellpadding="0" cellspacing="0"> 28 <tr> 29 <td width="53%" height="493" rowspan="2"><div align="center"> 30 <table width="88%" height="420" border="1" cellpadding="0" 31 cellspacing="0" > 32 <tr> 33 <td><font size="1"> 34 <% 35 File file=new File("/home/jim/Development/apache-tomcat-7.0.30/webapps/ROOT/notebooke.log"); 36 try{ 37 DataInputStream datain=new DataInputStream(new BufferedInputStream( 38 new FileInputStream(file))); 39 String name=""; 40 String words=""; 41 while((name=datain.readUTF())!=null){ 42 byte translate[]=name.getBytes("ISO-8859-1"); 43 name =new String(translate); 44 words=datain.readUTF(); 45 translate=words.getBytes("ISO-8859-1"); 46 words=new String(translate); 47 out.print(name+":<br>"); 48 out.print("<p>"+words+"<p><br>"); 49 } 50 datain.close(); 51 }catch (IOException e){ } 52 %> 53 </font> 54 </td> 55 </tr> 56 </table> 57 </div> 58 </td> 59 </tr> 60 <td height="334"> 61 <form action="Ex6_8.jsp?action=submit" method="post" name="form1"> 62 <p><textarea rows="15" cols="30" name="words"></textarea></p> 63 <table width="98%" border="0"> 64 <tr> 65 <td> 66 <div align="center"> 67 <font size="2"> 68 您是:</font> 69 <input name="name" type="text" size="9"> 70 </div> 71 </td> 72 <td> 73 <div align="center"> 74 <input type="submit" name="submit3" value="发表公告"> 75 </div> 76 </td> 77 </tr> 78 </table> 79 </form></td> 80 </tr> 81 </table></div> 82 </body> 83 </html>
上面的程序中,利用了DataInputStram类的readUTF()方法和DataOutputStream类的writeUTF()方法完成读写操作。
这两个方法是以UTF编码格式在文件中读写自负。
而程序的页面编码和表单传送变量都是采用GB2312编码。因此程序采用了getByes("ISO-8850-1")以相应的编码读取字符,从而避免中文乱码问题。
4.基于对象流的文件读写
基于对象流的文件读写技术提供了一种方法:以文件为存储介质,将对象持久化存储,并且在需要的时候以对象的方式读取文件。
这样能够大大方便业务逻辑的实现,因为这时在考虑程序的时候只需要关心若干个对象的读写,而不需要去考虑每个属性,甚至每个字节的编码、格式和其他细节。
对象流读写是通过ObjectInputStream类和ObjectOutputStream类来支持的。
4.1 ObjectInputStream类
构造函数:
4.2ObjectOutputStream类
构造函数:
4.3readObject方法和writeObject方法
使用writeObject方法将一个对象写入该流。任一对象,包括串和数组,均采用writeObject方法被写入。也能将多个对象或基类型对象写入此流。反过来,必须以这些对象被写入的相同类型和相同顺序,从相应的ObjectInputStream流中以readObject方法读出这些对象。
基于对象流的读写要求对象具有序列化的特性。只有支持java.io.Serializable或java.io.Externalizeble接口的对象才能从流中读取。只有支持java.io.Serializable接口的对象才能被写入该流。序列化保证了对象能以“流”的状态读写。
而一个常用的技术是把对象用一些容器装起来。java核心包提供了很多集合类容器。例如Vector类,Hashtable类以及他们的子类。这些类实现了Serializable接口,因此可以在流中读写。这样读写的时候可以更少考虑对象的次序,因为这样只需在流里面读写一个容器类的对象。而获取容器类存储的业务对象,可以使用容器类的方法。
下面的这个例子演示了基于对象流的文件读写操作,首先是一个序列化的java类Article。
1 package samples.javabean; 2 import java.io.Serializable; 3 import java.sql.Timestamp; 4 5 6 public class Article implements Serializable{ 7 String author; 8 String content; 9 Timestamp date; 10 11 public Article(){ 12 this.author="default author"; 13 this.content="empty"; 14 this.date=new Timestamp(System.currentTimeMillis()); 15 } 16 17 public String getAuthor() { 18 return author; 19 } 20 21 public void setAuthor(String author) { 22 this.author = author; 23 } 24 25 public String getContent() { 26 return content; 27 } 28 29 public void setContent(String content) { 30 this.content = content; 31 } 32 33 public Timestamp getDate() { 34 return date; 35 } 36 37 public void setDate(Timestamp date) { 38 this.date = date; 39 } 40 41 }
1 <%@ page language="java" contentType="text/html; charset=GB18030" 2 pageEncoding="GB18030"%> 3 <%@page import="java.util.*"%> 4 <%@ page import="java.io.*" %> 5 <%@ page import="samples.javabean.*" %> 6 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 7 <html> 8 <head> 9 <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> 10 <title>Insert title here</title> 11 <% 12 File file=new File("/home/jim/Development/apache-tomcat-7.0.30/webapps/ROOT/chatlist.log"); 13 if(!file.exists()){ 14 file.createNewFile(); 15 ObjectOutputStream newfile=new ObjectOutputStream(new FileOutputStream(file)); 16 ArrayList list=new ArrayList(); 17 newfile.writeObject(list); 18 newfile.flush(); 19 newfile.close(); 20 } 21 request.setCharacterEncoding("GB18030"); 22 String author=request.getParameter("name"); 23 String content=request.getParameter("msg"); 24 String action=request.getParameter("action"); 25 %> 26 </head> 27 <body> 28 <font size="2"> 29 <form name="chat" method="post" action="Ex6_9.jsp?action=submit"> 30 姓名<input type="text" name="name"> 31 发言<input type="text" name="msg"> 32 <input type="submit" name="提交" value="Submit"> 33 </form> 34 <% 35 ObjectInputStream o=new ObjectInputStream(new FileInputStream(file)); 36 ArrayList msglist=(ArrayList)(o.readObject()); 37 o.close(); 38 if(msglist==null){ 39 msglist=new ArrayList(); 40 } 41 if("submit".equals(action)){ 42 Article new_msg=new Article(); 43 new_msg.setAuthor(author); 44 new_msg.setContent(content); 45 msglist.add(new_msg); 46 ObjectOutputStream output =new ObjectOutputStream(new FileOutputStream(file)); 47 output.writeObject(msglist); 48 output.flush(); 49 output.close(); 50 } 51 for(Iterator<Object> it=msglist.iterator();it.hasNext();){ 52 Article msg=(Article)it.next(); 53 out.print(msg.getAuthor()+":"); 54 out.print(msg.getContent()+"("); 55 out.print(msg.getDate()+")<br>"); 56 } 57 %> 58 </font> 59 </body> 60 </html>
执行结果:
程序中将Article对象放入一个ArrayList对象中,然后将ArrayList对象写入文件,并且从文件独处。这里要求ArrayList对象和Article对象都是可序列化的。
5.随机文件读写
可以同时进行读取和写入操作。
RandomAccessFile类:
构造函数:
参数name或者file指向了一个文件。参数mode表示打开文件的方式。可以取r表示可读,rw表示可读可写。
RandomAccessFile类提供了一个方法seek,用来移动RandomAccessFile对象指向的文件的指针。他的long型参数表示指针与文件开头的偏移量。同时还有一个方法getFilePointer取得文件指针当前的偏移位置。通过控制文件指针,RandomAccessFIle类可以完成对文件的随即读写操作。
下面的例子是利用了RandomAccessFile类完成分页读取文件的功能简单的例子:
1 <%@ page language="java" contentType="text/html; charset=GB18030" 2 pageEncoding="GB18030"%> 3 <%@ page import="java.io.*" %> 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 5 <html> 6 <head> 7 <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> 8 <title>Insert title here</title> 9 </head> 10 <body> 11 <% 12 File file=new File("/home/jim/Development/apache-tomcat-7.0.30/webapps/ROOT/RELEASE-NOTES.txt"); 13 int pagesize=1000; 14 int pagemax=(int)file.length()/pagesize; 15 String pagenum=request.getParameter("pagenum"); 16 int pages; 17 if(pagenum==null) pages=0; 18 else 19 { 20 pages=new Integer(pagenum).intValue(); 21 if(pages<0) pages=0; 22 else if(pages>pagemax) pages=pagemax; 23 } 24 %> 25 读取文件<%=file.getPath() %>:<br><br> 26 <a href="Ex6_10.jsp?pagenum=<%=pages-1 %>">上一页</a><--------> 27 <a href="Ex6_10.jsp?pagenum=<%=pages+1 %>">下一页</a><br><br> 28 <% 29 try{ 30 RandomAccessFile random=new RandomAccessFile(file,"r"); 31 long offset=pagesize*pages; 32 random.seek(offset); 33 byte content[]=new byte[pagesize]; 34 int count=0; 35 count=random.read(content); 36 String str=new String(content,0,count); 37 str=str.replace("<", "<"); 38 str=str.replace(">", ">"); 39 str=str.replace("\r\n", "<br>"); 40 out.println(str); 41 random.close(); 42 }catch(IOException e){} 43 %> 44 </body> 45 </html>