2015-06-24 3 views
5

मैं तारों को स्टोर करने के लिए एक बाइनरी फ़ाइल प्रारूप तैयार कर रहा हूं [अंतरिक्ष को बचाने के लिए शून्य को समाप्त किए बिना] और बाइनरी डेटा।बाइनरी फ़ाइल प्रारूप में पोर्टेबिलिटी समस्याओं को कैसे संभालें

i। छोटे/बड़े एंडियन सिस्टम से निपटने का सबसे अच्छा तरीका क्या है? i.a सब कुछ नेटवर्क बाइट ऑर्डर में परिवर्तित कर देगा और वापस ntohl()/htonl() काम के साथ?

ii। क्या पैक किए गए ढांचे x86, x64 और arm पर समान आकार होंगे?

iii। क्या इस दृष्टिकोण के साथ उनकी कोई अंतर्निहित कमजोरी है? मैं प्रारूप विकसित का उपयोग कर रहा

struct __attribute__((packed)) Header { 
    uint8_t magic; 
    uint8_t flags; 
}; 

struct __attribute__((packed)) Record { 
    uint64_t length; 
    uint32_t crc; 
    uint16_t year; 
    uint8_t day; 
    uint8_t month; 
    uint8_t hour; 
    uint8_t minute; 
    uint8_t second; 
    uint8_t type; 
}; 

परीक्षक कोड:

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

struct __attribute__((packed)) Header { 
    uint8_t magic; 
    uint8_t flags; 
}; 

struct __attribute__((packed)) Record { 
    uint64_t length; 
    uint32_t crc; 
    uint16_t year; 
    uint8_t day; 
    uint8_t month; 
    uint8_t hour; 
    uint8_t minute; 
    uint8_t second; 
    uint8_t type; 
}; 

    int main(void) 
    { 

     int fd = open("test.dat", O_RDWR|O_APPEND|O_CREAT, 444); 
     struct Header header = {1, 0}; 
     write(fd, &header, sizeof(header)); 
     char msg[] = {"BINARY"}; 
     struct Record record = {strlen(msg), 0, 0, 0, 0, 0, 0, 0}; 
     write(fd, &record, sizeof(record)); 
     write(fd, msg, record.length); 
     close(fd); 
     fd = open("test.dat", O_RDWR|O_APPEND|O_CREAT, 444); 


     read(fd, &header, sizeof(struct Header)); 
     read(fd, &record, sizeof(struct Record)); 
     int len = record.length; 
     char c; 
     while (len != 0) { 
      read(fd, &c, 1); 
      len--; 
      printf("%c", c); 
     } 
     close(fd); 
    } 
+0

मैं बंद करने के लिए मतदान कर रहा हूं, एसओ क्षमा के लिए बहुत व्यापक है, एक अलग साइट आज़माएं! – Olaf

+3

@ ओलाफ: मैं रखने के लिए वोट दूंगा: यह एक बहुत व्यावहारिक असली दुनिया का सवाल है जो हर समय आता है। सिर्फ इसलिए कि इसमें एक भी कट-एंड-सूखे उत्तर नहीं है इसका मतलब यह नहीं है कि यह विचार के लायक नहीं है। (इसके साथ ही, मैं नियमित रूप से नियमित नहीं हूं, इसलिए यदि सर्वसम्मति यह है कि व्यावहारिक, असली दुनिया प्रोग्रामिंग प्रश्नों के कुछ स्वार्थ हैं कि यह साइट _not_ है, तो मुझे बहस करने की कोई स्थिति नहीं है।) –

+0

@SteveSummit: मैं वास्तव में इस बात से सहमत हूं कि प्रश्न वास्तव में दिलचस्प है (दिमाग मेरी "क्षमा करें")। हालांकि, यह एसओ के लिए ऑफ-विषय है। मुझे उम्मीद है कि ओपी को एक और साइट मिल जाएगी (यकीन नहीं है, अगर स्टैक एक्सचेंज पर कोई है)। वोट के लिए: अच्छा, यह स्पष्ट रूप से _my_ राय है। अगर दूसरे अलग सोचते हैं, तो यह खुले रहेंगे। में इसके साथ जी सकता हूँ। – Olaf

उत्तर

7

मैं। फ़ाइल को एक क्रम में परिभाषित करना और "आंतरिक" क्रम में परिवर्तित करना, यदि आवश्यक हो, तो पढ़ने/लिखने (शायद ntohl और जैसा) के साथ, मेरी राय में, सर्वोत्तम दृष्टिकोण है।

ii। मुझे पैक किए गए ढांचे पर भरोसा नहीं है। वे उन प्लेटफार्मों के लिए इस दृष्टिकोण के लिए काम कर सकते हैं, लेकिन इसकी कोई गारंटी नहीं है।

iii। पूरे structs पर फ्रेड और fwrite का उपयोग कर बाइनरी फाइलों को पढ़ना और लिखना एक मूल रूप से कमजोर दृष्टिकोण है (फिर से मेरी राय में)। आप संभावना को अधिकतम करते हैं कि आपको शब्द आकार की समस्याओं, पैडिंग और संरेखण समस्याओं, और बाइट ऑर्डर समस्याओं से काटा जाएगा।

मुझे क्या करना पसंद है जो get16() और put32() जैसे छोटे कार्यों को लिखते हैं जो एक समय में एक बाइट पढ़ते हैं और लिखते हैं और इसलिए शब्द आकार और बाइट ऑर्डर कठिनाइयों के लिए निस्संदेह असंवेदनशील होते हैं। फिर मैं इनके संदर्भ में सरल रखता हूं और प्राप्त करता हूं रिकॉर्ड (और जैसा)।

unsigned int get16(FILE *fp) 
{ 
    unsigned int r; 
    r = getc(fp); 
    r = (r << 8) | getc(fp); 
    return r; 
} 

void put32(unsigned long int x, FILE *fp) 
{ 
    putc((int)((x >> 24) & 0xff), fp); 
    putc((int)((x >> 16) & 0xff), fp); 
    putc((int)((x >> 8) & 0xff), fp); 
    putc((int)(x & 0xff), fp); 
} 

[पीएस। जैसा कि @ ओलाफ टिप्पणियों में से एक में सही ढंग से इंगित करता है, उत्पादन कोड में आपको इन कार्यों में ईओएफ और त्रुटि के लिए हैंडलिंग की आवश्यकता होगी। मैंने प्रेजेंटेशन की सादगी के लिए उन्हें छोड़ दिया है।]

+0

एक mmap ed buffer पर पॉइंटर अंकगणित के साथ get16() लागू करेगा? – clockley1

+0

निश्चित रूप से। मैंने भी ऐसा किया है। –

+0

देखें? आप वास्तव में _did_ वोट ;-) नोट @ user1450181: आपको निश्चित रूप से त्रुटि-हैंडलिंग जोड़ना चाहिए, 'ईओएफ'/बुश दिशाओं के लिए त्रुटि को पकड़ना! यह भी दोनों नोट: 'getc()' रिटर्न 'int'। 'हस्ताक्षरित' को कास्टिंग नकारात्मक मानों के लिए कार्यान्वयन_ है। – Olaf

संबंधित मुद्दे