`
Eastsun
  • 浏览: 311052 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

在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);
}
  • src.rar (256.5 KB)
  • 描述: JGVM中的大部分源代码
  • 下载次数: 61
分享到:
评论

相关推荐

    JAVA基于J2ME的手机游戏开发(论文+源代码).rar

    在J2ME游戏开发中,理解类的继承、封装和多态性至关重要,同时,熟练掌握线程管理和内存优化也是提高游戏性能的关键。 5. **毕业设计过程**:在进行计算机毕业设计时,通常需要经历需求分析、系统设计、编码实现、...

    tengge py for s60编程教程

    07.用py类模拟c语言结构体 08.用py类构建链表综合应用 09.py类的三种使用方法 10.object类的使用 11.类属性的重新定义 12.用父类构造函数初始化子类的方法 13.类的属性和实例属性的区别 14.类中标识符命名规则

    数字电视机顶盒中Java虚拟机的研究

    Java方法由Java语言编写,编译为字节码后存储在class文件中,与平台无关。本地方法则由其他编程语言(如C、C++或汇编语言)编写,编译为特定于处理器的机器码后保存在动态库中,运行中的Java程序通过调用本地方法与...

    Java基础复习大纲.docx

    JVM(Java虚拟机)是Java程序运行的基础,它是一种模拟真实计算机的软件或硬件系统,能执行字节码文件。而GC(Garbage Collection)机制则负责自动回收不再使用的内存,避免内存泄露。 Java的运行原理是先编译后...

    电力日负荷曲线预测程序和数据集(预测未来一天的负荷曲线)

    电力日负荷曲线预测程序和数据集(预测未来一天的负荷曲线)

    勾正科技向新而生智赢未来-2024年H1中国家庭智能大屏行业发展白皮书83页.pdf

    勾正科技向新而生智赢未来-2024年H1中国家庭智能大屏行业发展白皮书83页.pdf

    成绩分析问题-总文件压缩包(代码+所有磁盘文件)

    题目2.2(成绩分析问题):设计并实现一个成绩分析系统,们能够实现录入、保存一个班级学生多门课程的成绩,并成绩进行分析等功能。

    源代码-非零坊ASP友情链接 v5.0.zip

    更多毕业设计https://cv2022.blog.csdn.net/article/details/124463185

    java-springboot+vue应急救援物资管理系统源码.zip

    系统选用B/S模式,后端应用springboot框架,前端应用vue框架, MySQL为后台数据库。 本系统基于java设计的各项功能,数据库服务器端采用了Mysql作为后台数据库,使Web与数据库紧密联系起来。 在设计过程中,充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。

    鸿蒙应用开发领域中DevEco Studio的安装、使用技巧及性能分析工具详细介绍

    内容概要:本文主要介绍了鸿蒙原生应用开发过程中可能遇到的内存问题以及相应的解决方案。针对这些问题,华为提供的 DevEco Studio 包含了性能分析工具 DevEco Profiler,提供两种场景化的分析模板——Snapshot Insight 和 Allocation Insight,支持实时监控、ArkTS 和 Native 内存的深度分析。这使得开发者能够有效识别、定界定位并优化内存问题,大幅提升应用的稳定性和性能。此外,文章还介绍了 DevEco Studio 强大的模拟器功能,该模拟器能仿真各类设备及场景,包括GPS定位、导航和低电量管理,极大提高了开发效率和测试灵活性。最后,文中详细列出了常见的快捷键,并给出了保持 DevEco Studio 与 Android Studio 快捷键同步的方法。 适合人群:专注于鸿蒙生态系统内的应用开发的技术人员,特别是有一定经验的中级至高级程序员。 使用场景及目标:本文旨在帮助开发者更好地理解和掌握 DevEco Studio 的强大工具链,尤其是解决开发过程中经常遇见的内存管理和多设备兼容问题,目标是优化开发流程,减少调测时间,增强产品的质量和用户体验。 阅读建议:开发者可通过鸿蒙官方提供的资源链接下载最新版本的 DevEco Studio 并探索相关技术博客,以获得最新的技术和使用技巧。建议在实践中逐步熟悉各个功能模块,并积极利用性能分析工具和模拟器来解决现实中的问题。

    我是谁啊我耽误 的耽误是

    我是谁

    精美导航引导页HTML源码 自适应手机/电脑,无后台

    精美导航引导页HTML源码,自适应手机/电脑,无后台,上传网站根目录就能用,首页内容在index里面修改 可以双页切换,亲测可用,搭建简单,附带修改教程

    hap手机软件包测试用

    hap手机软件包测试,测试使用

    电气工程领域的Altium Designer电子线路CAD训练-从基础入门到PCB设计实践

    内容概要:本文档是一份针对自动化专业的《电子线路CAD训练》实习报告,详细介绍了通过使用Altium Designer冬春软件进行电子线路的原理图设计、元件库文件设计、PCB板设计及元件封装库设计的过程。文档首先概述了训练的目的和重要性,随后逐步讲解Altium Designer Winter的安装与配置,然后重点展示了具体元件的设计细节,如温度传感器、AD输入通道、四双向模拟开关等的实际应用。此外,还详细阐述了自动布线和手动布线的具体步骤与注意事项,最后通过对此次实习的回顾,强调了本次训练对于提升电路设计能力和后续学习的支持。 适用人群:本报告适用于正在学习自动化及相关专业的在校大学生或从事电气工程领域的工程师和技术人员。 使用场景及目标:旨在帮助读者深入了解电子线路CAD的基础理论知识及其实际应用场景,特别是在Altium Designer环境下的操作流程。目标在于强化学生或技术人员的专业技能,以便他们能够在未来的工作或研究中有更强的设计能力。同时,该报告也可作为相关课程的教学材料。 其他说明:附录部分提供了完整的电路原理图和详细的元器件列表,供读者进一步理解和参照练习。

    2019年 金融网点分县统计数据.zip

    “2019年金融网点分县统计数据”提供了中国县域金融机构布局的详细信息,覆盖国有大型商业银行、股份制商业银行、城市商业银行及农村商业银行的网点分布特征。截至2019年底,全国银行网点总量为197,719个,其中县域地区分布87,003个,占比44%;市区网点110,716个,占比56%。 从银行类型看,国有大型商业银行县域网点数量最多(46,481个),但分布不均,如交通银行县域网点仅占9.01%,而邮政储蓄银行县域覆盖率高达59%。股份制商业银行县域网点仅占10%,主要集中于华东地区(73%)。农村商业银行县域网点占比60%(34,525个),华北和华中地区占其总量的53%。 区域分布上,华中地区县域网点占比最高(57.66%),其次是华东(34%)和西南(46%);华南地区县域网点最少,仅占7%。国有大行在华东地区县域网点占比32%,农村商业银行则集中在华北(32%)和华中(21%)。 该数据为研究金融资源城乡配置、普惠金融发展及区域经济差异提供了基础支撑。例如,国有大行2019年县域网点数量较前一年增加,反映其下沉服务趋势;而农村金融机构通过人缘地缘优势持续优化县域服务。数据格式包含分银行、分地区的统计表格,适用于量化分析金融网络覆盖与经济社会发展的关联性。

    GFP-ATOMIC参数的含义

    GFP-ATOMIC参数的含义

    ollama国内源,bash使用

    ollama国内源,bash使用

    电动汽车制造商迁移至Snowflake的数据平台现代化解决方案与实操

    内容概要:本文详细介绍了一家电动汽车(EV)制造商面临的数据处理挑战以及为解决这些问题所采取的举措——将现有数据平台迁移到Snowflake云平台上。文中阐述了制造商目前遇到的问题,如查询速度慢、运营成本高、难以整合结构化及非结构化的数据来源,并提出了具体的改进方向和技术细节。为了帮助潜在技术人员更好地理解和准备相关技术测试,还提供了一个详细的步骤指南来构建数据管道。具体要求分为两大部分:一是在当前架构上进行操作演示,二是利用Snowflake完成未来状态架构搭建并做技术示范,同时提供了预期产出物列表、所需技能概述及观众构成等关键信息。 适用人群:对于想要深入理解数据仓库迁移流程及其技术实施的专业人士非常有价值,特别适合作为数据工程师、数据科学家和其他IT专业人士参与面试的技术评估资料。 使用场景及目标:旨在展示候选人在构建现代数据工程基础设施方面的技术和创新能力。此外还可以作为内部培训材料供团队成员提高技能,或者为计划类似转型项目的企业决策层提供借鉴参考,从而优化其自身的数据管理策略和架构规划。 其他说明:演示时间被安排为60分钟,其中包括用例讲解(5分钟)、架构讨论(10分钟

    自动封装javaBean的工具类

    自动封装javaBean的工具类

    源代码-飞翔非主流ASP爬虫伪静态缓存版 v2.0.zip

    更多毕业设计https://cv2022.blog.csdn.net/article/details/124463185

Global site tag (gtag.js) - Google Analytics