मेरे पास लगभग १००० वस्तुओं के बारे में एक "बड़ी" JSON फ़ाइल है।
क्रमबद्ध / deserialize करने के लिए https://arduinojson.org/ का उपयोग करना।

void ConfigFile_Save_Variable(String VarName, String VarValue) {
  Serial.print("ConfigFile_Save_Variable: ");
  Serial.print(VarName); Serial.print("="); Serial.print(VarValue);

  File configFile = SPIFFS.open("/config.json", "r");
  if (!configFile) {
    Serial.println("- failed to open config file for writing");
    return;
  }

  DynamicJsonDocument doc(2048);
  deserializeJson(doc, configFile);
  serializeJson(doc, Serial);
  configFile.close();
  //
  doc[VarName] = VarValue;
  //
  configFile = SPIFFS.open("/config.json", "w");
  serializeJson(doc, configFile);
  serializeJson(doc, Serial);
  configFile.close();
  Serial.println("");
  Serial.println(" - config.json saved - OK.");

अगर मैं केवल 1 ऑब्जेक्ट को संपादित करना चाहता हूं और JSON फ़ाइल को सहेजना चाहता हूं, तो पूरी फाइल फिर से लिखी जाती है।
यह लेवलिंग पहनने के लिए बुरा है, क्योंकि यह सभी डेटा फिर से लिखता है, केवल 1 ऑब्जेक्ट बदल दिया गया है।

तो मैं केवल पूरी फाइल नहीं बल्कि परिवर्तन लिखने का एक तरीका ढूंढ रहा हूं। भाग्य के बिना हर जगह देखने की कोशिश की।

1
strange_esp 3 सितंबर 2020, 19:14

2 जवाब

सबसे बढ़िया उत्तर

इसे संभालने का सबसे अच्छा तरीका JSON को तोड़ना है - प्रत्येक शीर्ष स्तर की वस्तु को अपनी फ़ाइल में लिखें। आपके पास ऑब्जेक्ट के लिए पहले से ही लेबल हैं, यदि आपको लेबल नाम के लिए अधिक स्थान की आवश्यकता है तो /config/ या /c/ के साथ पहले से फ़ाइल नाम के रूप में उनका उपयोग करें।

आइए देखें कि आप SPIFF से जो मांग रहे हैं वह काम क्यों नहीं करता है।

JSON को पाठ के रूप में भंडारण के लिए क्रमबद्ध किया गया है। उदाहरण के लिए, वस्तु

{
  label_0: {
    label_a: "small string",
    label_b: 1
    },
  label_1: {
    label_c: "another string",
    label_d: "more string"
  }
}

के रूप में क्रमबद्ध है

{"label_0":{"label_a":"small string","label_b":1},"label_1":{"label_c":"another string","label_d":"more string"}}

SPIFFS संग्रहीत फ़ाइलों को निश्चित आकार के पृष्ठों में विभाजित करता है। इसे हर बार फ्लैश करने के लिए एक पूरा पेज लिखना होता है - यह सिर्फ बदले हुए बाइट्स को नहीं लिख सकता है; ऐसा नहीं है कि फ्लैश स्टोरेज कैसे काम करता है।

मान लीजिए label_a छोटा हो जाता है - बस "s"। फिर label_a के बाद सब कुछ फाइल में नीचे शिफ्ट करना होगा। SPIFFS के लिए वह करने के लिए जो आप पूछ रहे हैं, उसे एक पृष्ठ लिखना होगा और याद रखना होगा कि पृष्ठ का केवल एक हिस्सा उपयोग में था।

यदि label_a का मान बड़ा हो जाता है - "this is a much longer string" तो सब कुछ फ़ाइल में ऊपर स्थानांतरित करना होगा। SPIFFS को अतिप्रवाह को संग्रहीत करने के लिए एक नया पृष्ठ आवंटित करना होगा और याद रखना होगा कि इसका केवल एक हिस्सा उपयोग में था।

ध्यान रखें कि SPIFFS यह याद रखने का एकमात्र तरीका है कि कौन से ब्लॉक उपयोग में हैं, उस जानकारी को फ्लैश करने के लिए भी लिखना है।

एक साधारण फाइल सिस्टम के बारे में पूछने के लिए यह बहुत कुछ है।

आइए स्थिति पर कुछ दृष्टिकोण भी प्राप्त करें। फ़ाइल कितनी बड़ी है, और यह कितनी बार लिखी जाती है? यदि आपके पास 1000 ऑब्जेक्ट हैं और प्रत्येक ऑब्जेक्ट स्टोर करने के लिए 200 बाइट्स लेता है, तो आपका JSON लगभग 20,000 बाइट्स होगा। एक औसत ESP8266 या ESP32 में 4MB फ्लैश होता है, शायद 1.5MB SPIFFS के लिए उपलब्ध होता है। आप 1.5MB में 20,000 बाइट्स को 75 बार स्टोर कर सकते हैं - इसलिए आपके पास वियर लेवलिंग के लिए लगभग 75x या थोड़ा कम का कारक हो सकता है।

अधिकांश ESP8266 और ESP32 में फ्लैश को 100,000 राइट्स के लिए रेट किया गया है (व्यवहार में यह आमतौर पर अधिक समय तक चलेगा)। तो पहनने के स्तर के साथ आप त्रुटियों को देखने की अपेक्षा किए बिना 20,000 बाइट फ़ाइल 750,000 बार लिख सकते हैं।

क्या आप वास्तव में इस फ़ाइल को १००० या १०,००० बार भी लिखने की संभावना रखते हैं?

यदि आप हैं - यह कॉन्फ़िगरेशन फ़ाइल के लिए एक अजीब परिदृश्य की तरह लगता है, और आपको पुनर्विचार करना चाहिए कि आप इस फ़ाइल को कैसे प्रबंधित कर रहे हैं और यह क्या कर रहा है।

यदि नहीं तो यह वास्तव में कोई समस्या नहीं है।

1
romkey 3 सितंबर 2020, 20:23

TLDR: मैनुअल वियर लेवलिंग बहुत कठिन है, और लेवलिंग वैसे भी स्वचालित हो सकती है। मैं अक्सर बदले गए कॉन्फ़िगरेशन विकल्पों को एक अलग फ़ाइल में अलग कर दूंगा ताकि आप हर बार कम लिखें, और केवल डिस्क पर लिखें जब आपको पूरी तरह से करना होगा (यानी: प्रोग्राम समाप्त)

यदि json फ़ाइल की लंबाई बदल जाती है, अर्थात: आप "true" को "false" में बदलते हैं, तो पूरी फ़ाइल को फिर से लिखा जाना चाहिए क्योंकि [disc] फ़ाइल को आवंटित किया जाने वाला स्थान अब बदल गया है। यदि आप प्रत्येक कॉन्फ़िगरेशन मान के लिए वर्णों की एक निर्धारित संख्या आरक्षित करते हैं, या केवल x अंक संख्याओं को कॉन्फ़िगरेशन मान के रूप में उपयोग करते हैं, तो आप फ़ाइल के साथ इंटरफेस किए बिना डिस्क पर सीधे बाइनरी डेटा को फिर से लिखने में सक्षम हो सकते हैं। लेकिन इसके लिए कुछ बेहद निम्न स्तर की प्रोग्रामिंग और सटीक मेमोरी पतों के ज्ञान की आवश्यकता होगी। इसके अलावा, क्योंकि आप भंडारण के लिए फ्लैश मेमोरी का उपयोग कर रहे हैं, आपको अभी भी किए गए प्रत्येक परिवर्तन के लिए एक पूर्ण मेमोरी ब्लॉक को पढ़ना, अपडेट करना और लिखना होगा। समय के साथ, विशेष रूप से यदि आप किसी भी नियमितता के साथ केवल एक मान को अपडेट करते हैं, तो यह पूर्ण पुनर्लेखन की तुलना में लंबे समय में डिस्क के लिए अधिक हानिकारक हो सकता है।

डेस्कटॉप एसएसडी स्वचालित रूप से संपूर्ण डिस्क पर पहनने का स्तर होगा। यदि esp ऐसा ही करता है, तो आपको अपने आप को समतल करने के बारे में चिंता करने की ज़रूरत नहीं है, बल्कि जब आप इसे फिर से लिखते हैं तो फ़ाइल का आकार कम से कम रखना चाहिए।

उपरोक्त को देखते हुए, एक संभावित समाधान अक्सर फिर से लिखे गए कॉन्फ़िगरेशन विकल्पों को एक अलग फ़ाइल में अलग करना होगा, और शायद ही कभी फिर से लिखे गए लोगों को अपनी मुख्य फ़ाइल में रखना होगा। आप सभी कॉन्फ़िगरेशन डेटा को स्मृति में भी रख सकते हैं, और केवल प्रोग्राम के अंत में फ़ाइल को फिर से लिख सकते हैं, हालांकि यह केवल तभी लागू होता है जब आप अपने प्रोग्राम को लगातार शुरू/बंद नहीं करते हैं। चरम पर अलगाव लेते हुए आप सैद्धांतिक रूप से प्रत्येक कॉन्फ़िगरेशन विकल्प के लिए एक अलग फ़ाइल का उपयोग कर सकते हैं, जो आपको एक समय में केवल एक मान को फिर से लिखने की अनुमति देगा।

1
61616 3 सितंबर 2020, 19:44