You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

POS设备字节流文件读取疑问:如何解析非文本格式的farestructure.txt?

Is farestructure.txt a byte stream (binary) format? How to read its content?

Great question—let's break this down clearly:

Yes, this is absolutely a binary byte stream file

The reason plain text editors (Notepad, Word) show garbage is because this file isn't made of human-readable text characters. Instead, it's a packed binary data file structured to be read directly by the POS device's application, using fixed-size data chunks matched to a C struct.

Looking at your code snippet, the app reads the entire file into a buffer, then uses memcpy to extract fields in a strict order and size:

  • 4 bytes for fareStructureVersion (likely a 32-bit integer)
  • 7 bytes for commenceDatetime
  • 7 bytes for expiryDatetime
  • 2 bytes for sectionCount (16-bit integer)
  • 1 byte for consessionTypeID1 (8-bit integer/byte)

This is classic binary struct serialization—no text encoding involved, just raw bytes mapped to data types.


How to read its content properly

To decode this file, you need to mirror the exact struct definition the POS app uses, then read the file into that struct. Here's a step-by-step approach:

1. Define the matching C struct

First, create a struct that matches the field order and sizes from the memcpy calls. Important: Disable struct padding (most compilers add padding bytes between fields for alignment, but the file stores data tightly packed). Use #pragma pack(1) for this:

#pragma pack(1)
typedef struct {
    uint32_t fareStructureVersion;  // 4 bytes (32-bit unsigned int)
    uint8_t commenceDatetime[7];    // 7-byte datetime (likely BCD-encoded)
    uint8_t expiryDatetime[7];      // 7-byte expiry datetime
    uint16_t sectionCount;          // 2 bytes (16-bit unsigned int)
    uint8_t consessionTypeID1;      // 1 byte (8-bit unsigned int)
    // Add more fields here to match the rest of the memcpy calls in the full code
} FareStructure;
#pragma pack()

2. Read the file into the struct

You can read the file directly into an instance of this struct, or use the same buffer approach as the original code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>

// ... struct definition here ...

int main() {
    FareStructure fs;
    struct stat st_t;

    // Get file size (optional, but useful for validation)
    if (stat("farestructure.txt", &st_t) != 0) {
        perror("Failed to get file stats");
        return 1;
    }

    // Open and read the file
    int fd = open("farestructure.txt", O_RDONLY);
    if (fd == -1) {
        perror("Failed to open file");
        return 1;
    }

    ssize_t readSize = read(fd, &fs, sizeof(FareStructure));
    close(fd);

    if (readSize != sizeof(FareStructure)) {
        printf("Error: Incomplete read (read %zd bytes, expected %zu)\n", readSize, sizeof(FareStructure));
        return 1;
    }

    // Now decode and print the fields
    // Handle datetime (common BCD encoding example)
    uint16_t startYear = ((fs.commenceDatetime[0] & 0xF0) >> 4) * 10 + (fs.commenceDatetime[0] & 0x0F);
    startYear = startYear * 100 + ((fs.commenceDatetime[1] & 0xF0) >> 4) * 10 + (fs.commenceDatetime[1] & 0x0F);
    uint8_t startMonth = ((fs.commenceDatetime[2] & 0xF0) >> 4) * 10 + (fs.commenceDatetime[2] & 0x0F);
    uint8_t startDay = ((fs.commenceDatetime[3] & 0xF0) >> 4) * 10 + (fs.commenceDatetime[3] & 0x0F);
    uint8_t startHour = ((fs.commenceDatetime[4] & 0xF0) >> 4) * 10 + (fs.commenceDatetime[4] & 0x0F);
    uint8_t startMinute = ((fs.commenceDatetime[5] & 0xF0) >> 4) * 10 + (fs.commenceDatetime[5] & 0x0F);
    uint8_t startSecond = ((fs.commenceDatetime[6] & 0xF0) >> 4) * 10 + (fs.commenceDatetime[6] & 0x0F);

    printf("Fare Structure Version: %u\n", fs.fareStructureVersion);
    printf("Commence DateTime: %04d-%02d-%02d %02d:%02d:%02d\n", startYear, startMonth, startDay, startHour, startMinute, startSecond);
    printf("Expiry DateTime: "); // Repeat the BCD decode logic for expiryDatetime
    printf("Section Count: %u\n", fs.sectionCount);
    printf("Concession Type ID 1: %u\n", fs.consessionTypeID1);

    return 0;
}

3. Key considerations

  • Byte Order (Endianness): POS devices often use little-endian byte order. If you're reading on a big-endian system, you'll need to convert multi-byte fields (like fareStructureVersion or sectionCount) using functions like ntohl()/ntohs(), or manually reverse the bytes.
  • Datetime Encoding: The 7-byte datetime fields are almost certainly BCD (Binary-Coded Decimal), where each byte stores two decimal digits (e.g., the byte 0x24 represents 24). If BCD doesn't make sense, check the POS device's documentation for custom encoding.
  • Complete Struct: Your code snippet only shows the first few fields—you'll need to add all remaining fields from the full memcpy sequence to get the complete data.
  • Validation: Always compare the file size to the struct size (or the total of all field sizes) to ensure you're reading the full structure.

内容的提问来源于stack exchange,提问作者Thushantha .Srimal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:56:07