嵌入式系统上的外部文件资源(C语言加FAT)

External file ressource on embedded system (C language with FAT)

我的 application/device 在 ARM Cortex M3 (STM32) 上是 运行,没有 OS 但有 FatFs)并且需要访问许多资源文件(音频, 图片等..)

由于用户有权访问资源文件夹以进行原子更新,我想将所有这些资源文件打包成一个文件(.dat、.rom、.whatever) 所以用户不会错误处理这些数据。

有人能给我指出一个好的解决方案吗?

我不介意在我的应用程序中重新映射 fopen、fread、fseek 和 fclose,但我不想从头开始(编码序列化程序、table 内容、解析器等...) .我的系统非常有限(没有 malloc,没有框架,只有 stdlib 和 FatFs)

感谢您给我的任何意见。

注意:我不是在寻找将资源嵌入代码 (ROM) 中的解决方案,因为显然它们太大了。

进一步阐述 Joachim 上面所说的内容:

未压缩(有时)存档格式的流行选择是 cpio、tar 和 zip。这 3 个中的任何一个都可以正常工作。

这里有一些关于使用 TAR 或 CPIO 的更深入的评论。

TAR

我之前使用 tar 用于确切目的,在带有 FatFS 的 stm32 上,所以可以告诉你它有效。我之所以选择它而不是 cpio 或 zip,是因为它很熟悉(大多数开发人员都见过)、易用性和丰富的命令行工具。

GNU Tar 使您可以细粒度地控制文件在存档中的放置顺序和正则表达式以操纵文件名 (--xform) 或 --exclude 路径。您几乎可以保证只需要 GNU Tar 和一个 makefile 就可以准确地获得您想要的存档。我不确定 cpiozip.

也可以这样说

这意味着它适用于我的构建环境,但您的要求可能会有所不同。

CPIO

cpio 在我的 tar 中有很多 worse/harder 可以使用的命令行工具集观点。这就是为什么我尽可能避开它的原因。但是,它的文件格式稍微轻一些,可能更容易解析(并不是说 tar 很难)。

Linux 内核项目将 cpio 用于 initramfs 映像,因此这可能是您在 Internet 上找到的用于此类目的的最好/最成熟的示例。

如果您获取任何内核源代码树,工具 usr/gen_init_cpio.c 可用于从该源文件中描述的 cpio 列表文件格式生成 cpio。

提取码在init/initramfs.c

压缩包

我从未将 zip 格式用于此类目的。所以这里没有真正的评论。

应该可以递归使用fatfs。

驱动器 0 将是您的真实设备,驱动器 1 将是驱动器 0 上的文件。您可以像这样实现 disk_* 函数

#define BLOCKSIZE 512
FIL imagefile;
DSTATUS disk_initialize(BYTE drv) {
  UINT r;
  if(drv == 0)
    return SD_initialize();
  else if(drv == 1) {
    r = f_open(&image, "0:/RESOURCE.DAT", FA_READ);
    if(r == FR_OK)
      return 0;
  }
  return STA_NOINIT;
}
DRESULT disk_read(BYTE drv, BYTE *buff, DWORD sector, DWORD count) {
  UINT br, r;
  if(drv == 0)
    return SD_read_blocks(buff, sector, count);
  else if(drv == 1) {
    r = f_seek(&imagefile, sector*BLOCKSIZE);
    if(r != FR_OK)
      return RES_ERROR;
    r = f_read(&imagefile, buff, count*BLOCKSIZE, &br);
    if((r == FR_OK) && (br == count*BLOCKSIZE))
      return RES_OK;
  }
  return RES_ERROR;
}

要在 Linux 或其他类似系统上创建文件系统映像,您需要 mkfs.msdos 和 mtools 包。 See this SO post on how to do it。也可以使用 Cygwin 在 Windows 上工作。

Berendi找到了一个非常巧妙的解决方案:利用已有的fat库递归访问!

实现很简单,经过大量测试,我想post递归使用的代码FatFs和单文件fat生成的命令。

  1. 首先,让我们生成一个 100Mb 的 FAT32 文件:

dd if=/dev/zero of=fat.fs bs=1024 count=102400

mkfs.vfat -F 32 -r 112 -S 512 -v fatfile.fs

  1. Create/push内容进去:

echo HelloWorld on Virtual FAT >> helloworld.txt

mcopy -i fatfile.fs helloworld.txt ::/

  1. 更改 diskio.c 文件,添加 Berendi 的代码,同时:
DSTATUS disk_status ()
{
  DSTATUS status = STA_NOINIT;
  switch (pdrv)
  {
  case FATFS_DRIVE_VIRTUAL:
      printf("disk_status: FATFS_DRIVE_VIRTUAL\r\n" );
  case FATFS_DRIVE_ATA:    /* SD CARD */
      status = FATFS_SD_SDIO_disk_status();
  }
}
  1. 不要忘记为驱动器名称和卷数添加枚举:

#define _VOLUMES 2

  1. 然后挂载虚拟FAT,并访问它:
f_mount(&VirtualFAT, (TCHAR const*)"1:/", 1);
f_open(&file, "1:/test.txt", FA_READ);

非常感谢您的帮助。