文件可以永久地存储信息,从本质上讲文件就是存放在盘上的一系列数据的集合。应用程序如果想长期保存数据,就必须将数据存储到文件中,这就涉及到文件的操作。而在编写网站应用程序的过程中,有许多地方要对文件进行操作。

本章将要对JSP中文件操作的应用作一些介绍,如读写文件、上传下载文件、创建删除目录等。

7.1 数据流和File类

数据从一个输入源获得。程序的结果被送到输出目的地。这些源和目的地被广泛地定义。例如一个网络连接器,内存缓冲区或磁盘文件可以被输入/输出类熟练地操作,这些外设都由相同的抽象体流(stream)来处理。

流,是一个生产或消费信息的逻辑实体。流通过输入/输出系统与物理设备相连。尽管与之相连的实际的物理设备各不相同,所有的流都以同样的方式运转。

7.1.1 数据流

Java定义了两种数据流:字节流字符流

  • 字节流:为处理字节式输入/输出提供了丰富的环境,其处理单元为1个字节,操作字节和字节数组。
  • InputStream:抽象类是表示字节输入流的所有类的超类。
    需要定义 InputStream 的子类的应用程序必须始终提供返回下一个输入字节的方法。
  • OutputStream:此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。
    需要定义 OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法
  • 字符流:提供了处理任何类型输入/输出操作的足够的功能,字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串。
  • Reader:用于读取字符流的抽象类。
    子类必须实现的方法只有 read(char[], int, int)close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。用于读取字符流的抽象类。
  • Writer :写入字符流的抽象类。
    子类必须实现的方法仅有 write(char[], int, int)flush()close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。

一个字节流可以和其他任何类型的对象并用,包括二进制数据。这样的多功能性使得字节流对很多类型的程序都很重要。字节流以InputStreamOutputStream为顶层。InputStream(输入流)是一个定义了流式字节输入模式的抽象类,该类的所有方法在出错条件下引发一个IOException异常。OutputStream(输出流)是定义了流式字节输出模式的抽象类,该类的所有方法返回一个void值并且在出错情况下引发一个IOException异常。

字符流ReaderWriter为顶层。Reader是定义Java的流式字符输入模式的抽象类,该类的所有方法在出错情况下都将引发IOException异常。Writer是定义流式字符输出的抽象类,所有该类的方法都返回一个void值并在出错条件下引发IOException异常。

7.1.2 File类

文件和目录路径名的抽象表示形式。

用户界面和操作系统使用与系统相关的路径名字符串来命名文件和目录。此类呈现分层路径名的一个抽象的、与系统无关的视图。

抽象路径名有两个组件:

  • 一个可选的与系统有关的前缀 字符串,比如盘符,/表示 中的根目录,\\ 表示 Microsoft Windows UNC 路径名,
  • 零个或更多字符串名称 的序列。

File类:用于文件系统操作的类

  • Java内建的用来操作文件目录的类File,该类提供新增、删除与修改等操作文件相关功能所需的方法成员。
  • File类没有指定信息怎样从文件读取或向文件存储;
  • 它描述了文件本身的属性。
  • File对象用来获取或处理与磁盘文件相关的信息,例如权限、时间、日期和目录路径。另外,File还浏览子目录层次结构。

可以用来生成File对象的构造函数如下:

File(String directoryPath) File(String directoryPath, String filename) File(File dirObj, String filename)

其中,directoryPath是文件的路径名,filename是文件名,dirObj是一个指定目录的File对象。

第一个构造函数通过全路径—路径文件名来创建对象,pathname可以是绝对路径也可以是相对路径。
第二个构造函数通过父目录和文件名来创建对象,filename是不含路径的文件名。
第三个构造函数也是通过父目录和文件名来创建对象,但父目录由一个File对象提供。

注意:文件的路径有两种形式,即绝对路径和相对路径。绝对路径包含它所指定的文件的完整路径信息,根据绝对路径就可以惟一定位一个文件。而相对路径是针对“其他某个路径”而言的,这个路径和相对路径共同定位一个文件的位置。

File类位于命名空间java.io,因此在JSP网页使用File类之前,必须利用以下的程序代码,将此命名空间载入:

<%@ page import =“java.io.*" %>

方 法

说 明

isDirectory()

返回一个布尔值,true表示为目录,false则表示是文件,借以判断File对象所参考的路径是否为目录

isFile()

返回一个布尔值,true表示为文件,false则表示是目录,借以判断File对象所参考的路径是否为文件

canRead()

返回布尔值,true表示此为允许读取的文件

canWrite()

返回布尔值,true表示此为允许写入的文件

exists()

返回一个布尔值,true表示参考的文件目录存在

getName()

取得File对象所参考的路径底下的目录或文件名称

getPath()

取得File对象所参考的路径字符串

toString()

将File对象转换成为以字符串类型的名称表示

equals()

比较两个File对象是否相等

由于File对象本身仅仅只是参考一个特定的路径,因此上述的路径及文件参数也可能代表一个不存在的文件,在进行文件的操作之前,可以利用exists方法,查看文件是否存在,以判断是否进行相关的文件操作,这一点非常重要,若是尝试存取一个不存在的文件,会让系统产生一个错误的例外对象。

【例7-1】下面的范例演示一个查看文件相关性质的JSP网页实例。查看文件内容(usingFile.jsp)

<%@page contentType="text/html"%>
<%@page pageEncoding="GB2312"%>
<%@page import="java.io.*"%>
<html>
<head><title>运用 File 对象</title></head>
<body>
<% // 先在 C:盘下创建文件夹
String thePath="C:\\ch07\\theFile";
File myDir = new File(thePath);
File myFile = new File(thePath,"testFile.txt" );
File mynotExistFileFile = newFile(thePath,"notExistFile.txt" ) ;
out.println("目录"+thePath+"是否存在:"+myDir.exists()+"<BR>" );
out.println("文件"+thePath+"\\testFile.txt 是否存在:"+myFile.exists()+"<BR>");
out.println("文件"+thePath+"\\notExistFile.txt 是否存在:"+mynotExistFileFile.exists()+"<BR>"+"<BR>");
out.println("文件"+thePath+"\\testFile.txt 是否可读取:"+myFile.canRead()+"<BR> );
out.println("文件"+thePath+"\\testFile.txt 是否可写入:"+myFile.canWrite()+"<BR>");
%>
</body>
</html>

一般文件的维护操作包含了新增、删除及列举等操作,File类本身也提供了相关功能的方法成员,列举如表所示

方 法

说 明

createNewFile()

创建一个新文件

delete()

删除指定的文件

renameTo()

重新命名文件

setReadonly

将文件对象所参照的文件设为只读

mkdir()

建一指定的目录

mkdirs()

建立指定路径底下的所有目录

1、创建文件与目录文件夹

File类提供一个名称为createNewFile()的方法成员,用以建立File对象参数所指定的文件,以下为引用此方法的程序代码范例片段:
boolean blCreate = myFile.createNewFile() ;

由于createNewFile()返回一个布尔值,因此必须利用声明为boolean类型的变量存储运行结果,若是上式blCreate结果值为true,表示文件建立成功;若是false则表示文件建立失败,并且返回一个IOException例外对象,这个情形通常发生在指定的目录底下已经存在所要建立的文件,因此在建立文件之前查看其是否存在是非常重要的操作。

File类另外提供建立目录的方法成员mkdir,必须利用File类的实体对象引用这个方法以建立指定的目录,例如以下的程序代码
File myFile = new File(pathName); bool blMK = myFile.mkdir();

其中的返回值意义同上述CreateNewFile方法,这里必须注意的是,由于引用这个方法所要建立的是一个目录,因此第1行程序代码中所指定的参数值必须是一个路径而非文件,同时指定建立的目录其上层目录的路径必须是存在的,例如下面的程序代码:

boolean blNew;
File myDir = new File("C:/testDir/newDir");
blNew = myDir.mkdir();

其中mkdir()C:/testDir目录下建立一个新的目录newDir,前提是C:/testDir目录必须存在,否则建立目录的作业将会失败。

另外一个类似mkdir()的方法为mkdirs(),这个方法不同的地方在于若是指定的目录路径不存在,则整个目录结构均将被创建,例如以下的程序代码:

File myMkDirs = new File("C:/firstDir/secondDir/thirdDir");
blNew = myMkDirs.mkdirs();

当网页运行该段程序代码的时候,其中C:/firstDir/secondDir/thirdDir这个路径的文件夹以及子文件夹,都会被建立。

2、删除文件与目录数据夹

删除文件或者是目录非常容易,只要引用File类所提供的方法成员delete() 即可。这个方法将会删除File对象本身所代表的文件或是目录,也就是建立File对象,指定路径底下的文件,或是建立对象时所输入的特定目录路径参数。
delete方法有一个布尔类型的返回值,若是成功删除指定删除文件,则返回值为true,当指定的文件不存在,或是指定的文件删除失败,则返回值为false
另外必须特别注意的是,delete方法只能删除空目录,若是目录底下存在任何文件或是子目录,删除的操作会失败,并且返回一个代表删除目录失败的false布尔值。

7.2 读写文本文件

读写文件是文件操作最基本的内容。

读写文本文件所需的功能,主要由2个类所提供:FileWriter()FileReader()

  • FileReader()则用以读取文件中的数据。
    语法如下:FileReader myFileReader = new FileReader(strFileName);必须输入指定操作的文件完整路径名称或是File对象
  • FileWriter()负责将数据写入文件
    语法如下:FileWriter myFileWriter = new FileWriter(fileName); 将数据写入文本文件之前,首先必须建立FileWriter对象,同时传入所要操作的文件完整路径名称字符串.

7.3 文件的浏览

【例7-3】浏览当前目录中文件与子目录的例子browserFile.jsp,例子执行后,会在浏览器中输出当前目录中的所有文件和子目录,并对文件和子目录进行统计。

<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>文件的浏览</title>
</head>
<body>
<h1>文件的浏览</h1>
<%int fcount=0,dcount=0;%>
<%
String path=request.getRealPath("/");
// 建立当前目录中文件的 File 对象
File d=new File(path);
// 取得代表目录中所有文件的 File 对象数组
File list[]=d.listFiles();
out.println("<font color=#ff0000>" + path + "目录下的文件: </font><br>");
// 循环输出当前目录下的所有文件
for(int i=0;i<list.length;i++) {
	if(list[i].isFile()) {
		out.println(list[i].getName() + "<br>");
		fcount++;
	}
}
out.println("<br><font color=#ff0000>" + path + "目录下的目录: </font><br>");
// 循环输出当前目录下的所有子目录
for(int i=0;i<list.length;i++) {
	if(list[i].isDirectory()) {
		out.println(list[i].getName() + "<br>");
		dcount++;
	}
}
%>
<hr>
<h3>统计结果: </h3>
<center>
文件总数: <%=fcount%><br>
目录总数: <%=dcount%><br>
</center>
</body>
</html>

jsp文件怎么写java代码 jsp 写文件_jsp文件怎么写java代码

7.4 创建和删除目录

【例 7-4】编写一个有关目录的创建与删除的例子 Directory.jsp。本例的效果是,如果没有目录文件就创建一个新的目录文件,如果目录文件存在就删除该目录文件。代码如下:

<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>目录的创建、检查与删除</title>
</head>
<body>
<% String path = request.getRealPath("");
path = path + "\\text";
// 将要建立的目录路径
File d = new File(path);
// 建立代表 uploadFile 目录的 File 对象,并得到它的一个引用
if(d.exists()) {
	// 检查 uploadFile 目录是否存在
	d.delete();
	out.println("uploadFile 目录存在,现被删除");
} else {
	d.mkdir();
	// 建立 uploadFile 目录
	out.println("uploadFile 目录不存在,现被建立");
}
%>
</body>
</html>

7.5 文件的上传和下载

【例7-5】 在这里我们写一个简单的页面uploadfile.jsp,提供一个表单,用户从这里选择文件并把文件上载到服务器。

uploadfile.jsp

<%@ page contentType="text/html;charset=gb2312" %>
<html>
<head><title>上传文件</title></head>
<body bgcolor="#ffffff" text="#000000">
<p><b><font size=5>选择要上传文件</font></b></p>
<form METHOD="POST" ACTION="uploadfile1.jsp" ENCTYPE="multipart/form-data">
    <INPUT TYPE="FILE" NAME="FILE1" SIZE="30"><BR>
    <INPUT TYPE="SUBMIT" VALUE="开始上传">
</form>
</body>
</html>

在 uploadfile.jsp 页面中,需要注意的是:

<FORM METHOD="POST" ACTION="uploadfile1.jsp" ENCTYPE="multipart/form-data">

在该语句中, ENCTYPE="multipart/form-data"表示以二进制的方式传递提交的数据。

现在创建处理信息的页面 uploadfile1.jsp, 实现获取文件里面的信息并保存在指定的文件夹upload 内的功能,代码如下:

uploadfile1.jsp

<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.io.*"%>
<%@ page import="java.util.*"%>
<%@ page import="javax.servlet.*"%>
<%@ page import="javax.servlet.http.*"%>
<html><head><title>upFile</title></head>
<body bgcolor="#ffffff">
<%
int MAX_SIZE = 102400 * 102400; //定义上载文件的最大字节
String rootPath; // 创建根路径的保存变量
DataInputStream in = null; //声明文件读入类
FileOutputStream fileOut = null;
String remoteAddr = request.getRemoteAddr(); //取得客户端的网络地址
String serverName = request.getServerName(); //获得服务器的名字
String realPath = request.getRealPath("/");//取得互联网程序的绝对地址
realPath = realPath.substring(0,realPath.lastIndexOf("\\"));
rootPath = realPath + "\\upload\\"; //创建文件的保存目录
out.println("上传文件保存目录为"+rootPath);
String contentType = request.getContentType(); //取得客户端上传的数据类型
try{
	if(contentType.indexOf("multipart/form-data") >= 0){
		in = new DataInputStream(request.getInputStream()); //读入上传的数据
		int formDataLength = request.getContentLength();
		if(formDataLength > MAX_SIZE){
			out.println("<P>上传的文件字节数不可以超过" + MAX_SIZE + "</p>");
			return;
		}
		byte dataBytes[] = new byte[formDataLength]; //保存上传文件的数据
		int byteRead = 0;
		int totalBytesRead = 0;
		while(totalBytesRead < formDataLength){ //上传的数据保存在 byte 数组
			byteRead = in.read(dataBytes,totalBytesRead,formDataLength);
			totalBytesRead += byteRead;
		}
		String file = new String(dataBytes); //根据 byte 数组创建字符串
		String saveFile = file.substring(file.indexOf("filename=\"") + 10); //取得上传数据的文件名
		saveFile = saveFile.substring(0,saveFile.indexOf("\n"));
		saveFile = saveFile.substring(saveFile.lastIndexOf("\\") + 1, saveFile.indexOf("\""));
		int lastIndex = contentType.lastIndexOf("=");
		// 取得数据的分隔字符串
		String boundary = contentType.substring(lastIndex + 1,contentType.length());
		String fileName = rootPath + saveFile;
		int pos;
		pos = file.indexOf("filename=\"");
		pos = file.indexOf("\n",pos) + 1;
		pos = file.indexOf("\n",pos) + 1;
		pos = file.indexOf("\n",pos) + 1;
		int boundaryLocation = file.indexOf(boundary,pos) - 4;
		int startPos = ((file.substring(0,pos)).getBytes()).length;//取得文件数据的开始的位置
		// 取得文件数据的结束的位置
		int endPos = ((file.substring(0,boundaryLocation)).getBytes()).length;
		File checkFile = new File(fileName); //检查上载文件是否存在
		if(checkFile.exists()){
			out.println("<p>" + saveFile + "文件已经存在.</p>");
		}
		File fileDir = new File(rootPath);//检查上载文件的目录是否存在
		if(!fileDir.exists()){
			fileDir.mkdirs();
		}
		fileOut = new FileOutputStream(fileName); //创建文件的写出类
		fileOut.write(dataBytes,startPos,(endPos - startPos)); //保存文件的数据
		fileOut.close();
		out.println("<P><font color=red size=5>" + saveFile + "文件成功上传.</font></p>");
	} else {
		String content = request.getContentType();
		out.println("<p>上传的数据类型不是是 multipart/form-data</p>");
	}
} catch(Exception ex) {
	throw new ServletException(ex.getMessage());
}
%>
<a href="uploadfile.jsp">继续上传文件</a>
</body>
</html>

代码中首先获取了上传文件的相关属性信息和文件内容,然后将获取的信息转换为指定格式的文件保存在服务器上。用 request 对象获取相关信息。 然后在保存文件之前使用 if(checkFile.exists())判断上传文件是否存在,使用 if(!fileDir.exists())判断保存的文件目录是否存在,判断结束后,使用fileOut.write(dataBytes,startPos,(endPos-startPos))语句保存文件信息。

让一个已知文件类型直接提示浏览者下载,而不是用它相关联的程序打开。以下用例子说明如何操作。创建两个 jsp 页面共同完成该功能,一个 Downfile.jsp 页面主要显示指定文件夹 upload 中要下载的文件对象,可以由客户选择其中之一;另一个文件 Downfile1.jsp 从服务器获取相关下载信息,把数据输出到客户端。

Downfile.jsp

<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.io.File" %>
<%@ page import="java.io.FilenameFilter" %>
<HTML>
<head><title>显示现在文件</title></head>
<body>
<center>
<h3>请选择要下载的文件</h3>
<table>
<%
    String path = request.getRealPath("/");
    File file1 = new File(path, "\\upload");
    String str[] = file1.list();
    for (int i = 0; i < str.length; i++) {
        String ss = str[i];
        out.println("<tr><td>" + ss + "</td><td><a href='Downfile1.jsp?name1=" + ss + "'>下载</a></td></tr>");
    }
%>
</table>
<center>
</body>
</HTML>

在该文件中,使用创建的 File 对象调用 list()方法,将指定文件夹 upload 中所有文件显示并可以选择下载保存。

Downfile1.jsp

<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.io.*" %>
<% response.reset();
try {
    String str = request.getParameter("name1"); //获得响应客户的输出流:
    str = new String(str.getBytes("iso8859-1"), "gb2312");
    String path = request.getRealPath("/");
    path = path.substring(0, path.lastIndexOf("\\"));
    path = path + "\\upload\\";
    File fileLoad = new File(path, str);//下载文件位置:
    response.reset();
    OutputStream o = response.getOutputStream();
    BufferedOutputStream bos = new BufferedOutputStream(o);
    byte b[] = new byte[500]; //输出文件用的字节数组,每次发送 500 个字节到输出流:
    response.setHeader("Content-disposition", "attachment;filename=" + new
            String(str.getBytes("gb2312"), "iso8859-1")); //客户使用保存文件的对话框
    response.setContentType("application/x-tar");//通知客户文件的 MIME 类型:
    long fileLength = fileLoad.length();//通知客户文件的长度:
    String length = String.valueOf(fileLength);
    response.setHeader("Content_Length", length);
    FileInputStream in = new FileInputStream(fileLoad);//读取文件,并发送给客户下载:
    int n = 0;
    while ((n = in.read(b)) != -1) {
        bos.write(b, 0, n);
    }
    bos.close();
} catch (Exception e) {
    System.out.print(e);
}
response.reset();
%>

7.6 使用jspSmartUpload上传包

首先介绍如何安装所需的包,从网站上下载jspsmartupload.jar这个文件,将此文件放到网站WEB-INF\lib的文件夹下,接下来就可以在JSP网页当中使用此包。
在网页当中引用包的时候,必须以下式将其载入:
<%@page import="com.jspsmart.upload.*" %>

上传文件的类是一种JavaBean组件,在使用前要先实例化,代码如下:

<jsp:useBean id="theSmartUpload" class="com.jspsmart.upload.SmartUpload" />

这段语法声明网页当中将以id值theSmartUpload为名称,引用SmartUpload这个组件,进行文件上传操作。

jspSmartUpload提供了相当丰富的功能,其中最简单的方式便是引用SmartUpload类的方法成员,其中包含了3个步骤:初始化、上传和存储文件。

1、初始化SmartUpload对象

在引用SmartUpload之前,必须对其进行初始化,方法initialize()用来完成初始化操作,语法如下(其中的theSmartUpload为SmartUpload的名称,pageContext则是初始化过程所需的对象):
theSmartUpload.initialize(pageContext) ;

初始化完成之后,就可以开始准备上传文件的操作。在此之前,还必须引用setTotalMaxFileSize()方法,设置所允许的文件大小,下面的程序代码设置一个最大为10MB的上传限制。
theSmartUpload.setTotalMaxFileSize(10*1024*1024) ;

2、上传

初始化完成之后,紧接着直接调用upload(),开始进行上传操作,其语法如下:theSmartUpload.upload() ;

需要注意的是,这个方法没有任何参数,它将表单上所有指定的文件直接上传。

3、存储文件

存储文件是上传的最后一个步骤,save()用来指定上传之后文件所要保存的位置,其语法如下(其中的fileSavePath代表上传之后的文件所要存储的位置):
fileCount=theSmartUpload.save(fileSavePath) ;

save()方法完成文件的存储工作之后,便会返回一个表示上传文件数目的整数值,上式的fileCount用来存储这个值。

了解相关的基础用法,接下来要说明上传文件的表单,通常必须提供一个文件地址框,让用户输入所要上传的文件名称及完整路径,然后进行上传。一般来说,HTML文件输入方块标签,便可以提供所需的功能,如:<input type=file name=File1 size=50 />

最后必须注意的是,用来容纳文件标签的表单,其编码格式必须设置为multipart/form-data,才能在文件传输的过程中进行正确的编码,如:<form action=actionpage enctype="multipart/form-data" >

【例7-6】现在来看看一个简单的范例,其中演示了最简单的文件上传功能(注:该代码运行前需要在C盘上创建upload文件夹)

文件上传(FileUpload.html)代码如下:

<html>
<head>
    <title>jspSmartUpload</title>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body>
upload file<br>
<form action="upload.jsp" method="post" enctype="multipart/form-data">
    <table>
        <tr>
            <td>name:
                <input type="file" name="file2" size="20"></td>
        </tr>
        <tr>
            <td><input type="submit" value="上传"></td>
        </tr>
    </table>
</form>
</body>
</html>

upload.jsp 代码如下:

<%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %>
<%@ page import="com.jspsmart.upload.*" %>
<jsp:useBean id="mySmartUpload" scope="page" class="com.jspsmart.upload.SmartUpload"/>
<html>
<head>
    <title>上载附件 </title>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body>
<%  //上载附件
    try {
        mySmartUpload.initialize(pageContext);
        mySmartUpload.service(request, response);
        mySmartUpload.upload();
        String fn = mySmartUpload.getFiles().getFile(0).getFileName();
        mySmartUpload.save("c:\\upload");//文件保存的目录为 upload
        out.println("已经成功上传了文件");
    } catch (Exception e) {%><a href=FileUpload.html>重新上传</a><%
        e.printStackTrace();
    }
%>
<a href=FileUpload.html>继续上传</a>
</body>
</html>

7.7 使用Commons-FileUpload上传包

Commons FileUpload提供了相当丰富的功能,其中最简单的方式便是采用以下方法进行文件的操作。

  • DiskFileItemFactory:设置磁盘空间,保存临时文件。这只是一个具类。
    DiskFileItemFactory factory=new DiskFileItemFactory();
  • ServletFileUpload:文件上传的核心类,此类接收request,并解析reqeust。
    ServletFileUpload upload=new ServletFileUpload(factory);
  • 进行文件解析后放在List中,因为这个类库支持多个文件上传,因此会把结果保存在List中。
    List<FileItem>fileList=upload.parseRequest(request);
  • 获取上传文件,进行分析。
    File remoteFile = new File(new String(fileItem.getName().getBytes(),"UTF-8"));