话说long long ago,在本人开发项目时,需要导入一个文件夹(目录)下的文件,通过解析其中的数据并入库。
选择一个文件目录,好像没有这个控件。开始想到了不选目录,选文件。但是要选多个文件哦,而且数目不固定。
用file文件浏览不好,想到了用swfUpload可以选择多个文件。可以做到,但是还是选择文件不是选择目录。
不过我想要的,想呀想的……
诶~可以用ExtJS,自己扩展一个还是可以的。于是就有了今天这篇文章和这个文件浏览器。
extFileBrowser.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Ext 文件浏览选择器</title> <meta http-equiv="author" content="hoojo"> <meta http-equiv="email" content="[email protected]"> <meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"> <meta http-equiv="ext-lib" content="v2.2.1"> <meta http-equiv="version" content="v1.0"> <meta http-equiv="content-type" content="text/html; charset=gbk"> <link rel="stylesheet" type="text/css" href="ext-2.2/resources/css/ext-all.css" /> <script type="text/javascript" src="ext-2.2/adapter/ext/ext-base.js"></script> <script type="text/javascript" src="ext-2.2/ext-all.js"></script> <script type="text/javascript" src="Ext.hoo.component.FileBrowserComponent.js"></script> <script type="text/javascript"> Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = "ext-2.2/resources/images/default/s.gif"; var fileBrowser = new Ext.hoo.component.FileBrowserWindow(); //var fileBrowser = new Ext.hoo.component.FileBrowserPanel(); fileBrowser.show(); fileBrowser.tree.getSelectionModel().on("beforeselect", function (sm, node) { //只能选择文件夹,如果要选择文件修改这里即可 var flag = ((!node || (!!node && !!node.leaf)) || !(node.attributes.path.indexOf(":") != -1)) ? true : false; fileBrowser.buttons[0].setDisabled(flag); fileBrowser.buttons[1].setDisabled(flag); }, fileBrowser.tree); }); </script> </head> <body> </body> </html>
Ext.hoo.component.FileBrowserComponent.js
/** * Ext.hoo.component.FileBrowserWindow 系统文件浏览选择组件,可以选定电脑上的文件或文件夹 * @author: hoojo * @createDate 2010-10-17 * @email: [email protected] * @blog: http://blog.csdn.net/IBM_hoojo * @ext_lib: v2.2 * @version 1.0 */ Ext.ns("Ext.hoo.component"); Ext.hoo.component.FileBrowserWindow = Ext.extend(Ext.Window, { constructor: function (config) { config = config || {}; Ext.apply(this, config); this.tree = new Ext.hoo.tree.FileSystemTree(); Ext.hoo.component.FileBrowserWindow.superclass.constructor.call(this, { renderTo: Ext.getBody(), width: 300, height: 300, frame: true, layout: "fit", border: false, title: "请选择", items: this.tree, buttons: [{ text: "新建", disabled: true, handler: this.onNewHandler, scope: this }, { text: "确定", disabled: true, handler: this.onOkHandler, scope: this }, { text: "取消", handler: function () { this.hide(Ext.getBody()); }, scope: this }] }); }, onNewHandler: function () { this.setPath(); this.setFile(); Ext.Msg.prompt("新建文件", "请输入文件夹名称", this.onCreateDir, this); }, onOkHandler: function () { this.setPath(); this.setFile(); Ext.Msg.alert("路径", this.getPath()); }, onCreateDir: function (btn, text) { if (btn == "ok") { var path = this.getPath(); var node = this.getFile(); var dirName = text; if (!!path && !!dirName) { //本地添加模式 /*var newNode = new Ext.tree.AsyncTreeNode({ text: dirName, path: node.attributes.path + "/" + dirName }); node.expand(true, true); node.appendChild(newNode);*/ //远程加载模式 Ext.Ajax.request({ url: Ext.hoo.tree.FileSystemTree.TREE_CREATE_DIR_URL, params: {path: encodeURIComponent(path), dirName: encodeURIComponent(dirName)},//处理中文文件名,乱码问题 success: function (response, options) { var returnNnode = Ext.decode(response.responseText); node.appendChild(returnNnode); node.expand(true); }, failure: function (response) { Ext.Msg.alert("程序异常", response.responseText); } }); } } }, setPath: function () { this.path = this.tree.getSelectedNode().attributes.path || ""; }, setFile: function () { this.nodeFile = this.tree.getSelectedNode() || {}; }, getPath: function () { return this.path; }, getFile: function () { return this.nodeFile; } }); /** * Ext.hoo.component.FileBrowserPanel 系统文件浏览选择组件,可以选定电脑上的文件或文件夹 * 不同于上面的是,这里是一个panel。有时候弹出window,并不能达到预想的效果。特别是window弹出在 * iframe中的Object对象上面,如:在播放器上面弹出此组件,拖动windwo的效果不理想。 * 这时就需要用模态,模态嵌入FileBrowserPanel组件即可 * @author: hoojo * @createDate 2010-10-17 * @email: [email protected] * @blog: http://blog.csdn.net/IBM_hoojo * @ext_lib: v2.2 * @version 1.0 */ Ext.hoo.component.FileBrowserPanel = Ext.extend(Ext.Panel, { constructor: function (config) { config = config || {}; Ext.apply(this, config); this.tree = new Ext.hoo.tree.FileSystemTree(); Ext.hoo.component.FileBrowserPanel.superclass.constructor.call(this, { renderTo: Ext.getBody(), border: false, width: 300, height: 400, layout: "fit", title: "请选择", items: this.tree, buttons: [{ text: "新建", disabled: true, handler: this.onNewHandler, scope: this }, { text: "确定", disabled: true, handler: function () { this.path = this.tree.getSelectedNode().attributes.path || ""; this.nodeFile = this.tree.getSelectedNode() || {}; //window.returnValue = this.path; //window.close(); Ext.Msg.alert("路径", this.path); }, scope: this }, { text: "取消", handler: function () { this.hide(Ext.getBody()); //window.close(); }, scope: this }] }); }, onNewHandler: function () { this.setPath(); this.setFile(); Ext.Msg.prompt("新建文件", "请输入文件夹名称", this.onCreateDir, this); }, onCreateDir: function (btn, text) { if (btn == "ok") { var path = this.getPath(); var node = this.getFile(); var dirName = text; if (!!path && !!dirName) { //本地添加模式 /*var newNode = new Ext.tree.AsyncTreeNode({ text: dirName, path: node.attributes.path + "/" + dirName }); node.expand(true, true); node.appendChild(newNode);*/ //远程加载模式 Ext.Ajax.request({ url: Ext.hoo.tree.FileSystemTree.TREE_CREATE_DIR_URL, params: {path: encodeURIComponent(path), dirName: encodeURIComponent(dirName)},//处理中文文件名,乱码问题 success: function (response, options) { var returnNnode = Ext.decode(response.responseText); node.appendChild(returnNnode); node.expand(true, true); }, failure: function (response) { Ext.Msg.alert("程序异常", response.responseText); } }); } } }, setPath: function () { this.path = this.tree.getSelectedNode().attributes.path || ""; }, setFile: function () { this.nodeFile = this.tree.getSelectedNode() || {}; }, getPath: function () { return this.path; }, getFile: function () { return this.nodeFile; } }); /** * Ext.hoo.tree.FileSystemTree 系统文件树,显示所有的文件 * @author: hoojo * @createDate 2010-10-17 * @email: [email protected] * @blog: http://blog.csdn.net/IBM_hoojo * @ext_lib: v2.2 * @version 1.0 */ Ext.ns("Ext.hoo.tree"); Ext.hoo.tree.FileSystemTree = Ext.extend(Ext.tree.TreePanel, { constructor: function () { Ext.hoo.tree.FileSystemTree.superclass.constructor.call(this, { //rootVisible: false, autoScroll: true, root: new Ext.tree.AsyncTreeNode({ text: "My System Files", id: "0", path: "root", children:[] }), listeners: { expandnode: { fn: this.onExpandNode, scope: this } } }); }, onExpandNode: function (node) { //只对未加载过的添加子结点,加载后不在重复加载;避免增加请求,浪费资源 if (!node.attributes.isLoad) { Ext.Ajax.request({ url: Ext.hoo.tree.FileSystemTree.TREE_DATA_URL, params: {path: encodeURIComponent(node.attributes.path)},//处理中文文件名,乱码问题 success: function (response, options) { node.attributes.isLoad = true;//设置加载标示 var nodes = Ext.decode(response.responseText); node.appendChild(nodes); }, failure: function (response) { Ext.Msg.alert("程序异常", response.responseText); } }); } }, getSelectedNode: function () { return this.getSelectionModel().getSelectedNode(); } }); Ext.hoo.tree.FileSystemTree.TREE_CREATE_DIR_URL = "http://localhost:8080/Test/FileBrowser?method=mkDir"; Ext.hoo.tree.FileSystemTree.TREE_DATA_URL = "http://localhost:8080/Test/FileBrowser?method=getData";
服务器端java code:
FileBrowser Servlet:
package com.hoo.servlet; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.net.URLDecoder; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.swing.filechooser.FileSystemView; import net.sf.json.JSONArray; import com.hoo.entity.FileInfo; import com.hoo.util.FileUtils; /** * <b>function:</b> 查询本地硬盘文件数据、创建目录 * @project Test * @package com.hoo.servlet * @fileName FileBrowser.java * @author hoojo */ public class FileBrowser extends HttpServlet { private static final long serialVersionUID = 1599390137455995515L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); String path = request.getParameter("path"); path = path == null ? "" : URLDecoder.decode(path, "UTF-8"); String method = request.getParameter("method"); FileInfo info = new FileInfo(); if ("getData".equals(method)) { if ("root".equals(path)) { FileSystemView fsv = FileSystemView.getFileSystemView(); File[] roots = fsv.getRoots(); //File.listRoots(); //桌面 for (File f : roots) { info.getChildren().add(FileUtils.getFileInfo(f)); } for (File f : roots[0].listFiles()) { if (f.getName().contains("My Documents")) { info.getChildren().add(FileUtils.getFileInfo(f)); } } FileInfo fileInfo = new FileInfo(); fileInfo.setName("我的电脑"); fileInfo.setPath("My Computer"); for (File fi : roots[0].listFiles()[0].listFiles()) { fileInfo.getChildren().add(FileUtils.getFileInfo(fi)); } info.getChildren().add(fileInfo); fileInfo = new FileInfo(); fileInfo.setName("网上邻居"); fileInfo.setPath("Network Place"); for (File fi : roots[0].listFiles()[1].listFiles()) { fileInfo.getChildren().add(FileUtils.getFileInfo(fi)); } info.getChildren().add(fileInfo); out.print(JSONArray.fromObject(info.getChildren()).toString()); } else if (path != null && !"".equals(path)) { FileUtils.getFileInfo(info, new File(path), new String[] {"*"}); out.print(JSONArray.fromObject(info.getChildren()).toString()); } } if ("mkDir".equals(method)) { String dirName = request.getParameter("dirName"); dirName = dirName == null ? "" : URLDecoder.decode(dirName, "UTF-8"); boolean success = false; try { success = FileUtils.mkDir(path, dirName); FileInfo node = FileUtils.getFileInfo(new File(FileUtils.getDoPath(path) + dirName)); out.print(JSONArray.fromObject(node)); } catch (Exception e) { e.printStackTrace(); success = false; } System.out.println(success); } out.flush(); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
这个类用到了json-lib.jar工具包,此包可以帮我们把java对象,包括list、map、array序列化成json的字符串。
至少用到以下依赖包:
FileInfo 封装文件信息的java Bean:
package com.hoo.entity; import java.util.ArrayList; import java.util.List; /** * <b>function:</b>文件信息 * @author hoojo * @createDate Oct 10, 2010 9:53:51 PM * @file FileInfo.java * @package com.hoo.entity * @project MultiUpload * @blog http://blog.csdn.net/IBM_hoojo * @email [email protected] * @version 1.0 */ public class FileInfo { //文件id private String id; //文件名称 private String name; private String text; //文件路径 private String path; //是否有目录,有无子节点 private boolean leaf; //修改日期 private String editDate; //后缀 private String suffix; //长度 private long length; // 子目录中所有文件 private List<FileInfo> children = new ArrayList<FileInfo>(); //setter、getter public String toString() { return "name:" + name + ", size:" + children.size(); } }
FileUtils 文件操作工具类
package com.hoo.util; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; import java.util.UUID; import com.hoo.entity.FileInfo; /** * <b>function:</b> 磁盘文件操作工具类 * @project Test * @package com.hoo.util * @fileName FileUtils.java * @createDate 2010-10-4 下午03:32:42 * @author hoojo */ @SuppressWarnings("unused") public abstract class FileUtils { /** * <b>function:</b>传递一个File,返回该文件的FileInfo实体类 * @author hoojo * @createDate Oct 10, 2010 10:10:19 PM * @param file File * @return FileInfo */ public static FileInfo getFileInfo(File file) { FileInfo info = new FileInfo(); if (file != null) { info.setId(UUID.randomUUID().toString()); if (file.getName() == null || "".equals(file.getName()) || "::".equals(file.getName())) { info.setName(file.getAbsolutePath()); } else { info.setName(file.getName()); } //info.setLeaf(file.isFile()); info.setLeaf(!file.isDirectory()); info.setLength(file.length()); info.setPath(getDoPath(file.getAbsolutePath())); info.setSuffix(getType(file.getName())); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = new Date(); date.setTime(file.lastModified()); info.setEditDate(sdf.format(date)); } return info; } public static void setFileInfo(File file, FileInfo info) { if (file != null && info != null) { info.setId(UUID.randomUUID().toString()); if (file.getName() == null || "".equals(file.getName()) || "::".equals(file.getName())) { info.setName(file.getAbsolutePath()); } else { info.setName(file.getName()); } //info.setLeaf(file.isFile()); info.setLeaf(!file.isDirectory()); info.setLength(file.length()); info.setPath(getDoPath(file.getAbsolutePath())); info.setSuffix(getType(file.getName())); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = new Date(); date.setTime(file.lastModified()); info.setEditDate(sdf.format(date)); } } /** * <b>function:</b>处理后的系统文件路径 * @author hoojo * @createDate Oct 10, 2010 12:49:31 AM * @param path 文件路径 * @return 返回处理后的路径 */ public static String getDoPath(String path) { path = path.replace("//", "/"); String lastChar = path.substring(path.length() - 1); if (!"/".equals(lastChar)) { path += "/"; } return path; } /** * <b>function:</b>和文件后缀一样,不同的是没有“.” * @author hoojo * @createDate Oct 10, 2010 2:42:43 PM * @param fileName 文件名称 * @return */ public static String getType(String fileName) { int index = fileName.lastIndexOf("."); if (index != -1) { String suffix = fileName.substring(index + 1);//后缀 return suffix; } else { return null; } } /** * <b>function:</b> 得到指定目录下所有的文件集合 * @createDate 2010-10-20 下午02:20:06 * @author hoojo * @param info 将数据设置在该变量中 * @param file 文件目录 */ public static void getAllFileInfo(FileInfo info, File file) { if (file.isDirectory()) { long size = 0; File[] allFiles = file.listFiles(); for (File f : allFiles) { size += f.length(); FileInfo fi = getFileInfo(f); info.getChildren().add(fi); getAllFileInfo(fi, f); } info.setLength(size); } } /** * <b>function:</b> 得到当前目录所有文件 * @createDate 2010-10-20 下午02:21:06 * @author hoojo * @param info 文件对象 * @param file 目录 */ public static void getFileInfo(FileInfo info, File file, String[] allowTypes) { if (file.isDirectory()) { long size = 0; File[] allFiles = file.listFiles(); for (File f : allFiles) { size += f.length(); FileInfo fi = getFileInfo(f); if (f.isDirectory()) { info.getChildren().add(fi); } else { if (validTypeByName(f.getName(), allowTypes, true)) { info.getChildren().add(fi); } } } info.setLength(size); } } /** * <b>function:</b> 根据文件名和类型数组验证文件类型是否合法,flag是否忽略大小写 * @author hoojo * @createDate Oct 10, 2010 11:54:54 AM * @param fileName 文件名 * @param allowTypes 类型数组 * @param flag 是否获得大小写 * @return 是否验证通过 */ public static boolean validTypeByName(String fileName, String[] allowTypes, boolean flag) { String suffix = getType(fileName); boolean valid = false; if (allowTypes.length > 0 && "*".equals(allowTypes[0])) { valid = true; } else { for (String type : allowTypes) { if (flag) {//不区分大小写后缀 if (suffix != null && suffix.equalsIgnoreCase(type)) { valid = true; break; } } else {//严格区分大小写 if (suffix != null && suffix.equals(type)) { valid = true; break; } } } } return valid; } /** * <b>function:</b> 在path目录下创建目录 * @createDate 2010-11-3 下午04:03:34 * @author hoojo * @param path * @param dirName * @return */ public static boolean mkDir(String path, String dirName) { boolean success = false; File file = new File(getDoPath(path) + dirName); if (!file.exists()) { success = file.mkdirs(); } return success; } }
点击新建可以创建新目录,确定可以获取选择的路径。