POS设备字节流文件读取疑问:如何解析非文本格式的farestructure.txt?
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
fareStructureVersionorsectionCount) using functions likentohl()/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
0x24represents24). 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
memcpysequence 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

