千里冰封
JAVA 浓香四溢
posts - 151,comments - 2801,trackbacks - 0
    在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 given <code>Display</code> 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 a <code>Command</code> object identifying the command. This is either
     * one of the applications have been added to <code>Displayable</code> with <code>addCommand(Command)</code>
     * or is the implicit <code>SELECT_COMMAND</code> of List.
     * 
@param d the <code>Displayable</code> 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 a <code>FileConnection</code> object.
     * 
@return non null <code>FileConection</code> object
     
*/
    
public FileConnection getSelectedFile() throws IOException {
        FileConnection fileConnection 
= (FileConnection) Connector.open(selectedURL);
        
return fileConnection;
    }

    
/**
     * Returns selected <code>FileURL</code> object.
     * 
@return non null <code>FileURL</code> 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 null <code>CommandListener</code> object
     
*/
    
protected CommandListener getCommandListener() {
        
return commandListener;
    }

    
/**
     * Sets command listener to this component.
     * 
@param commandListener <code>CommandListener</code> 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:/来访问.






尽管千里冰封
依然拥有晴空

你我共同品味JAVA的浓香.
posted on 2008-07-31 23:00 千里冰封 阅读(2218) 评论(3)  编辑  收藏 所属分类: JAVAME

FeedBack:
# re: JAVAME(JSR75)组件之文件选择器
2008-08-23 13:59 | yhh2083
楼主,真棒!  回复  更多评论
  
# re: JAVAME(JSR75)组件之文件选择器
2008-10-16 22:54 | 过路云
我最近安装了Wireless Toolkit 2.5 但是却不知道怎么使用,网上没有教程,不知道楼主能否给我说一说,最好有个使用教程加一个实例,我的邮箱mukeywa@sina.com 谢谢!  回复  更多评论
  
# re: JAVAME(JSR75)组件之文件选择器
2009-02-11 00:30 | rockey
不错的实践经验。谢谢分享。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: