2008-10-16 24 views
11

में फ़ाइल करने के लिए utf16 लिखना मैं बाइनरी मोड में ऑफस्ट्रीम के साथ फ़ाइल करने के लिए एक wstring लिखने की कोशिश कर रहा हूं, लेकिन मुझे लगता है कि मैं कुछ गलत कर रहा हूं। यह मैं क्या कोशिश की है है: एन्कोडिंग के साथ उदाहरण के लिए में फ़ायरफ़ॉक्सबाइनरी मोड

ofstream outFile("test.txt", std::ios::out | std::ios::binary); 
wstring hello = L"hello"; 
outFile.write((char *) hello.c_str(), hello.length() * sizeof(wchar_t)); 
outFile.close(); 

उद्घाटन test.txt UTF16 को यह दिखा देंगे सेट के रूप में:

हैलो

क्या कोई मुझे बता सकता है कि ऐसा क्यों होता है?

FF FE 68 00 00 00 65 00 00 00 6C 00 00 00 6C 00 00 00 6F 00 00 00 

ऐसा लगता है कि मैं किसी कारण से हर चरित्र के बीच में दो अतिरिक्त बाइट्स मिलता है: एक हेक्स संपादक मैं में फ़ाइल खुल रही

:

संपादित करें?

+0

सही उत्पादन के लिए wchar_t से रूपांतरण करने के लिए धारा के साथ जुड़े स्थानीय करने के लिए एक पहलू जोड़ें। निचे देखो। –

उत्तर

6

मुझे संदेह है कि आकार (wchar_t) आपके पर्यावरण में 4 है - यानी यह यूटीएफ -16 के बजाय यूटीएफ -32/यूसीएस -4 लिख रहा है। यह निश्चित रूप से हेक्स डंप जैसा दिखता है।

यह परीक्षण करने में आसान है (केवल आकार (wchar_t) प्रिंट करें) लेकिन मुझे पूरा यकीन है कि यह क्या हो रहा है।

यूटीएफ -32 wstring से यूटीएफ -16 तक जाने के लिए आपको उचित एन्कोडिंग लागू करने की आवश्यकता होगी, क्योंकि सरोगेट जोड़े खेल में आते हैं।

+0

हाँ, आप सही हैं wchar_t आकार 4 का है, मैं एक मैक में हूँ। तो यह बहुत समझाता है :) मुझे यूटीएफ -16 में सरोगेट जोड़े के बारे में पता है, इसे थोड़ा और देखना होगा। – Cactuar

+0

आउटपुट से आप यह नहीं बता सकते कि यह यूटीएफ -16 या यूटीएफ -32 है, यह सब दिखाता है कि wchar_t 4 बाइट चौड़ा है। स्ट्रिंग का एन्कोडिंग भाषा द्वारा परिभाषित नहीं किया गया है (हालांकि यह यूसीएस -4 होने की संभावना है)। –

0

आपको WinHex जैसे हेक्स संपादक में आउटपुट फ़ाइल को देखना चाहिए ताकि आप वास्तविक बिट्स और बाइट्स देख सकें, यह सत्यापित करने के लिए कि आउटपुट वास्तव में यूटीएफ -16 है। इसे यहां पोस्ट करें और हमें परिणाम बताएं। यह हमें बताएगा कि फ़ायरफ़ॉक्स या आपके सी ++ प्रोग्राम को दोष देना है या नहीं।

लेकिन ऐसा लगता है कि आपके सी ++ प्रोग्राम काम करता है और फ़ायरफ़ॉक्स आपके यूटीएफ -16 को सही तरीके से व्याख्या नहीं कर रहा है। यूटीएफ -16 प्रत्येक चरित्र के लिए दो बाइट्स के लिए कॉल करता है। लेकिन फ़ायरफ़ॉक्स दो गुना प्रिंट कर रहा है जैसा कि इसे करना चाहिए, इसलिए शायद यह आपकी स्ट्रिंग को यूटीएफ -8 या एएससीआईआईआई के रूप में समझने की कोशिश कर रहा है, जो आम तौर पर प्रति चरित्र 1 बाइट होता है।

जब आप कहते हैं "यूटीएफ 16 पर एन्कोडिंग सेट के साथ फ़ायरफ़ॉक्स" आपका क्या मतलब है? मुझे संदेह है कि वह काम काम करता है।

14

यहां हम छोटे उपयोग किए गए लोकेल गुणों में भाग लेते हैं। यदि आप अपनी स्ट्रिंग को एक स्ट्रिंग (कच्चे डेटा के बजाए) के रूप में आउटपुट करते हैं तो आप लोकल को उचित रूपांतरण ऑटो-जादुई रूप से प्राप्त कर सकते हैं।

एनबी। यह कोड wchar_t वर्ण की औसतता को ध्यान में रखता नहीं है।

#include <locale> 
#include <fstream> 
#include <iostream> 
// See Below for the facet 
#include "UTF16Facet.h" 

int main(int argc,char* argv[]) 
{ 
    // construct a custom unicode facet and add it to a local. 
    UTF16Facet *unicodeFacet = new UTF16Facet(); 
    const std::locale unicodeLocale(std::cout.getloc(), unicodeFacet); 

    // Create a stream and imbue it with the facet 
    std::wofstream saveFile; 
    saveFile.imbue(unicodeLocale); 


    // Now the stream is imbued we can open it. 
    // NB If you open the file stream first. Any attempt to imbue it with a local will silently fail. 
    saveFile.open("output.uni"); 
    saveFile << L"This is my Data\n"; 


    return(0); 
}  

फ़ाइल: UTF16Facet.h

#include <locale> 

class UTF16Facet: public std::codecvt<wchar_t,char,std::char_traits<wchar_t>::state_type> 
{ 
    typedef std::codecvt<wchar_t,char,std::char_traits<wchar_t>::state_type> MyType; 
    typedef MyType::state_type   state_type; 
    typedef MyType::result    result; 


    /* This function deals with converting data from the input stream into the internal stream.*/ 
    /* 
    * from, from_end: Points to the beginning and end of the input that we are converting 'from'. 
    * to, to_limit: Points to where we are writing the conversion 'to' 
    * from_next:  When the function exits this should have been updated to point at the next location 
    *     to read from. (ie the first unconverted input character) 
    * to_next:   When the function exits this should have been updated to point at the next location 
    *     to write to. 
    * 
    * status:   This indicates the status of the conversion. 
    *     possible values are: 
    *     error:  An error occurred the bad file bit will be set. 
    *     ok:   Everything went to plan 
    *     partial: Not enough input data was supplied to complete any conversion. 
    *     nonconv: no conversion was done. 
    */ 
    virtual result do_in(state_type &s, 
          const char *from,const char *from_end,const char* &from_next, 
          wchar_t  *to, wchar_t *to_limit,wchar_t* &to_next) const 
    { 
     // Loop over both the input and output array/ 
     for(;(from < from_end) && (to < to_limit);from += 2,++to) 
     { 
      /*Input the Data*/ 
      /* As the input 16 bits may not fill the wchar_t object 
      * Initialise it so that zero out all its bit's. This 
      * is important on systems with 32bit wchar_t objects. 
      */ 
      (*to)        = L'\0'; 

      /* Next read the data from the input stream into 
      * wchar_t object. Remember that we need to copy 
      * into the bottom 16 bits no matter what size the 
      * the wchar_t object is. 
      */ 
      reinterpret_cast<char*>(to)[0] = from[0]; 
      reinterpret_cast<char*>(to)[1] = from[1]; 
     } 
     from_next = from; 
     to_next  = to; 

     return((from > from_end)?partial:ok); 
    } 



    /* This function deals with converting data from the internal stream to a C/C++ file stream.*/ 
    /* 
    * from, from_end: Points to the beginning and end of the input that we are converting 'from'. 
    * to, to_limit: Points to where we are writing the conversion 'to' 
    * from_next:  When the function exits this should have been updated to point at the next location 
    *     to read from. (ie the first unconverted input character) 
    * to_next:   When the function exits this should have been updated to point at the next location 
    *     to write to. 
    * 
    * status:   This indicates the status of the conversion. 
    *     possible values are: 
    *     error:  An error occurred the bad file bit will be set. 
    *     ok:   Everything went to plan 
    *     partial: Not enough input data was supplied to complete any conversion. 
    *     nonconv: no conversion was done. 
    */ 
    virtual result do_out(state_type &state, 
          const wchar_t *from, const wchar_t *from_end, const wchar_t* &from_next, 
          char   *to, char   *to_limit, char*   &to_next) const 
    { 
     for(;(from < from_end) && (to < to_limit);++from,to += 2) 
     { 
      /* Output the Data */ 
      /* NB I am assuming the characters are encoded as UTF-16. 
      * This means they are 16 bits inside a wchar_t object. 
      * As the size of wchar_t varies between platforms I need 
      * to take this into consideration and only take the bottom 
      * 16 bits of each wchar_t object. 
      */ 
      to[0]  = reinterpret_cast<const char*>(from)[0]; 
      to[1]  = reinterpret_cast<const char*>(from)[1]; 

     } 
     from_next = from; 
     to_next  = to; 

     return((to > to_limit)?partial:ok); 
    } 
}; 
+0

ध्यान दें, कि आपका Facet यूसीएस -2 से रूपांतरण/यूटीएफ -16 में रूपांतरण लागू करता है। यूटीएफ -16 एक परिवर्तनीय लंबाई एन्कोडिंग है जिसे उपकरण सरोगेट जोड़े कहा जाता है। यूसीएस -2 यूनिकोड का उप-समूह है, यही वजह है कि यूटीएफ -16 का आविष्कार किया गया है। संदर्भ और स्पष्ट स्पष्टीकरण के लिए –

2

wofstream और UTF16 पहलू ऊपर परिभाषित विफल रहता है क्योंकि wofstream 2 बाइट्स 0D 0A करने के लिए मूल्य 0A के साथ सभी बाइट्स धर्मान्तरित का उपयोग कर खिड़कियों पर, इस पर ध्यान दिए बिना है 0 ए बाइट, '\ x0A', एल '\ x0A', एल '\ x000A', '\ n', एल '\ n' और std :: endl में आप कैसे एक ही परिणाम देते हैं। विंडोज़ पर आपको बाइनरी मोड में फ़ाइल को ऑफस्ट्रीम (wofsteam नहीं) के साथ खोलना होगा और आउटपुट लिखना होगा जैसे कि यह मूल पोस्ट में किया जाता है।

1

प्रदत्त Utf16Facet बड़े स्ट्रिंग्स के लिए gcc में काम नहीं किया है, यहां संस्करण है जो मेरे लिए काम करता है ... इस तरह फ़ाइल UTF-16LE में सहेजी जाएगी। UTF-16BE के लिए, बस do_in और do_out पर असाइनमेंट को उलटा करें, उदा। to[0] = from[1] और to[1] = from[0]

#include <locale> 
#include <bits/codecvt.h> 


class UTF16Facet: public std::codecvt<wchar_t,char,std::char_traits<wchar_t>::state_type> 
{ 
    typedef std::codecvt<wchar_t,char,std::char_traits<wchar_t>::state_type> MyType; 
    typedef MyType::state_type   state_type; 
    typedef MyType::result    result; 


    /* This function deals with converting data from the input stream into the internal stream.*/ 
    /* 
    * from, from_end: Points to the beginning and end of the input that we are converting 'from'. 
    * to, to_limit: Points to where we are writing the conversion 'to' 
    * from_next:  When the function exits this should have been updated to point at the next location 
    *     to read from. (ie the first unconverted input character) 
    * to_next:   When the function exits this should have been updated to point at the next location 
    *     to write to. 
    * 
    * status:   This indicates the status of the conversion. 
    *     possible values are: 
    *     error:  An error occurred the bad file bit will be set. 
    *     ok:   Everything went to plan 
    *     partial: Not enough input data was supplied to complete any conversion. 
    *     nonconv: no conversion was done. 
    */ 
    virtual result do_in(state_type &s, 
          const char *from,const char *from_end,const char* &from_next, 
          wchar_t  *to, wchar_t *to_limit,wchar_t* &to_next) const 
    { 

     for(;from < from_end;from += 2,++to) 
     { 
      if(to<=to_limit){ 
       (*to)        = L'\0'; 

       reinterpret_cast<char*>(to)[0] = from[0]; 
       reinterpret_cast<char*>(to)[1] = from[1]; 

       from_next = from; 
       to_next  = to; 
      } 
     } 

     return((to != to_limit)?partial:ok); 
    } 



    /* This function deals with converting data from the internal stream to a C/C++ file stream.*/ 
    /* 
    * from, from_end: Points to the beginning and end of the input that we are converting 'from'. 
    * to, to_limit: Points to where we are writing the conversion 'to' 
    * from_next:  When the function exits this should have been updated to point at the next location 
    *     to read from. (ie the first unconverted input character) 
    * to_next:   When the function exits this should have been updated to point at the next location 
    *     to write to. 
    * 
    * status:   This indicates the status of the conversion. 
    *     possible values are: 
    *     error:  An error occurred the bad file bit will be set. 
    *     ok:   Everything went to plan 
    *     partial: Not enough input data was supplied to complete any conversion. 
    *     nonconv: no conversion was done. 
    */ 
    virtual result do_out(state_type &state, 
          const wchar_t *from, const wchar_t *from_end, const wchar_t* &from_next, 
          char   *to, char   *to_limit, char*   &to_next) const 
    { 

     for(;(from < from_end);++from, to += 2) 
     { 
      if(to <= to_limit){ 

       to[0]  = reinterpret_cast<const char*>(from)[0]; 
       to[1]  = reinterpret_cast<const char*>(from)[1]; 

       from_next = from; 
       to_next  = to; 
      } 
     } 

     return((to != to_limit)?partial:ok); 
    } 
}; 
6

यह आसान अगर आप (अतिरिक्त का एक बहुत "utf8" जो इस समस्याओं को हल करती है हमेशा के लिए की तरह शामिल नहीं है क्योंकि) C++11 मानक का उपयोग करें।

लेकिन आप पुराने मानकों के साथ मल्टी-प्लैटफार्म कोड का उपयोग करना चाहते हैं, तो आप धाराओं के साथ लिखने के लिए इस विधि का उपयोग कर सकते हैं:

  1. Read the article about UTF converter for streams
  2. ऊपर स्रोतों से अपनी परियोजना के लिए stxutif.h जोड़े एएनएसआई मोड में फ़ाइल खोलें और एक फाइल के शुरू करने के बीओएम जोड़ने के लिए, इस तरह:

    std::ofstream fs; 
    fs.open(filepath, std::ios::out|std::ios::binary); 
    
    unsigned char smarker[3]; 
    smarker[0] = 0xEF; 
    smarker[1] = 0xBB; 
    smarker[2] = 0xBF; 
    
    fs << smarker; 
    fs.close(); 
    
  3. फिर UTF के रूप में फ़ाइल को खोलने और आपकी सामग्री लिखें:

    std::wofstream fs; 
    fs.open(filepath, std::ios::out|std::ios::app); 
    
    std::locale utf8_locale(std::locale(), new utf8cvt<false>); 
    fs.imbue(utf8_locale); 
    
    fs << .. // Write anything you want... 
    
+1

'+ 1' :) – Anne

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