ExtJS 文件浏览器,可以选择文件和文件夹

话说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="hoojo_@126.com">  
    <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: hoojo_@126.com 
 * @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: hoojo_@126.com 
 * @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: hoojo_@126.com 
 * @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 hoojo_@126.com 
 * @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;  
    }  
} 

点击新建可以创建新目录,确定可以获取选择的路径。

文章导航