在JAVAME开发的时候,可能会需要浏览手机的文件目录,但是又没有和JAVASE里面的JFileChooser一样的组件可以用,只有自己写一个了,在写的过程中,发现了一些问题,在此与大家分享一下.
一开始我以为,只要是支持JSR75的手机都可以支持手机内所有文件的访问,可是在真机上一看才知道,手机的文件或者文件夹有公有与有私有之分,我们看上
去像是公有的文件夹,在JAVAME里面却不能访问.比如我测试用的手机是诺基亚的N76,它的SD卡上的Music目录,对于程序来说,就是私有的,不
能访问的,而"手机动漫"这个目录却是能访问的.难怪我测了很多次放在Music目录里面的歌曲,怎么播也播不出来,后来经过一步一步的调试,才知道原来
此目录下面的文件不可读.要知道ME的调试是多么不方便,又不能用System.out.println调试,因为在真机上面根本就没有输出窗口.只能自
己一句一句用Alert来调试.
不说废话了,先给出代码吧.这是一个继承自
List的组件.用列表的方式显示出当前目录下的所有文件.本来是想全新写一个的,后来发现netbeans有一个,所以就直接用了它的,写得很不错,说
到这里,我觉得netbeans很多地方确实不错,只是很多人由于以前的偏见没有给它机会而已.
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.hadeslee.test; import java.io.IOException; import java.util.Enumeration; import javax.microedition.io.Connector; import javax.microedition.io.file.FileConnection; import javax.microedition.io.file.FileSystemRegistry; import javax.microedition.lcdui.Alert; import javax.microedition.lcdui.AlertType; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Image; import javax.microedition.lcdui.List; /** * * @author hadeslee */ public class FileBrowser extends List implements CommandListener { /** * Command fired on file selection. */ public static final Command SELECT_FILE_COMMAND = new Command("选择", Command.OK, 1); private String currDirName; private String currFile; private Image dirIcon; private Image fileIcon; private CommandListener commandListener; /* special string denotes upper directory */ private static final String UP_DIRECTORY = ".."; /* special string that denotes upper directory accessible by this browser. * this virtual directory contains all roots. */ private static final String MEGA_ROOT = "/"; /* separator string as defined by FC specification */ private static final String SEP_STR = "/"; /* separator character as defined by FC specification */ private static final char SEP = '/'; private Display display; private String selectedURL; private String filter = null; private String title; /** * Creates a new instance of FileBrowser for givenDisplay
object. * @param display non null display object. */ public FileBrowser(Display display) { super("文件浏览器", IMPLICIT); currDirName = MEGA_ROOT; this.display = display; super.setCommandListener(this); setSelectCommand(SELECT_FILE_COMMAND); try { dirIcon = Image.createImage(this.getClass().getResourceAsStream( "dir.png")); } catch (IOException e) { dirIcon = null; } try { fileIcon = Image.createImage(this.getClass().getResourceAsStream( "file.png")); } catch (IOException e) { fileIcon = null; } showDir(); } /** * 显示当前的文件夹 */ private void showDir() { new Thread(new Runnable() { public void run() { try { showCurrDir(); } catch (SecurityException e) { Alert alert = new Alert("错误", "您没有权限访问此文件或文件夹!", null, AlertType.ERROR); alert.setTimeout(2000); display.setCurrent(alert, FileBrowser.this); } catch (Exception e) { e.printStackTrace(); } } }).start(); } /** * Indicates that a command event has occurred on Displayable d. * @param c aCommand
object identifying the command. This is either * one of the applications have been added toDisplayable
withaddCommand(Command)
* or is the implicitSELECT_COMMAND
of List. * @param d theDisplayable
on which this event has occurred */ public void commandAction(Command c, Displayable d) { if (c.equals(SELECT_FILE_COMMAND)) { List curr = (List) d; currFile = curr.getString(curr.getSelectedIndex()); new Thread(new Runnable() { public void run() { if (currFile.endsWith(SEP_STR) || currFile.equals(UP_DIRECTORY)) { openDir(currFile); } else { //switch To Next doDismiss(); } } }).start(); } else { if (commandListener != null) { commandListener.commandAction(c, d); } } } /** * Sets component's title. * @param title component's title. */ public void setTitle(String title) { this.title = title; super.setTitle(title); } /** * Show file list in the current directory . */ private void showCurrDir() { if (title == null) { super.setTitle(currDirName); } Enumeration e = null; FileConnection currDir = null; deleteAll(); if (MEGA_ROOT.equals(currDirName)) { append(UP_DIRECTORY, dirIcon); e = FileSystemRegistry.listRoots(); } else { try { currDir = (FileConnection) Connector.open("file:///" + currDirName); e = currDir.list(); } catch (IOException ioe) { } append(UP_DIRECTORY, dirIcon); } if (e == null) { try { currDir.close(); } catch (IOException ioe) { ioe.printStackTrace(); } return ; } while (e.hasMoreElements()) { String fileName = (String) e.nextElement(); if (fileName.charAt(fileName.length() - 1) == SEP) { // This is directory append(fileName, dirIcon); } else { // this is regular file if (filter == null || fileName.indexOf(filter) > -1) { append(fileName, fileIcon); } } } if (currDir != null) { try { currDir.close(); } catch (IOException ioe) { ioe.printStackTrace(); } } } private void openDir(String fileName) { /* In case of directory just change the current directory * and show it */ if (currDirName.equals(MEGA_ROOT)) { if (fileName.equals(UP_DIRECTORY)) { // can not go up from MEGA_ROOT return; } currDirName = fileName; } else if (fileName.equals(UP_DIRECTORY)) { // Go up one directory // TODO use setFileConnection when implemented int i = currDirName.lastIndexOf(SEP, currDirName.length() - 2); if (i != -1) { currDirName = currDirName.substring(0, i + 1); } else { currDirName = MEGA_ROOT; } } else { currDirName = currDirName + fileName; } showDir(); } /** * Returns selected file as aFileConnection
object. * @return non nullFileConection
object */ public FileConnection getSelectedFile() throws IOException { FileConnection fileConnection = (FileConnection) Connector.open( selectedURL); return fileConnection; } /** * Returns selectedFileURL
object. * @return non nullFileURL
object */ public String getSelectedFileURL() { return selectedURL; } /** * Sets the file filter. * @param filter file filter String object */ public void setFilter(String filter) { this.filter = filter; } /** * Returns command listener. * @return non nullCommandListener
object */ protected CommandListener getCommandListener() { return commandListener; } /** * Sets command listener to this component. * @param commandListenerCommandListener
to be used */ public void setCommandListener(CommandListener commandListener) { this.commandListener = commandListener; } private void doDismiss() { selectedURL = "file:///" + currDirName + currFile; CommandListener listener = getCommandListener(); if (listener != null) { listener.commandAction(SELECT_FILE_COMMAND, this); } } }
这个类可以用做浏览手机文件之用,也可以用做得到得选的文件之用,如果想要在选择了文件以后做什么事情的话,可以调用它的setCommandListener方法.并且处理SELECT_FILE_COMMAND.
经过试验,我发现所有的只读文件夹对于FileConnection来说,就是私有的,是不能访问到的,所以当我们要访问的时候,最好是把那些只读的文件夹改为可读写.
发现一件N76的文件的好玩的事情.在N76里面,你访问的时候,总共有四个根文件夹,分别是:
手机存储/ C:/ 存储卡/ E:/
可是我发现手机存储和C是一样的,存储卡和E也是一样的,也就是说可以用file:///手机存储/来访问也可以用file:///C:/来访问.