当前位置: 代码迷 >> JavaScript >> J2ME(JSR75)组件之资料选择器
  详细解决方案

J2ME(JSR75)组件之资料选择器

热度:197   发布时间:2012-08-27 21:21:57.0
J2ME(JSR75)组件之文件选择器

????? 在J2ME开发的时候,可能会需要浏览手机的文件目录,但是又没有和J2SE里面的JFileChooser一样的组件可以用,只有自己写一个了,在写的过程中,发现了一些问题,在此与大家分享一下。
  一开始我以为,只要是支持JSR75的手机都可以支持手机内所有文件的访问,可是在真机上一看才知道,手机的文件或者文件夹有公有与有私有之分,我们看上去像是公有的文件夹,在J2ME里面却不能访问。比如我测试用的手机是诺基亚的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.
 */
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:/来访问。