Files

The most basic kind of StreamConnection is a javax.microedition.io.file.FileConnection :

public interface FileConnection extends StreamConnection

In J2ME, the FileConnection class takes the place of java.io.File in J2SE. Thus, as well as methods to open streams, it has methods to get information about the file. Do be careful here. Every warning in Chapter 17 about cross-platform file access goes triple for J2ME. Some small device filesystems look like Windows, but many more look like DOS, right down to a maximum 8.3 filename. Others look like Unix (in fact, some are Unix), and still others look nothing like any common desktop operating system.

FileConnection is not a standard part of any J2ME profile, but devices that have filesystems are likely to include it. Filesystems include not only built-in filesystems on internal hard drives and flash memory, but also various types of removable memory, such as SmartMedia cards, CompactFlash cards, or Sony memory sticks. For instance, youll find FileConnection on Nokia phones that implement the S60 Platform 2nd Edition or later, including the N80, N92, and N71. If you e not developing for a specific platform with known capabilities, you can check for its presence by testing the microedition.io.file.FileConnection.version system property:

if (System.getproperty("microedition.io.file.FileConnection.version") != null) { // file connections are available }

This property is set only on platforms where you can open a FileConnection.

To open a FileConnection, just use a standard file URL such as file:///C:/Nokia/Images/Image(007).jpg. Some devices also define virtual filesystem roots that don expose the entire filesystem, such as /Images. For example, on many recent Nokia phones, this statement opens the file at file:///C:/Nokia/Images/Image(007).jpg:

InputStream in = Connector.openInputStream("file:///Images/Image(007).jpg ");

As in applets, access to the filesystem is restricted to signed, trusted MIDlets. Untrusted MIDlets prompt the user for authorization before reading or writing files. Even trusted MIDlets are normally prevented from accessing or even seeing certain sensitive parts of the filesystem, such as Record Management System (RMS) databases or operating system files. For instance, a Linux-based PDA shouldn allow access to /vmlinuz, and a MIDlet shouldn need it. MIDlets are meant for basic user-level programs, after all, not device drivers and system software.

If you want to do more than just read from or write to the file, open a connection and cast it to FileConnection rather than opening an input or output stream directly:

FileConnnection fc = (FileConnection) Connector.open( "file:///Volumes/Birds/Contacts/ipod_created_instructions.vcf ");;

You can then call FileConnnections openInputStream( ), openOutputStream( ), openDataInputStream( ), and openDataOutputStream( ) methods to get the streams you use to read and write:

public static InputStream openInputStream(String url) throws IOException, IllegalModeException, SecurityException public static OutputStream openOutputStream(String url) throws IOException, IllegalModeException, SecurityException public static DataInputStream openDataInputStream(String url) throws IOException, IllegalModeException, SecurityException public static DataOutputStream openDataOutputStream(String url) throws IOException, IllegalModeException, SecurityException

Each FileConnection can have only one InputStream and one OutputStream open at a time, though you can open a new stream after closing the old one. Unlike sockets, closing the associated stream does not close the FileConnection. To close a FileConnection, you must explicitly call the connections close( ) method.

A SecurityException is thrown if the user vetoes the file access. An IllegalModeException is thrown if the connection was opened in write-only mode. These are runtime exceptions. A checked IOException is thrown if anything else goes wrong.

Usually, you begin writing at the beginning of a file and overwrite any existing data in the file. FileConnection does not support random access. However, it adds one extra method that enables you to start writing at a specified position in the file rather than at the beginning:

public OutputStream openOutputStream(long byteOffset) throws IOException, IllegalArgumentException, IllegalModeException, SecurityException

You can also cut off the end of the file, truncating it to a certain length in bytes:

public void truncate(long byteOffset) throws IOException, IllegalArgumentException, IllegalModeException, ConnectionClosedException

In both cases, the byteOffset must be nonnegative, or an IllegalArgumentException is thrown.

As with java.io.File, having a FileConnection object does not guarantee that the file actually exists. Thus, before trying to read or write to a file, you should first check whether the file exists:

public boolean exists( ) throws IllegalModeException, SecurityException, ConnectionClosedException

You should also check whether the file is a really a file, or if its a directory. exists( ) returns TRue in both cases, but the isDirectory( ) method tells you. It returns true if the file exists and is a directory or false otherwise:

public boolean isDirectory( ) throws SecurityException, IllegalModeException, ConnectionClosedException

If a file does not exist, you can use the create( ) method to create it:

public void create( ) throws IOException, IllegalModeException, SecurityException, ConnectionClosedException

For example, this code tries to create the file newfile.txt in the directory /CFCard if it doesn already exist:

FileConnection fc = (FileConnection) Connector.open("file:///CFCard/newfile.txt"); if (!fc.exists()) fc.create( );

Unlike with java.io.FileOutputStream, merely opening an OutputStream to a file with FileConnection is not sufficient to create it. You must explicitly call create( ) before opening an OutputStream with FileConnection.

To create a directory, use the mkdir( ) method instead:

public void mkdir( ) throws IOException, IllegalModeException, SecurityException, ConnectionClosedException

You can also change the name of an existing file or directory using the rename( ) method:

public void rename(String newName) throws IOException, NullPointerException, IllegalArgumentException, IllegalModeException, SecurityException, ConnectionClosedException

The new name must not contain any slashes, or an IllegalArgumentException is thrown. Unlike the rename( ) method in java.io.File, this method never moves a file to a different directory. FileConnection has no methods to move or copy a file. This method also has the side effect of closing all currently open streams to the file, though the connections to the file remain open.

You can delete a file or directory, permissions permitting of course, with the delete( ) method:

public void delete( ) throws IOException, IllegalModeException, SecurityException, ConnectionClosedException

The getName( ) method takes no arguments and returns the name of the file as a string:

public String getName( )

The name does not include any part of the directory in which the file lives. That is, you get back something like index.html instead of /public/html/javafaq/index.html. If the file is a directory, the name ends with a forward slash (/).

The getPath( ) method returns an absolute path to the files parent directory, as initially provided in the file URL:

public String getPath( )

For example, if the URL was file:///a/b/c/d.jpg, getPath( ) would return /a/b/c/. If the URL was file:///a/b/c/, getPath( ) would return /a/b/. Forward slashes are always used, even on FAT and other DOS/Windows filesystems. The full absolute path to the file is getPath( ) + getFile( ).

Root directories are treated specially. For a root directory, getPath( ) always returns the empty string.

Finally, the getURL( ) method returns the complete file URL that was used to open the FileConnection:

public String getURL( )

.3.1.

.3.1.1. File attributes

The FileConnection class has several methods that return information about the file, such as its length, the time it was last modified, whether its readable, whether its writable, and whether its hidden.

The canWrite( ) method indicates whether the program can write into the file referred to by this FileConnection object, while the canRead( ) method indicates whether the program can read from the file:

public boolean canRead( ) throws SecurityException, ConnectionClosedException IllegalModeException, public boolean canWrite( ) throws SecurityException, IllegalModeException, ConnectionClosedException

You can sometimes change the readability of a file using the setReadable( ) method or the writability using setWritable( ):

public boolean setReadable(boolean readable) throws IOException, SecurityException, IllegalModeException, ConnectionClosedException public boolean setWritable(boolean writable) throws IOException, SecurityException, IllegalModeException, ConnectionClosedException

More often than not, though, if a file isn already readable or writable, you can make it so; trying to do it anyway simply results in one exception or another.

The isOpen( ) method returns TRue if the file is open and false if it isn :

public boolean isOpen( ) throws SecurityException, IllegalModeException, ConnectionClosedException

The isHidden( ) method returns TRue if the file exists but is hidden:

public boolean isHidden( ) throws SecurityException, IllegalModeException, ConnectionClosedException

Exactly what "hidden" means varies from one platform to the next, but you probably shouldn show a hidden file to the user by default. isHidden( ) returns false if the file isn hidden or doesn exist.

You can hide a file by passing true to setHidden( ) or unhide it by passing false:

public void setHidden(boolean hidden) throws IOException, IllegalModeException, SecurityException, ConnectionClosedException

The lastModified( ) method returns a long indicating the last time this file was modified:

public long lastModified( ) throws SecurityException, IllegalModeException, ConnectionClosedException

The time is the number of milliseconds since midnight, January 1, 1970, Greenwich Mean Time. lastModified( ) returns 0 if for any reason the last modified date can be determined.

The fileSize( ) method returns the number of bytes in the file:

public long fileSize( ) throws IOException, IllegalModeException, SecurityException, ConnectionClosedException

fileSize( ) returns -1 if the file doesn exist or can be read. It throws an IOException if you invoke it on a directory. However, the directorySize( ) method returns the sum of the sizes of all the files in the directory:

public long directorySize(boolean includeSubDirs) throws IOException, IllegalModeException, SecurityException, ConnectionClosedException

If includeSubDirs is TRue, this sum includes the sizes of all files in all subdirectories, applied recursively. Otherwise, it just returns the cumulative size of the files directly contained in this directory. Invoking directorySize( ) on a FileConnection object that represents a file throws an IOException.

Finally, you can use the totalSize( ), usedSize( ), and availableSize( ) methods to determine the size in bytes of the filesystem where this FileConnection object is found, the number of bytes used on the filesystem, and the number of free bytes, respectively:

public long totalSize( ) throws IllegalModeException, SecurityException, ConnectionClosedException public long availableSize( ) throws IllegalModeException, SecurityException, ConnectionClosedException public long usedSize

.3.1.2. Listing directories

The list( ) method returns an enumeration of strings containing the names of each nonhidden file in the directory referred to by the FileConnection object:

public Enumeration list( ) throws IOException, IllegalModeException, SecurityException, ConnectionClosedException

This method throws an IOException if the FileConnection object doesn point to an accessible directory. It throws a SecurityException if the program isn allowed to read the directory being listed. An overloaded version of list( ) can optionally display hidden files and filter the files displayed:

public Enumeration list(String filter, boolean includeHidden) throws IOException, IllegalModeException, SecurityException, ConnectionClosedException

J2ME has no FileFilters or FilenameFilters. Instead, the filter is a simple string pattern for the files to be displayed. The asterisk (*) is a wildcard. For instance, the pattern "*.jpg" finds all files whose names end with .jpg. To find all JPEG files, youd pass "*.jpg" as the first argument and true as the second argument:

fc.list("*.jpg", true);

Mostly, this all mirrors what youve already seen in the java.io.File class. However, FileConnection does have one unique ability File doesn . The setFileConnection( ) method changes this object so it points to another file:

public void setFileConnection(String fileName) throws IOException, IllegalArgumentException, NullPointerException, SecurityException, ConnectionClosedException

This method is intended for directory traversal, and it has a number of prerequisites. The current FileConnection must point to a directory, not a file. Also, you can set the FileConnection only to a file or directory in the same directory, or to the parent directory (..).

.3.2. Filesystem Listeners

The FileSystemRegistry class and the FileSystemListener interface enable a J2ME program to learn about new filesystems as they e mounted or unmounted. This is important because many embedded devices still use removable media such as smart cards and memory sticks. On some devices, those may be the only filesystems a MIDlet can see.

The FileSystemListener interface declares a single method, rootChanged( ):

public void rootChanged(int state, String rootName)

The first argument is either FileSystemListener.ROOT_ADDED or FileSystemListener.ROOT_REMOVED. Such listeners are added to or removed from the FileSystemRegistry class using these two static methods:

public static boolean addFileSystemListener(FileSystemListener listener) throws SecurityException, NullPointerException public static boolean removeFileSystemListener(FileSystemListener listener) throws NullPointerException

You can also use FileSystemRegistry to enumerate all the currently mounted filesystem roots, with the listRoots( ) method:

public static Enumeration listRoots( ) throws SecurityException

These roots are the logical roots exposed to the client program, not necessarily the real roots of the filesystem. Normally, the true root or roots are inaccessible for security reasons. Thus, even Unix-based devices may have several logical roots.

Example 24-3 demonstrates a simple program that recursively lists all the files in a directory, and all the files in directories in the directory, and so on. Files are indented two spaces for each level deep they are in the hierarchy.

Example 24-3. The DirLister MIDlet

import java.io.*; import java.util.*; import javax.microedition.io.*; import javax.microedition.midlet.*; import javax.microedition.io.file.*; import javax.microedition.lcdui.*; public class DirLister extends MIDlet { private int level = 0; public void startApp( ) { Form form = new Form("File Roots"); Enumeration roots = FileSystemRegistry.listRoots( ); while (roots.hasMoreElements( )) { Object next = roots.nextElement( ); String url = "file:///" + next; System.out.println(url); try { FileConnection connection = (FileConnection) Connector.open(url); getInfo(connection, form); } catch (IOException ex) { form.append(ex.getMessage( ) +" "); } } Display.getDisplay(this).setCurrent(form); } public void pauseApp( ) {} public void destroyApp(boolean condition) { notifyDestroyed( ); } private void getInfo(FileConnection connection, Form form) throws IOException { if (connection.isDirectory( )) form.append("------ "); for (int i = 0; i < level; i++) form.append(" "); form.append(connection.getPath() + connection.getName( ) + " "); if (connection.isDirectory( )) { level++; Enumeration list = connection.list( ); String path = connection.getPath() + connection.getName( ); while (list.hasMoreElements( )) { Object next = list.nextElement( ); String url = "file://" + path + next ; try { FileConnection child = (FileConnection) Connector.open(url); getInfo(child, form); } catch (Exception ex) { form.append(ex.getMessage( ) +" "); } } level--; } } }

Figure 24-3 shows this MIDlet running in the J2ME Wireless Toolkit Emulator. You can see that there are two roots on this system, /CFCard1 and /CFCard2. /CFCard1 contains three directories, movs, pix, and snds. movs and snds are empty, but pix contains two files, _dukeok2.png and _dukeok8.png. /CFCard2 contains only a single file, secrets.txt.

Figure 24-3. The DirLister MIDlet

Категории

© amp.flylib.com,