读书人

在J2ME中模拟C语言中的资料操作

发布时间: 2012-10-05 15:34:34 作者: rapoo

在J2ME中模拟C语言中的文件操作
最近在写一个模拟器(OR虚拟机),用于运行文曲星(一种电子词典)上的一种类C语言开发的GVmaker程序(不知道这里有没有玩过文曲星的,关于GVmaker可以看这里).做这个东西主要是怀念一下以前玩文曲星的日子.另外刚刚买了个智能手机,尝试一下J2ME的开发,这也是我第一个J2ME程序.
这个东西并不复杂,而且因为刚学JAVA的时候写过一个桌面版的(只不过那个写的比较烂),所以构思好大体框架把各种接口定义好后就一路写过去.待到写文件系统这一块的时候才发现J2ME对文件的访问没有C语言中那么方便,也不像J2SE中有RandomAccessFile可以用.google了一下,也没有发现相关资料.于是我自己写了个在内存中模拟C语言文件操做.当然,通过内存模拟文件操作具有很大的局限性,消耗内存并且当文件过大的时候就不适用了.不过我这个就是为了模拟器中操作文件用的,而文曲星上的程序操作的文件都不会太大,所以这样用是没问题的.
下面是实现的几个主要类:
内存文件的实现

/** * 虚拟文件,使用内存模拟文件操作<p> * 每个虚拟文件除了读写数据外,还有三个属性:position,limit,capacity<p> *     其capacity描述了这个虚拟文件当前能容纳的最大数据量,这个值不能从外部修改,但在向其写入数据时根据需要内部会适当扩充其capacity<p> *     limit描述的是虚拟文件当前存储的数据总量,外部可以读取或修改或增加数据到虚拟文件.这个值在调用readFromStream时自动初始化,并且内部自动维护<p> *     position表示下一个读/写数据的地址,相当于普通文件操作中的文件指针.其初始值应该由调用者在调用readFromStream方法后正确设置<p> * 对于一个含有数据,并正确初始化的VirtualFile,应有以下关系成立:<p> *     0<=position<=limit<=capacity * @author Eastsun * @version 2008-2-25 */public final class VirtualFile {    //每次增量的最小值:128K    private static final int MIN_ADD_CAPS = 0x20000;    private static final int MAX_COUNT = 5;    //内存块,最多支持5块,也就是640K,对GVmaker来说足够了    private byte[][] bufs = new byte[MAX_COUNT][];    //caps[k]表示第0,..k-1块内存的总容量    private int[] caps = new int[MAX_COUNT + 1];    //内存块数量    private int count;    //当前所在内存块下标    private int index;    //文件长度    private int limit;    //the index of the next element to be read or written    private int position;    /**     * 使用一个初始容量构造VirtualFile     * @param size     */    public VirtualFile(int size) {        bufs[0] = new byte[size];        for (int n = 1; n <= MAX_COUNT; n++) {            caps[n] = size;        }        count = 1;    }    /**     * 得到该VirtualFile总容量     * @return capacity     */    public int capacity() {        return caps[count];    }    /**     * 得到VirtualFile中实际存储数据的长度,也就是文件的长度     * @return length of file     */    public int limit() {        return limit;    }    /**     * 得到VirtualFile中的读写指针位置,也就是文件指针     * @return position     */    public int position() {        return position;    }    /**     * 设置文件指针     * @param newPos 新的指针位置     * @return newPos 设置后的指针,若出错返回-1     */    public int position(int newPos) {        if (newPos < 0 || newPos > limit) {            return -1;        }        position = newPos;        //修改index,使其满足caps[index]<=position<caps[index+1]        while (caps[index + 1] <= position) {            index++;        }        while (caps[index] > position) {            index--;        }        return position;    }    /**     * 读取文件数据,并且position加1     * @return 当前position出的文件内容;若已到文件位(>=limit()),返回-1     */    public int getc() {        if (position >= limit) {            return -1;        }        int c = bufs[index][position - caps[index]] & 0xff;        position++;        if (position >= caps[index + 1]) {            index++;        }        return c;    }    public int putc(int ch) {        if (position > limit) {            return -1;        }        ensureCapacity(position + 1);        bufs[index][position - caps[index]] = (byte) ch;        position++;        if (position > limit) {            limit = position;        }        if (position >= caps[index + 1]) {            index++;        }        return ch;    }    /**     * 将position,limit清零     */    public void refresh() {        index = position = limit = 0;    }    /**     * 从in读取数据到VirtualFile,初始limit的值,并设置position的值为0<p>     * 操作完成后关闭in     * @param in 数据来源     * @throws java.io.IOException 发生IO错误     */    public void readFromStream(InputStream in) throws IOException {        int size = in.available();        limit = size;        ensureCapacity(size);        int n = 0;        while (size > 0) {            size -= in.read(bufs[n++]);        }        in.close();    }    /**     * 将VirtualFile中的内容写入到out<p>     * 操作完成后关闭out     * @param out 写入目标     * @throws java.io.IOException 发生IO错误     */    public void writeToStream(OutputStream out) throws IOException {        int n = 0;        while (limit > caps[n + 1]) {            out.write(bufs[n++]);        }        if (limit > caps[n]) {            out.write(bufs[n], 0, limit - caps[n]);        }        out.close();    }    //确保至少有minCap大小的内存可用    private void ensureCapacity(int minCap) {        if (caps[count] >= minCap) {            return;        }        //每次至少增加128K        int addCap = Math.max(MIN_ADD_CAPS, minCap - caps[count]);        bufs[count] = new byte[addCap];        for (int n = count + 1; n <= MAX_COUNT; n++) {            caps[n] = caps[count] + addCap;        }        count++;    }}


模拟C文件操作
/** * * @author Eastsun * @version 2008-2-22 */public class DefaultFileModel extends FileModel {    public static final String READ_MODE = "r";    public static final String READ_PLUS_MODE = "r+";    public static final String READ_B_MODE = "rb";    public static final String READ_B_PLUS_MODE = "rb+";    public static final String WRITE_MODE = "w";    public static final String WRITE_PLUS_MODE = "w+";    public static final String WRITE_B_MODE = "wb";    public static final String WRITE_B_PLUS_MODE = "wb+";    public static final String APPEND_MODE = "a";    public static final String APPEND_PLUS_MODE = "a+";    public static final String APPEND_B_MODE = "ab";    public static final String APPEND_B_PLUS_MODE = "ab+";    private static final int SEEK_SET = 0;    private static final int SEEK_CUR = 1;    private static final int SEEK_END = 2;    //同时访问文件的最大个数    private final static int MAX_FILE_COUNT = 3;    private FileSys fileSys;    private String workDir;    private boolean[] canRead;    private boolean[] canWrite;    private String[] fileNames;    //是否可用,也就是是否空闲    private boolean[] usable;    private VirtualFile[] files;    //用于生成String的byte数组    private byte[] strBuf;    //用于保存屏幕缓冲区数据    private Accessable graphBuffer;    public DefaultFileModel(FileSys fileSys) {        this.fileSys = fileSys;        workDir = "";        canRead = new boolean[MAX_FILE_COUNT];        canWrite = new boolean[MAX_FILE_COUNT];        usable = new boolean[MAX_FILE_COUNT];        files = new VirtualFile[MAX_FILE_COUNT];        fileNames = new String[MAX_FILE_COUNT];        for (int index = 0; index < MAX_FILE_COUNT; index++) {            usable[index] = true;            //初始容量:64K            files[index] = new VirtualFile(0x10000);        }        strBuf = new byte[200];    }    public boolean changeDir(Getable source, int addr) {        String newDir = getFileName(source, addr);        FileInf inf = fileSys.getFileInf(newDir);        if (inf.isDirectory()) {            workDir = newDir;            return true;        }        else {            return false;        }    }    public boolean makeDir(Getable source, int addr) {        String dir = getFileName(source, addr);        return fileSys.makeDir(dir);    }    public boolean fileList(ScreenModel screen, KeyModel key, Setable dest, int addr) {        return true;    }    public int fopen(Getable source, int fileName, int openMode) {        int num = -1;        //指示文件指针位置,true开头,false为结尾        boolean pointer = true;        //是否清除原有文件        boolean clear = false;        for (int index = 0; index < MAX_FILE_COUNT; index++) {            if (usable[index]) {                num = index;                break;            }        }        if (num == -1) {            return 0;        }        String name = getFileName(source, fileName);        String mode = getString(source, openMode);        FileInf inf = fileSys.getFileInf(name);        if (READ_MODE.equals(mode) || READ_B_MODE.equals(mode)) {            if (!(inf.isFile() && inf.canRead())) {                return 0;            }            canRead[num] = true;            canWrite[num] = false;        }        else if (READ_PLUS_MODE.equals(mode) || READ_B_PLUS_MODE.equals(mode)) {            if (!(inf.isFile() && inf.canRead() && inf.canWrite())) {                return 0;            }            canRead[num] = true;            canWrite[num] = true;        }        else if (WRITE_MODE.equals(mode) || WRITE_B_MODE.equals(mode)) {            if (inf.isFile() && !inf.canWrite()) {                return 0;            }            clear = true;            canRead[num] = false;            canWrite[num] = true;        }        else if (WRITE_PLUS_MODE.equals(mode) || WRITE_B_PLUS_MODE.equals(mode)) {            if (inf.isFile() && !inf.canWrite()) {                return 0;            }            clear = true;            canRead[num] = true;            canWrite[num] = true;        }        else if (APPEND_MODE.equals(mode) || APPEND_B_MODE.equals(mode)) {            if (!(inf.isFile() && inf.canWrite())) {                return 0;            }            canRead[num] = false;            canWrite[num] = true;            pointer = false;        }        else if (APPEND_PLUS_MODE.equals(mode) || APPEND_B_PLUS_MODE.equals(mode)) {            if (!(inf.isFile() && inf.canRead() && inf.canWrite())) {                return 0;            }            canRead[num] = true;            canWrite[num] = true;            pointer = false;        }        else {            return 0;        }        VirtualFile file = files[num];        if (clear) {            file.refresh();        }        else {            int length = 0;            try {                InputStream in = fileSys.getInputStream(name);                length = in.available();                file.readFromStream(in);                in.close();            } catch (IOException ex) {                return 0;            }            file.position(pointer ? 0 : length);        }        fileNames[num] = name;        usable[num] = false;        return num | 0x80;    }    public void fclose(int fp) {        fp &= 0x7f;        if (fp >= MAX_FILE_COUNT) {            return;        }        if (usable[fp]) {            return;        }        if (canWrite[fp]) {            try {                OutputStream out = fileSys.getOutputStream(fileNames[fp]);                files[fp].writeToStream(out);            } catch (IOException e) {            //do nothing            }        }        usable[fp] = true;    }    public int getc(int fp) {        fp &= 0x7f;        if (fp >= MAX_FILE_COUNT) {            return -1;        }        if (usable[fp] || !canRead[fp]) {            return -1;        }        return files[fp].getc();    }    public int putc(int c, int fp) {        fp &= 0x7f;        if (fp >= MAX_FILE_COUNT) {            return -1;        }        if (usable[fp] || !canWrite[fp]) {            return -1;        }        return files[fp].putc(c);    }    public int fread(Setable dest, int addr, int size, int fp) {        fp &= 0x7f;        if (fp >= MAX_FILE_COUNT) {            return -1;        }        if (usable[fp] || !canRead[fp]) {            return -1;        }        VirtualFile file = files[fp];        int count = 0, b;        while (count < size && (b = file.getc()) != -1) {            dest.setByte(addr++, (byte) b);            count++;        }        return count;    }    public int fwrite(Getable source, int addr, int size, int fp) {        fp &= 0x7f;        if (fp >= MAX_FILE_COUNT) {            return -1;        }        if (usable[fp] || !canWrite[fp]) {            return -1;        }        VirtualFile file = files[fp];        int count = 0, b;        while (count < size) {            b = source.getByte(addr++);            if (file.putc(b & 0xff) == -1) {                break;            }            count++;        }        return count;    }    public boolean deleteFile(Getable source, int addr) {        return fileSys.deleteFile(getFileName(source, addr));    }    public int fseek(int fp, int offset, int base) {        fp &= 0x7f;        if (fp >= MAX_FILE_COUNT || usable[fp]) {            return -1;        }        VirtualFile file = files[fp];        int pos = 0;        switch (base) {            case SEEK_SET:                pos = offset;                break;            case SEEK_CUR:                pos = file.position() + offset;                break;            case SEEK_END:                pos = file.limit() + offset;                break;            default:                return -1;        }        return file.position(pos);    }    public int ftell(int fp) {        fp &= 0x7f;        if (fp >= MAX_FILE_COUNT || usable[fp]) {            return -1;        }        return files[fp].position();    }    public boolean feof(int fp) {        fp &= 0x7f;        if (fp >= MAX_FILE_COUNT || usable[fp]) {            return true;        }        return files[fp].position() == files[fp].limit();    }    public void rewind(int fp) {        fp &= 0x7f;        if (fp >= MAX_FILE_COUNT || usable[fp]) {            return;        }        files[fp].position(0);    }    public void dispose() {        for (int index = 0; index < MAX_FILE_COUNT; index++) {            fclose(index | 0x80);        }    }    private String getFileName(Getable src, int addr) {        String name = getString(src, addr);        if (!name.startsWith("/")) {            name = workDir + "/" + name;        }        return name;    }    private String getString(Getable src, int addr) {        int length = 0;        byte b;        while ((b = src.getByte(addr++)) != 0) {            strBuf[length++] = b;        }        return new String(strBuf, 0, length);    }}


其中用到的两个interface:
FileSys提供了与底层文件系统的交互接口
/** * 文件系统接口<p> * 注意:方法中涉及的文件名都是GVM中用到的文件名,不一定与底层实际文件一一对应.其解释由具体实现者提供<p> * @author Eastsun * @version 1.0 */public interface FileSys {    /**     * 得到该文件的InputStream,以读取其内容     * @return in 当文件存在且canRead返回true时返回指向该文件的InputStream     * @throws java.io.IOException 文件不存在或不可读或发生IO错误     */    public InputStream getInputStream(String fileName) throws IOException;    /**     * 得到该文件的OutputStream以向其写入内容<p>     * 当文件不存在时会创建一个新的文件     * @return out  返回指向该文件的OutputStream     * @throws java.io.IOException 若文件不可写或发生IO错误     */    public OutputStream getOutputStream(String fileName) throws IOException;    /**     * 删除文件     * @param fileName 文件名     * @return true,如果删除成功     */    public boolean deleteFile(String fileName);    /**     * 建立文件夹     * @param dirName 文件夹名     * @return true,如果创建成功     */    public boolean makeDir(String dirName);    /**     * 得到指定文件/文件夹的相关信息<p>     * @param fileName 文件名     * @return 其相关信息     */    public FileInf getFileInf(String fileName);}


FileInf提供了文件的相关信息
/** * 一个描述文件信息的接口 * @author Eastsun * @version 1.0 */public interface FileInf {    /**     * 是否为一个文件     */    public boolean isFile();    /**     * 是否为一个文件夹     * @return 当仅当存在且为文件夹时返回true     */    public boolean isDirectory();    /**     * 该文件夹或文件是否可读     * @return 当且仅当存在且可读时返回true     */    public boolean canRead();    /**     * 该文件夹或文件是否可写     * @return 当仅当存在且可写时返回true     */    public boolean canWrite();    /**     * 得到文件夹下文件个数     * @return 为文件夹时返回其目录下文件个数(含子目录);否则返回-1     */    public int getFileNum();    /**     * 得到目录下第start个开始的num个文件名,保存到names中     * @param names 用于保存文件名的String数组     * @param start 开始文件号     * @param num   个数     * @return      实际得到的个数,如出错,返回-1     */    public int listFiles(String[] names, int start, int num);}

读书人网 >C语言

热点推荐